소스 검색

feat(multithreading): Locks for subscription and browsing services

Ubuntu 5 년 전
부모
커밋
6050ffe172

+ 4 - 4
include/open62541/server.h

@@ -910,7 +910,7 @@ typedef void (*UA_Server_EventNotificationCallback)
  * @return Returns a description of the created MonitoredItem. The structure
  * also contains a StatusCode (in case of an error) and the identifier of the
  * new MonitoredItem. */
-UA_MonitoredItemCreateResult UA_EXPORT
+UA_MonitoredItemCreateResult UA_EXPORT UA_THREADSAFE
 UA_Server_createDataChangeMonitoredItem(UA_Server *server,
           UA_TimestampsToReturn timestampsToReturn,
           const UA_MonitoredItemCreateRequest item,
@@ -923,7 +923,7 @@ UA_Server_createDataChangeMonitoredItem(UA_Server *server,
 /*           const UA_MonitoredItemCreateRequest item, void *context, */
 /*           UA_Server_EventNotificationCallback callback); */
 
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId);
 
 #endif
@@ -1315,7 +1315,7 @@ UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
  * @param eventType The type of the event for which a node should be created
  * @param outNodeId The NodeId of the newly created node for the event
  * @return The StatusCode of the UA_Server_createEvent method */
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
                       UA_NodeId *outNodeId);
 
@@ -1326,7 +1326,7 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
  * @param outEvent the EventId of the new event
  * @param deleteEventNode Specifies whether the node representation of the event should be deleted
  * @return The StatusCode of the UA_Server_triggerEvent method */
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_NodeId originId,
                        UA_ByteString *outEventId, const UA_Boolean deleteEventNode);
 

+ 7 - 0
src/server/ua_server_internal.h

@@ -247,6 +247,13 @@ readWithReadValue(UA_Server *server, const UA_NodeId *nodeId,
 UA_BrowsePathResult
 translateBrowsePathToNodeIds(UA_Server *server, const UA_BrowsePath *browsePath);
 
+void
+monitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem);
+
+UA_BrowsePathResult
+browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
+                           size_t browsePathSize, const UA_QualifiedName *browsePath);
+
 /***************************************/
 /* Check Information Model Consistency */
 /***************************************/

+ 2 - 2
src/server/ua_services_attribute.c

@@ -613,7 +613,7 @@ UA_Server_readObjectProperty(UA_Server *server, const UA_NodeId objectId,
     bp.relativePath.elements = &rpe;
 
     UA_StatusCode retval;
-    UA_BrowsePathResult bpr = UA_Server_translateBrowsePathToNodeIds(server, &bp);
+    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
     if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
         retval = bpr.statusCode;
         UA_BrowsePathResult_deleteMembers(&bpr);
@@ -1669,7 +1669,7 @@ UA_Server_writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
     bp.relativePath.elements = &rpe;
 
     UA_StatusCode retval;
-    UA_BrowsePathResult bpr = UA_Server_translateBrowsePathToNodeIds(server, &bp);
+    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
     if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
         retval = bpr.statusCode;
         UA_BrowsePathResult_deleteMembers(&bpr);

+ 8 - 1
src/server/ua_services_monitoreditem.c

@@ -247,10 +247,12 @@ Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session, struct cre
     if(server->config.monitoredItemRegisterCallback) {
         void *targetContext = NULL;
         UA_Server_getNodeContext(server, request->itemToMonitor.nodeId, &targetContext);
+        UA_UNLOCK(server->serviceMutex);
         server->config.monitoredItemRegisterCallback(server, &session->sessionId,
                                                      session->sessionHandle,
                                                      &request->itemToMonitor.nodeId,
                                                      targetContext, newMon->attributeId, false);
+        UA_LOCK(server->serviceMutex);
         newMon->registered = true;
     }
 
@@ -263,7 +265,7 @@ Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session, struct cre
     /* Create the first sample */
     if(request->monitoringMode == UA_MONITORINGMODE_REPORTING &&
        newMon->attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER)
-        UA_MonitoredItem_sampleCallback(server, newMon);
+        monitoredItem_sampleCallback(server, newMon);
 
     /* Prepare the response */
     result->revisedSamplingInterval = newMon->samplingInterval;
@@ -321,7 +323,9 @@ UA_Server_createDataChangeMonitoredItem(UA_Server *server,
 
     UA_MonitoredItemCreateResult result;
     UA_MonitoredItemCreateResult_init(&result);
+    UA_LOCK(server->serviceMutex);
     Operation_CreateMonitoredItem(server, &server->adminSession, &cmc, &item, &result);
+    UA_UNLOCK(server->serviceMutex);
     return result;
 }
 
@@ -544,14 +548,17 @@ Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
 
 UA_StatusCode
 UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId) {
+    UA_LOCK(server->serviceMutex);
     UA_MonitoredItem *mon;
     LIST_FOREACH(mon, &server->localMonitoredItems, listEntry) {
         if(mon->monitoredItemId != monitoredItemId)
             continue;
         LIST_REMOVE(mon, listEntry);
         UA_MonitoredItem_delete(server, mon);
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_GOOD;
     }
+    UA_UNLOCK(server->serviceMutex);
     return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
 }
 

+ 21 - 3
src/server/ua_services_view.c

@@ -289,6 +289,7 @@ UA_StatusCode
 UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd,
                           size_t *resultsSize, UA_ExpandedNodeId **results) {
     /* Set the list of relevant reference types */
+    UA_LOCK(server->serviceMutex);
     UA_NodeId *refTypes = NULL;
     size_t refTypesSize = 0;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
@@ -299,8 +300,10 @@ UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd,
         } else {
             retval = referenceSubtypes(server, &bd->referenceTypeId,
                                        &refTypesSize, &refTypes);
-            if(retval != UA_STATUSCODE_GOOD)
+            if(retval != UA_STATUSCODE_GOOD) {
+                UA_UNLOCK(server->serviceMutex);
                 return retval;
+            }
         }
     }
 
@@ -311,6 +314,8 @@ UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd,
     /* Clean up */
     if(refTypes && bd->includeSubtypes)
         UA_Array_delete(refTypes, refTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
+
+    UA_UNLOCK(server->serviceMutex);
     return retval;
 }
 
@@ -724,7 +729,9 @@ UA_Server_browse(UA_Server *server, UA_UInt32 maxReferences,
                  const UA_BrowseDescription *bd) {
     UA_BrowseResult result;
     UA_BrowseResult_init(&result);
+    UA_LOCK(server->serviceMutex);
     Operation_Browse(server, &server->adminSession, &maxReferences, bd, &result);
+    UA_UNLOCK(server->serviceMutex);
     return result;
 }
 
@@ -789,8 +796,10 @@ UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
                      const UA_ByteString *continuationPoint) {
     UA_BrowseResult result;
     UA_BrowseResult_init(&result);
+    UA_LOCK(server->serviceMutex);
     Operation_BrowseNext(server, &server->adminSession, &releaseContinuationPoint,
                          continuationPoint, &result);
+    UA_UNLOCK(server->serviceMutex);
     return result;
 }
 
@@ -1143,8 +1152,8 @@ Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
 }
 
 UA_BrowsePathResult
-UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
-                                     size_t browsePathSize, const UA_QualifiedName *browsePath) {
+browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
+                           size_t browsePathSize, const UA_QualifiedName *browsePath) {
     /* Construct the BrowsePath */
     UA_BrowsePath bp;
     UA_BrowsePath_init(&bp);
@@ -1167,6 +1176,15 @@ UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
     return bpr;
 }
 
+UA_BrowsePathResult
+UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
+                           size_t browsePathSize, const UA_QualifiedName *browsePath) {
+    UA_LOCK(server->serviceMutex);
+    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, origin, browsePathSize, browsePath);;
+    UA_UNLOCK(server->serviceMutex);
+    return bpr;
+}
+
 /************/
 /* Register */
 /************/

+ 12 - 2
src/server/ua_subscription_datachange.c

@@ -112,7 +112,7 @@ detectValueChangeWithFilter(UA_Server *server, UA_Session *session, UA_Monitored
         else if(mon->filter.dataChangeFilter.deadbandType == UA_DEADBANDTYPE_PERCENT) {
             /* Browse for the percent range */
             UA_QualifiedName qn = UA_QUALIFIEDNAME(0, "EURange");
-            UA_BrowsePathResult bpr = UA_Server_browseSimplifiedBrowsePath(server, mon->monitoredNodeId, 1, &qn);
+            UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, mon->monitoredNodeId, 1, &qn);
             if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
                   UA_BrowsePathResult_deleteMembers(&bpr);
                   return UA_STATUSCODE_GOOD;
@@ -306,18 +306,28 @@ sampleCallbackWithValue(UA_Server *server, UA_Session *session,
         UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*) mon;
         void *nodeContext = NULL;
         UA_Server_getNodeContext(server, mon->monitoredNodeId, &nodeContext);
+        UA_UNLOCK(server->serviceMutex);
         localMon->callback.dataChangeCallback(server, mon->monitoredItemId,
                                               localMon->context,
                                               &mon->monitoredNodeId,
                                               nodeContext, mon->attributeId,
                                               value);
+        UA_LOCK(server->serviceMutex);
     }
 
     return UA_STATUSCODE_GOOD;
 }
 
 void
-UA_MonitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem) {
+UA_MonitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem)
+{
+    UA_LOCK(server->serviceMutex);
+    monitoredItem_sampleCallback(server, monitoredItem);
+    UA_UNLOCK(server->serviceMutex)
+}
+
+void
+monitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *monitoredItem) {
     UA_Subscription *sub = monitoredItem->subscription;
     UA_Session *session = &server->adminSession;
     if(sub)

+ 37 - 26
src/server/ua_subscription_events.c

@@ -57,10 +57,12 @@ generateEventId(UA_ByteString *generatedId) {
 UA_StatusCode
 UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
                       UA_NodeId *outNodeId) {
+    UA_LOCK(server->serviceMutex);
     if(!outNodeId) {
         UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
                      "outNodeId must not be NULL. The event's NodeId must be returned "
                      "so it can be triggered.");
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     }
 
@@ -70,6 +72,7 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
     if(!isNodeInTree(server->nsCtx, &eventType, &baseEventTypeId, &hasSubtypeId, 1)) {
         UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
                      "Event type must be a subtype of BaseEventType!");
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     }
 
@@ -79,17 +82,16 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
     name = UA_QUALIFIEDNAME(0,"E");
     UA_NodeId newNodeId = UA_NODEID_NULL;
     UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
-    UA_StatusCode retval =
-        UA_Server_addObjectNode(server,
-                                UA_NODEID_NULL, /* Set a random unused NodeId */
-                                UA_NODEID_NULL, /* No parent */
-                                UA_NODEID_NULL, /* No parent reference */
-                                name,           /* an event does not have a name */
-                                eventType,      /* the type of the event */
-                                oAttr,          /* default attributes are fine */
-                                NULL,           /* no node context */
-                                &newNodeId);
-
+    UA_StatusCode retval = addNode(server, UA_NODECLASS_OBJECT,
+                                   &UA_NODEID_NULL, /* Set a random unused NodeId */
+                                   &UA_NODEID_NULL, /* No parent */
+                                   &UA_NODEID_NULL, /* No parent reference */
+                                   name,            /* an event does not have a name */
+                                   &eventType,      /* the type of the event */
+                                   (const UA_NodeAttributes*)&oAttr, /* default attributes are fine */
+                                   &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
+                                   NULL,           /* no node context */
+                                   &newNodeId);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
                      "Adding event failed. StatusCode %s", UA_StatusCode_name(retval));
@@ -98,12 +100,13 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
 
     /* Find the eventType variable */
     name = UA_QUALIFIEDNAME(0, "EventType");
-    UA_BrowsePathResult bpr = UA_Server_browseSimplifiedBrowsePath(server, newNodeId, 1, &name);
+    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, newNodeId, 1, &name);
     if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
         retval = bpr.statusCode;
         UA_BrowsePathResult_deleteMembers(&bpr);
-        UA_Server_deleteNode(server, newNodeId, true);
+        deleteNode(server, newNodeId, true);
         UA_NodeId_deleteMembers(&newNodeId);
+        UA_UNLOCK(server->serviceMutex);
         return retval;
     }
 
@@ -111,15 +114,17 @@ UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
     UA_Variant value;
     UA_Variant_init(&value);
     UA_Variant_setScalar(&value, (void*)(uintptr_t)&eventType, &UA_TYPES[UA_TYPES_NODEID]);
-    retval = UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
+    retval = writeWithWriteValue(server, &bpr.targets[0].targetId.nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value);
     UA_BrowsePathResult_deleteMembers(&bpr);
     if(retval != UA_STATUSCODE_GOOD) {
-        UA_Server_deleteNode(server, newNodeId, true);
+        deleteNode(server, newNodeId, true);
         UA_NodeId_deleteMembers(&newNodeId);
+        UA_UNLOCK(server->serviceMutex);
         return retval;
     }
 
     *outNodeId = newNodeId;
+    UA_UNLOCK(server->serviceMutex);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -128,8 +133,7 @@ isValidEvent(UA_Server *server, const UA_NodeId *validEventParent,
              const UA_NodeId *eventId) {
     /* find the eventType variableNode */
     UA_QualifiedName findName = UA_QUALIFIEDNAME(0, "EventType");
-    UA_BrowsePathResult bpr =
-        UA_Server_browseSimplifiedBrowsePath(server, *eventId, 1, &findName);
+    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, *eventId, 1, &findName);
     if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
         UA_BrowsePathResult_deleteMembers(&bpr);
         return false;
@@ -141,7 +145,7 @@ isValidEvent(UA_Server *server, const UA_NodeId *validEventParent,
 
     /* Read the Value of EventType Property Node (the Value should be a NodeId) */
     UA_StatusCode retval =
-        UA_Server_readValue(server, bpr.targets[0].targetId.nodeId, &tOutVariant);
+            readWithReadValue(server, &bpr.targets[0].targetId.nodeId, UA_ATTRIBUTEID_VALUE, &tOutVariant);
     if(retval != UA_STATUSCODE_GOOD ||
        !UA_Variant_hasScalarType(&tOutVariant, &UA_TYPES[UA_TYPES_NODEID])) {
         UA_BrowsePathResult_deleteMembers(&bpr);
@@ -200,7 +204,7 @@ resolveSimpleAttributeOperand(UA_Server *server, UA_Session *session, const UA_N
 
     /* Resolve the browse path */
     UA_BrowsePathResult bpr =
-        UA_Server_browseSimplifiedBrowsePath(server, *origin, sao->browsePathSize,
+        browseSimplifiedBrowsePath(server, *origin, sao->browsePathSize,
                                              sao->browsePath);
     if(bpr.targetsSize == 0 && bpr.statusCode == UA_STATUSCODE_GOOD)
         bpr.statusCode = UA_STATUSCODE_BADNOTFOUND;
@@ -283,7 +287,7 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event,
     /* Set the SourceNode */
     UA_StatusCode retval;
     UA_QualifiedName name = UA_QUALIFIEDNAME(0, "SourceNode");
-    UA_BrowsePathResult bpr = UA_Server_browseSimplifiedBrowsePath(server, *event, 1, &name);
+    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, *event, 1, &name);
     if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
         retval = bpr.statusCode;
         UA_BrowsePathResult_deleteMembers(&bpr);
@@ -292,7 +296,7 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event,
     UA_Variant value;
     UA_Variant_init(&value);
     UA_Variant_setScalarCopy(&value, origin, &UA_TYPES[UA_TYPES_NODEID]);
-    retval = UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
+    retval = writeWithWriteValue(server, &bpr.targets[0].targetId.nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value);
     UA_Variant_deleteMembers(&value);
     UA_BrowsePathResult_deleteMembers(&bpr);
     if(retval != UA_STATUSCODE_GOOD)
@@ -300,7 +304,7 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event,
 
     /* Set the ReceiveTime */
     name = UA_QUALIFIEDNAME(0, "ReceiveTime");
-    bpr = UA_Server_browseSimplifiedBrowsePath(server, *event, 1, &name);
+    bpr = browseSimplifiedBrowsePath(server, *event, 1, &name);
     if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
         retval = bpr.statusCode;
         UA_BrowsePathResult_deleteMembers(&bpr);
@@ -308,7 +312,7 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event,
     }
     UA_DateTime rcvTime = UA_DateTime_now();
     UA_Variant_setScalar(&value, &rcvTime, &UA_TYPES[UA_TYPES_DATETIME]);
-    retval = UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
+    retval = writeWithWriteValue(server, &bpr.targets[0].targetId.nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value);
     UA_BrowsePathResult_deleteMembers(&bpr);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
@@ -319,7 +323,7 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event,
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     name = UA_QUALIFIEDNAME(0, "EventId");
-    bpr = UA_Server_browseSimplifiedBrowsePath(server, *event, 1, &name);
+    bpr = browseSimplifiedBrowsePath(server, *event, 1, &name);
     if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
         retval = bpr.statusCode;
         UA_ByteString_deleteMembers(&eventId);
@@ -328,7 +332,7 @@ eventSetStandardFields(UA_Server *server, const UA_NodeId *event,
     }
     UA_Variant_init(&value);
     UA_Variant_setScalar(&value, &eventId, &UA_TYPES[UA_TYPES_BYTESTRING]);
-    retval = UA_Server_writeValue(server, bpr.targets[0].targetId.nodeId, value);
+    retval = writeWithWriteValue(server, &bpr.targets[0].targetId.nodeId, UA_ATTRIBUTEID_VALUE, &UA_TYPES[UA_TYPES_VARIANT], &value);
     UA_BrowsePathResult_deleteMembers(&bpr);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_ByteString_deleteMembers(&eventId);
@@ -380,11 +384,13 @@ static const UA_NodeId parentReferences_events[2] =
 UA_StatusCode
 UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_NodeId origin,
                        UA_ByteString *outEventId, const UA_Boolean deleteEventNode) {
+    UA_LOCK(server->serviceMutex);
     /* Check that the origin node exists */
     const UA_Node *originNode = UA_Nodestore_getNode(server->nsCtx, &origin);
     if(!originNode) {
         UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
                      "Origin node for event does not exist.");
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADNOTFOUND;
     }
     UA_Nodestore_releaseNode(server->nsCtx, originNode);
@@ -394,6 +400,7 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
                      parentReferences_events, 2)) {
         UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_USERLAND,
                      "Node for event must be in ObjectsFolder!");
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADINVALIDARGUMENT;
     }
 
@@ -402,6 +409,7 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
         UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                        "Events: Could not set the standard event fields with StatusCode %s",
                        UA_StatusCode_name(retval));
+        UA_UNLOCK(server->serviceMutex);
         return retval;
     }
 
@@ -414,6 +422,7 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
         UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                        "Events: Could not create the list of nodes listening on the "
                        "event with StatusCode %s", UA_StatusCode_name(retval));
+        UA_UNLOCK(server->serviceMutex);
         return retval;
     }
 
@@ -441,14 +450,16 @@ UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId, const UA_
 
     /* Delete the node representation of the event */
     if(deleteEventNode) {
-        retval = UA_Server_deleteNode(server, eventNodeId, true);
+        retval = deleteNode(server, eventNodeId, true);
         if(retval != UA_STATUSCODE_GOOD) {
             UA_LOG_WARNING(&server->config.logger, UA_LOGCATEGORY_SERVER,
                            "Attempt to remove event using deleteNode failed. StatusCode %s",
                            UA_StatusCode_name(retval));
+            UA_UNLOCK(server->serviceMutex);
             return retval;
         }
     }
+    UA_UNLOCK(server->serviceMutex);
     return UA_STATUSCODE_GOOD;
 }
 

+ 2 - 0
tests/server/check_server_readspeed.c

@@ -94,7 +94,9 @@ START_TEST(readSpeed) {
         size_t offset = 0;
         retval |= UA_decodeBinary(&request_msg, &offset, &req, &UA_TYPES[UA_TYPES_READREQUEST], NULL);
 
+        UA_LOCK(server->serviceMutex);
         Service_Read(server, &server->adminSession, &req, &res);
+        UA_UNLOCK(server->serviceMutex);
 
         UA_Byte *rpos = response_msg.data;
         const UA_Byte *rend = &response_msg.data[response_msg.length];

+ 51 - 1
tests/server/check_services_subscriptions.c

@@ -67,7 +67,9 @@ createSubscription(void) {
     UA_CreateSubscriptionResponse response;
     UA_CreateSubscriptionResponse_init(&response);
 
+    UA_LOCK(server->serviceMutex);
     Service_CreateSubscription(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     subscriptionId = response.subscriptionId;
 
@@ -98,7 +100,9 @@ createMonitoredItem(void) {
     UA_CreateMonitoredItemsResponse response;
     UA_CreateMonitoredItemsResponse_init(&response);
 
+    UA_LOCK(server->serviceMutex);
     Service_CreateMonitoredItems(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(response.resultsSize, 1);
     ck_assert_uint_eq(response.results[0].statusCode, UA_STATUSCODE_GOOD);
@@ -118,8 +122,9 @@ START_TEST(Server_createSubscription) {
 
     UA_CreateSubscriptionResponse response;
     UA_CreateSubscriptionResponse_init(&response);
-
+    UA_LOCK(server->serviceMutex);
     Service_CreateSubscription(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     subscriptionId = response.subscriptionId;
 
@@ -145,7 +150,9 @@ START_TEST(Server_modifySubscription) {
     UA_ModifySubscriptionResponse response;
     UA_ModifySubscriptionResponse_init(&response);
 
+    UA_LOCK(server->serviceMutex);
     Service_ModifySubscription(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
 
     UA_ModifySubscriptionResponse_deleteMembers(&response);
@@ -164,7 +171,10 @@ START_TEST(Server_setPublishingMode) {
     UA_SetPublishingModeResponse response;
     UA_SetPublishingModeResponse_init(&response);
 
+    UA_LOCK(server->serviceMutex);
     Service_SetPublishingMode(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
+
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(response.resultsSize, 1);
     ck_assert_uint_eq(response.results[0], UA_STATUSCODE_GOOD);
@@ -184,7 +194,9 @@ START_TEST(Server_republish) {
     UA_RepublishResponse response;
     UA_RepublishResponse_init(&response);
 
+    UA_LOCK(server->serviceMutex);
     Service_Republish(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_BADMESSAGENOTAVAILABLE);
 
     UA_RepublishResponse_deleteMembers(&response);
@@ -201,7 +213,9 @@ START_TEST(Server_republish_invalid) {
     UA_RepublishResponse response;
     UA_RepublishResponse_init(&response);
 
+    UA_LOCK(server->serviceMutex);
     Service_Republish(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID);
 
     UA_RepublishResponse_deleteMembers(&response);
@@ -220,7 +234,9 @@ START_TEST(Server_deleteSubscription) {
     UA_DeleteSubscriptionsResponse del_response;
     UA_DeleteSubscriptionsResponse_init(&del_response);
 
+    UA_LOCK(server->serviceMutex);
     Service_DeleteSubscriptions(server, session, &del_request, &del_response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(del_response.resultsSize, 1);
     ck_assert_uint_eq(del_response.results[0], UA_STATUSCODE_GOOD);
 
@@ -236,7 +252,9 @@ START_TEST(Server_publishCallback) {
     UA_CreateSubscriptionRequest_init(&request);
     request.publishingEnabled = true;
     UA_CreateSubscriptionResponse_init(&response);
+    UA_LOCK(server->serviceMutex);
     Service_CreateSubscription(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     UA_UInt32 subscriptionId1 = response.subscriptionId;
     UA_CreateSubscriptionResponse_deleteMembers(&response);
@@ -245,7 +263,9 @@ START_TEST(Server_publishCallback) {
     UA_CreateSubscriptionRequest_init(&request);
     request.publishingEnabled = true;
     UA_CreateSubscriptionResponse_init(&response);
+    UA_LOCK(server->serviceMutex);
     Service_CreateSubscription(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     UA_UInt32 subscriptionId2 = response.subscriptionId;
     UA_Double publishingInterval = response.revisedPublishingInterval;
@@ -277,7 +297,9 @@ START_TEST(Server_publishCallback) {
     UA_DeleteSubscriptionsResponse del_response;
     UA_DeleteSubscriptionsResponse_init(&del_response);
 
+    UA_LOCK(server->serviceMutex);
     Service_DeleteSubscriptions(server, session, &del_request, &del_response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(del_response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(del_response.resultsSize, 2);
     ck_assert_uint_eq(del_response.results[0], UA_STATUSCODE_GOOD);
@@ -318,7 +340,9 @@ START_TEST(Server_modifyMonitoredItems) {
     UA_ModifyMonitoredItemsResponse response;
     UA_ModifyMonitoredItemsResponse_init(&response);
 
+    UA_LOCK(server->serviceMutex);
     Service_ModifyMonitoredItems(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(response.resultsSize, 1);
     ck_assert_uint_eq(response.results[0].statusCode, UA_STATUSCODE_GOOD);
@@ -336,7 +360,9 @@ START_TEST(Server_overflow) {
     UA_CreateSubscriptionRequest_init(&createSubscriptionRequest);
     createSubscriptionRequest.publishingEnabled = true;
     UA_CreateSubscriptionResponse_init(&createSubscriptionResponse);
+    UA_LOCK(server->serviceMutex);
     Service_CreateSubscription(server, session, &createSubscriptionRequest, &createSubscriptionResponse);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(createSubscriptionResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     UA_UInt32 localSubscriptionId = createSubscriptionResponse.subscriptionId;
     UA_Double publishingInterval = createSubscriptionResponse.revisedPublishingInterval;
@@ -368,7 +394,9 @@ START_TEST(Server_overflow) {
     UA_CreateMonitoredItemsResponse createMonitoredItemsResponse;
     UA_CreateMonitoredItemsResponse_init(&createMonitoredItemsResponse);
 
+    UA_LOCK(server->serviceMutex);
     Service_CreateMonitoredItems(server, session, &createMonitoredItemsRequest, &createMonitoredItemsResponse);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(createMonitoredItemsResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(createMonitoredItemsResponse.resultsSize, 1);
     ck_assert_uint_eq(createMonitoredItemsResponse.results[0].statusCode, UA_STATUSCODE_GOOD);
@@ -438,8 +466,10 @@ START_TEST(Server_overflow) {
     UA_ModifyMonitoredItemsResponse modifyMonitoredItemsResponse;
     UA_ModifyMonitoredItemsResponse_init(&modifyMonitoredItemsResponse);
 
+    UA_LOCK(server->serviceMutex);
     Service_ModifyMonitoredItems(server, session, &modifyMonitoredItemsRequest,
                                  &modifyMonitoredItemsResponse);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(modifyMonitoredItemsResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(modifyMonitoredItemsResponse.resultsSize, 1);
     ck_assert_uint_eq(modifyMonitoredItemsResponse.results[0].statusCode, UA_STATUSCODE_GOOD);
@@ -468,8 +498,10 @@ START_TEST(Server_overflow) {
 
     UA_ModifyMonitoredItemsResponse_init(&modifyMonitoredItemsResponse);
 
+    UA_LOCK(server->serviceMutex);
     Service_ModifyMonitoredItems(server, session, &modifyMonitoredItemsRequest,
                                  &modifyMonitoredItemsResponse);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(modifyMonitoredItemsResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(modifyMonitoredItemsResponse.resultsSize, 1);
     ck_assert_uint_eq(modifyMonitoredItemsResponse.results[0].statusCode, UA_STATUSCODE_GOOD);
@@ -497,8 +529,10 @@ START_TEST(Server_overflow) {
 
     UA_ModifyMonitoredItemsResponse_init(&modifyMonitoredItemsResponse);
 
+    UA_LOCK(server->serviceMutex);
     Service_ModifyMonitoredItems(server, session, &modifyMonitoredItemsRequest,
                                  &modifyMonitoredItemsResponse);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(modifyMonitoredItemsResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(modifyMonitoredItemsResponse.resultsSize, 1);
     ck_assert_uint_eq(modifyMonitoredItemsResponse.results[0].statusCode, UA_STATUSCODE_GOOD);
@@ -522,8 +556,10 @@ START_TEST(Server_overflow) {
     UA_DeleteSubscriptionsResponse deleteSubscriptionsResponse;
     UA_DeleteSubscriptionsResponse_init(&deleteSubscriptionsResponse);
 
+    UA_LOCK(server->serviceMutex);
     Service_DeleteSubscriptions(server, session, &deleteSubscriptionsRequest,
                                 &deleteSubscriptionsResponse);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(deleteSubscriptionsResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(deleteSubscriptionsResponse.resultsSize, 1);
     ck_assert_uint_eq(deleteSubscriptionsResponse.results[0], UA_STATUSCODE_GOOD);
@@ -547,7 +583,9 @@ START_TEST(Server_setMonitoringMode) {
     UA_SetMonitoringModeResponse response;
     UA_SetMonitoringModeResponse_init(&response);
 
+    UA_LOCK(server->serviceMutex);
     Service_SetMonitoringMode(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(response.resultsSize, 1);
     ck_assert_uint_eq(response.results[0], UA_STATUSCODE_GOOD);
@@ -569,7 +607,9 @@ START_TEST(Server_deleteMonitoredItems) {
     UA_DeleteMonitoredItemsResponse response;
     UA_DeleteMonitoredItemsResponse_init(&response);
 
+    UA_LOCK(server->serviceMutex);
     Service_DeleteMonitoredItems(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(response.resultsSize, 1);
     ck_assert_uint_eq(response.results[0], UA_STATUSCODE_GOOD);
@@ -588,7 +628,9 @@ START_TEST(Server_lifeTimeCount) {
     request.requestedLifetimeCount = 3;
     request.requestedMaxKeepAliveCount = 1;
     UA_CreateSubscriptionResponse_init(&response);
+    UA_LOCK(server->serviceMutex);
     Service_CreateSubscription(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(response.revisedMaxKeepAliveCount, 1);
     ck_assert_uint_eq(response.revisedLifetimeCount, 3);
@@ -600,7 +642,9 @@ START_TEST(Server_lifeTimeCount) {
     request.requestedLifetimeCount = 4;
     request.requestedMaxKeepAliveCount = 2;
     UA_CreateSubscriptionResponse_init(&response);
+    UA_LOCK(server->serviceMutex);
     Service_CreateSubscription(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(response.revisedMaxKeepAliveCount, 2);
     /* revisedLifetimeCount is revised to 3*MaxKeepAliveCount == 3 */
@@ -633,7 +677,9 @@ START_TEST(Server_lifeTimeCount) {
 
     UA_CreateMonitoredItemsResponse mresponse;
     UA_CreateMonitoredItemsResponse_init(&mresponse);
+    UA_LOCK(server->serviceMutex);
     Service_CreateMonitoredItems(server, session, &mrequest, &mresponse);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(mresponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(mresponse.resultsSize, 1);
     ck_assert_uint_eq(mresponse.results[0].statusCode, UA_STATUSCODE_GOOD);
@@ -740,7 +786,9 @@ START_TEST(Server_invalidPublishingInterval) {
     request.publishingEnabled = true;
     request.requestedPublishingInterval = -5.0; // Must be positive
     UA_CreateSubscriptionResponse_init(&response);
+    UA_LOCK(server->serviceMutex);
     Service_CreateSubscription(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert(response.revisedPublishingInterval ==
               server->config.publishingIntervalLimits.min);
@@ -778,7 +826,9 @@ START_TEST(Server_invalidSamplingInterval) {
 
     UA_CreateMonitoredItemsResponse response;
     UA_CreateMonitoredItemsResponse_init(&response);
+    UA_LOCK(server->serviceMutex);
     Service_CreateMonitoredItems(server, session, &request, &response);
+    UA_UNLOCK(server->serviceMutex);
     ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
     ck_assert_uint_eq(response.resultsSize, 1);
     ck_assert_uint_eq(response.results[0].statusCode, UA_STATUSCODE_GOOD);

+ 2 - 1
tests/server/check_subscription_events.c

@@ -144,9 +144,10 @@ removeSubscription(void) {
 
     UA_DeleteSubscriptionsResponse deleteSubscriptionsResponse;
     UA_DeleteSubscriptionsResponse_init(&deleteSubscriptionsResponse);
-
+    UA_LOCK(server->serviceMutex);
     Service_DeleteSubscriptions(server, &server->adminSession, &deleteSubscriptionsRequest,
                                 &deleteSubscriptionsResponse);
+    UA_UNLOCK(server->serviceMutex);
     UA_DeleteSubscriptionsResponse_deleteMembers(&deleteSubscriptionsResponse);
 }