fix(scripted-alarms): atomic alarm-condition lookup under Lock (T15 review)
This commit is contained in:
@@ -107,9 +107,11 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
|||||||
ArgumentException.ThrowIfNullOrEmpty(alarmNodeId);
|
ArgumentException.ThrowIfNullOrEmpty(alarmNodeId);
|
||||||
ArgumentNullException.ThrowIfNull(state);
|
ArgumentNullException.ThrowIfNull(state);
|
||||||
|
|
||||||
if (_alarmConditions.TryGetValue(alarmNodeId, out var condition))
|
// Look up + project under a SINGLE Lock so a concurrent RebuildAddressSpace can't clear
|
||||||
|
// _alarmConditions / detach the condition node between the lookup and the Set* calls.
|
||||||
|
lock (Lock)
|
||||||
{
|
{
|
||||||
lock (Lock)
|
if (_alarmConditions.TryGetValue(alarmNodeId, out var condition))
|
||||||
{
|
{
|
||||||
// EnabledState / AckedState / ActiveState are mandatory children — always present after
|
// EnabledState / AckedState / ActiveState are mandatory children — always present after
|
||||||
// Create. Confirm + Shelving are optional Part 9 children: T14's real-server finding is
|
// Create. Confirm + Shelving are optional Part 9 children: T14's real-server finding is
|
||||||
@@ -147,15 +149,12 @@ public sealed class OtOpcUaNodeManager : CustomNodeManager2
|
|||||||
// NO ReportEvent here — T16 owns event firing. ClearChangeMasks just notifies any
|
// NO ReportEvent here — T16 owns event firing. ClearChangeMasks just notifies any
|
||||||
// attribute (not event) subscribers watching the condition's children directly.
|
// attribute (not event) subscribers watching the condition's children directly.
|
||||||
condition.ClearChangeMasks(SystemContext, includeChildren: true);
|
condition.ClearChangeMasks(SystemContext, includeChildren: true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: alarm not materialised as a real condition — keep the legacy bool[2] variable so
|
// Fallback: alarm not materialised as a real condition — keep the legacy bool[2] variable so
|
||||||
// un-materialised callers (and the existing unit tests) keep working.
|
// un-materialised callers (and the existing unit tests) keep working. CreateVariable mutates
|
||||||
lock (Lock)
|
// the SDK address space, so it MUST run under Lock (see WriteValue).
|
||||||
{
|
|
||||||
// CreateVariable mutates the SDK address space, so it MUST run under Lock (see WriteValue).
|
|
||||||
if (!_variables.TryGetValue(alarmNodeId, out var variable))
|
if (!_variables.TryGetValue(alarmNodeId, out var variable))
|
||||||
{
|
{
|
||||||
variable = CreateVariable(alarmNodeId);
|
variable = CreateVariable(alarmNodeId);
|
||||||
|
|||||||
Reference in New Issue
Block a user