Browse Source

feat(multithreading): Adding locks for Callbacks-, NodeManagement- and Discovery-functions

Ubuntu 5 years ago
parent
commit
12e959aa2c

+ 13 - 13
include/open62541/server.h

@@ -103,7 +103,7 @@ typedef void (*UA_ServerCallback)(UA_Server *server, void *data);
  *        identifier is not set.
  * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
  *         otherwise. */
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback,
                            void *data, UA_DateTime date, UA_UInt64 *callbackId);
 
@@ -120,11 +120,11 @@ UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback,
  *        identifier is not set.
  * @return Upon success, UA_STATUSCODE_GOOD is returned. An error code
  *         otherwise. */
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
                               void *data, UA_Double interval_ms, UA_UInt64 *callbackId);
 
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
                                          UA_Double interval_ms);
 
@@ -132,7 +132,7 @@ UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId
  *
  * @param server The server object.
  * @param callbackId The id of the callback */
-void UA_EXPORT
+void UA_EXPORT UA_THREADSAFE
 UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId);
 
 #define UA_Server_removeRepeatedCallback(server, callbackId) \
@@ -496,7 +496,7 @@ typedef UA_StatusCode
                            UA_NodeId referenceTypeId, void *handle);
 #endif
 
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
                                UA_NodeIteratorCallback callback, void *handle);
 
@@ -517,7 +517,7 @@ UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
  * @param client the client which is used to call the RegisterServer. It must
  *        already be connected to the correct endpoint
  * @param semaphoreFilePath optional parameter pointing to semaphore file. */
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_register_discovery(UA_Server *server, struct UA_Client *client,
                              const char* semaphoreFilePath);
 
@@ -526,7 +526,7 @@ UA_Server_register_discovery(UA_Server *server, struct UA_Client *client,
  * @param server
  * @param client the client which is used to call the RegisterServer. It must
  *        already be connected to the correct endpoint */
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_unregister_discovery(UA_Server *server, struct UA_Client *client);
 
  /* Adds a periodic callback to register the server with the LDS (local discovery server)
@@ -552,7 +552,7 @@ UA_Server_unregister_discovery(UA_Server *server, struct UA_Client *client);
   * @param intervalMs
   * @param delayFirstRegisterMs
   * @param periodicCallbackId */
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_addPeriodicServerRegisterCallback(UA_Server *server, struct UA_Client *client,
                                             const char* discoveryServerUrl,
                                             UA_Double intervalMs,
@@ -572,7 +572,7 @@ typedef void (*UA_Server_registerServerCallback)(const UA_RegisteredServer *regi
  * @param cb the callback
  * @param data data passed to the callback
  * @return UA_STATUSCODE_SUCCESS on success */
-void UA_EXPORT
+void UA_EXPORT UA_THREADSAFE
 UA_Server_setRegisterServerCallback(UA_Server *server, UA_Server_registerServerCallback cb,
                                     void* data);
 
@@ -600,7 +600,7 @@ typedef void (*UA_Server_serverOnNetworkCallback)(const UA_ServerOnNetwork *serv
  * @param cb the callback
  * @param data data passed to the callback
  * @return UA_STATUSCODE_SUCCESS on success */
-void UA_EXPORT
+void UA_EXPORT UA_THREADSAFE
 UA_Server_setServerOnNetworkCallback(UA_Server *server,
                                      UA_Server_serverOnNetworkCallback cb,
                                      void* data);
@@ -729,16 +729,16 @@ typedef struct {
                        const UA_NodeId *nodeId, void **nodeContext);
 } UA_NodeTypeLifecycle;
 
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
                                UA_NodeTypeLifecycle lifecycle);
 
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
                          void **nodeContext);
 
 /* Careful! The user has to ensure that the destructor callbacks still work. */
-UA_StatusCode UA_EXPORT
+UA_StatusCode UA_EXPORT UA_THREADSAFE
 UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
                          void *nodeContext);
 

+ 44 - 8
src/server/ua_server.c

@@ -119,9 +119,12 @@ UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
 UA_StatusCode
 UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
                                UA_NodeIteratorCallback callback, void *handle) {
+    UA_LOCK(server->serviceMutex);
     const UA_Node *parent = UA_Nodestore_getNode(server->nsCtx, &parentNodeId);
-    if(!parent)
+    if(!parent) {
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADNODEIDINVALID;
+    }
 
     /* TODO: We need to do an ugly copy of the references array since users may
      * delete references from within the callback. In single-threaded mode this
@@ -133,6 +136,7 @@ UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
     UA_Node *parentCopy = UA_Node_copy_alloc(parent);
     if(!parentCopy) {
         UA_Nodestore_releaseNode(server->nsCtx, parent);
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADUNEXPECTEDERROR;
     }
 
@@ -140,8 +144,10 @@ UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
     for(size_t i = parentCopy->referencesSize; i > 0; --i) {
         UA_NodeReferenceKind *ref = &parentCopy->references[i - 1];
         for(size_t j = 0; j<ref->targetIdsSize; j++) {
+            UA_UNLOCK(server->serviceMutex);
             retval = callback(ref->targetIds[j].nodeId, ref->isInverse,
                               ref->referenceTypeId, handle);
+            UA_LOCK(server->serviceMutex);
             if(retval != UA_STATUSCODE_GOOD)
                 goto cleanup;
         }
@@ -152,6 +158,7 @@ cleanup:
     UA_free(parentCopy);
 
     UA_Nodestore_releaseNode(server->nsCtx, parent);
+    UA_UNLOCK(server->serviceMutex);
     return retval;
 }
 
@@ -328,32 +335,61 @@ setServerShutdown(UA_Server *server) {
 UA_StatusCode
 UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback,
                            void *data, UA_DateTime date, UA_UInt64 *callbackId) {
-    return UA_Timer_addTimedCallback(&server->timer,
-                                     (UA_ApplicationCallback)callback,
-                                     server, data, date, callbackId);
+    UA_LOCK(server->serviceMutex);
+    UA_StatusCode retval = UA_Timer_addTimedCallback(&server->timer,
+                                                     (UA_ApplicationCallback)callback,
+                                                      server, data, date, callbackId);
+    UA_UNLOCK(server->serviceMutex);
+    return retval;
 }
 
 UA_StatusCode
-UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
+addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
                               void *data, UA_Double interval_ms,
                               UA_UInt64 *callbackId) {
     return UA_Timer_addRepeatedCallback(&server->timer,
                                         (UA_ApplicationCallback)callback,
-                                        server, data, interval_ms, callbackId);
+                                         server, data, interval_ms, callbackId);
 }
 
 UA_StatusCode
-UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
+UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
+                              void *data, UA_Double interval_ms,
+                              UA_UInt64 *callbackId) {
+    UA_LOCK(server->serviceMutex);
+    UA_StatusCode retval = addRepeatedCallback(server, callback, data, interval_ms, callbackId);
+    UA_UNLOCK(server->serviceMutex);
+    return retval;
+}
+
+UA_StatusCode
+changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
                                          UA_Double interval_ms) {
     return UA_Timer_changeRepeatedCallbackInterval(&server->timer, callbackId,
                                                    interval_ms);
 }
 
+UA_StatusCode
+UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
+                                         UA_Double interval_ms) {
+    UA_LOCK(server->serviceMutex);
+    UA_StatusCode retval = changeRepeatedCallbackInterval(server, callbackId, interval_ms);
+    UA_UNLOCK(server->serviceMutex);
+    return retval;
+}
+
 void
-UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId) {
+removeCallback(UA_Server *server, UA_UInt64 callbackId) {
     UA_Timer_removeCallback(&server->timer, callbackId);
 }
 
+void
+UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId) {
+    UA_LOCK(server->serviceMutex);
+    removeCallback(server, callbackId);
+    UA_UNLOCK(server->serviceMutex);
+}
+
 UA_StatusCode UA_EXPORT
 UA_Server_updateCertificate(UA_Server *server,
                             const UA_ByteString *oldCertificate,

+ 14 - 6
src/server/ua_server_discovery.c

@@ -12,11 +12,13 @@
 
 #ifdef UA_ENABLE_DISCOVERY
 
-static UA_StatusCode
+UA_StatusCode
 register_server_with_discovery_server(UA_Server *server,
-                                      UA_Client *client,
+                                      void *pClient,
                                       const UA_Boolean isUnregister,
                                       const char* semaphoreFilePath) {
+    UA_Client *client = (UA_Client *) pClient;
+
     /* Prepare the request. Do not cleanup the request after the service call,
      * as the members are stack-allocated or point into the server config. */
     UA_RegisterServer2Request request;
@@ -116,14 +118,20 @@ register_server_with_discovery_server(UA_Server *server,
 UA_StatusCode
 UA_Server_register_discovery(UA_Server *server, UA_Client *client,
                              const char* semaphoreFilePath) {
-    return register_server_with_discovery_server(server, client,
-                                                 false, semaphoreFilePath);
+    UA_LOCK(server->serviceMutex);
+    UA_StatusCode retval = register_server_with_discovery_server(server, client,
+                                                                 false, semaphoreFilePath);
+    UA_UNLOCK(server->serviceMutex);
+    return retval;
 }
 
 UA_StatusCode
 UA_Server_unregister_discovery(UA_Server *server, UA_Client *client) {
-    return register_server_with_discovery_server(server, client,
-                                                 true, NULL);
+    UA_LOCK(server->serviceMutex);
+    UA_StatusCode retval = register_server_with_discovery_server(server, client,
+                                                                 true, NULL);
+    UA_UNLOCK(server->serviceMutex);
+    return retval;
 }
 
 #endif /* UA_ENABLE_DISCOVERY */

+ 20 - 0
src/server/ua_server_internal.h

@@ -263,6 +263,26 @@ UA_StatusCode
 writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
                     const UA_QualifiedName propertyName, const UA_Variant value);
 
+UA_StatusCode
+getNodeContext(UA_Server *server, UA_NodeId nodeId, void **nodeContext);
+
+void
+removeCallback(UA_Server *server, UA_UInt64 callbackId);
+
+UA_StatusCode
+changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId, UA_Double interval_ms);
+
+UA_StatusCode
+addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
+                    void *data, UA_Double interval_ms, UA_UInt64 *callbackId);
+
+#ifdef UA_ENABLE_DISCOVERY
+UA_StatusCode
+register_server_with_discovery_server(UA_Server *server,
+                                      void *client,
+                                      const UA_Boolean isUnregister,
+                                      const char* semaphoreFilePath);
+#endif
 /***************************************/
 /* Check Information Model Consistency */
 /***************************************/

+ 36 - 16
src/server/ua_services_discovery.c

@@ -408,10 +408,13 @@ process_RegisterServer(UA_Server *server, UA_Session *session,
             return;
         }
 
-        if(server->discoveryManager.registerServerCallback)
+        if(server->discoveryManager.registerServerCallback) {
+            UA_UNLOCK(server->serviceMutex);
             server->discoveryManager.
-                registerServerCallback(requestServer,
-                                       server->discoveryManager.registerServerCallbackData);
+                    registerServerCallback(requestServer,
+                                           server->discoveryManager.registerServerCallbackData);
+            UA_LOCK(server->serviceMutex);
+        }
 
         // server found, remove from list
         LIST_REMOVE(registeredServer_entry, pointers);
@@ -455,10 +458,13 @@ process_RegisterServer(UA_Server *server, UA_Session *session,
     // Previously we only called it if it was a new register call. It may be the case that this endpoint
     // registered before, then crashed, restarts and registeres again. In that case the entry is not deleted
     // and the callback would not be called.
-    if(server->discoveryManager.registerServerCallback)
+    if(server->discoveryManager.registerServerCallback) {
+        UA_UNLOCK(server->serviceMutex);
         server->discoveryManager.
-            registerServerCallback(requestServer,
-                                   server->discoveryManager.registerServerCallbackData);
+                registerServerCallback(requestServer,
+                                       server->discoveryManager.registerServerCallbackData);
+        UA_LOCK(server->serviceMutex)
+    }
 
     // copy the data from the request into the list
     UA_RegisteredServer_copy(requestServer, &registeredServer_entry->registeredServer);
@@ -565,6 +571,7 @@ void UA_Discovery_cleanupTimedOut(UA_Server *server, UA_DateTime nowMonotonic) {
 static void
 periodicServerRegister(UA_Server *server, void *data) {
     UA_assert(data != NULL);
+    UA_LOCK(server->serviceMutex);
 
     struct PeriodicServerRegisterCallback *cb = (struct PeriodicServerRegisterCallback *)data;
 
@@ -578,7 +585,7 @@ periodicServerRegister(UA_Server *server, void *data) {
            UA_StatusCode retval = UA_Server_register_discovery(server,
            "opc.tcp://localhost:4840", "/path/to/some/file");
         */
-        retval = UA_Server_register_discovery(server, cb->client, NULL);
+        retval = register_server_with_discovery_server(server, cb->client, false, NULL);
     }
     if (cb->client->state == UA_CLIENTSTATE_CONNECTED) {
         UA_StatusCode retval1 = UA_Client_disconnect(cb->client);
@@ -606,7 +613,8 @@ periodicServerRegister(UA_Server *server, void *data) {
             nextInterval = cb->default_interval;
 
         cb->this_interval = nextInterval;
-        UA_Server_changeRepeatedCallbackInterval(server, cb->id, nextInterval);
+        changeRepeatedCallbackInterval(server, cb->id, nextInterval);
+        UA_UNLOCK(server->serviceMutex);
         return;
     }
 
@@ -616,11 +624,12 @@ periodicServerRegister(UA_Server *server, void *data) {
                  (int)(cb->default_interval/1000));
 
     if(!cb->registered) {
-        retval = UA_Server_changeRepeatedCallbackInterval(server, cb->id, cb->default_interval);
+        retval = changeRepeatedCallbackInterval(server, cb->id, cb->default_interval);
         /* If changing the interval fails, try again after the next registering */
         if(retval == UA_STATUSCODE_GOOD)
             cb->registered = true;
     }
+    UA_UNLOCK(server->serviceMutex);
 }
 
 UA_StatusCode
@@ -630,17 +639,20 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server,
                                             UA_Double intervalMs,
                                             UA_Double delayFirstRegisterMs,
                                             UA_UInt64 *periodicCallbackId) {
-
+    UA_LOCK(server->serviceMutex);
     /* No valid server URL */
     if(!discoveryServerUrl) {
         UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER,
                      "No discovery server URL provided");
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADINTERNALERROR;
     }
 
 
-    if (client->connection.state != UA_CONNECTION_CLOSED)
+    if (client->connection.state != UA_CONNECTION_CLOSED) {
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADINVALIDSTATE;
+    }
 
     /* check if we are already registering with the given discovery url and remove the old periodic call */
     {
@@ -650,7 +662,7 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server,
             if(strcmp(rs->callback->discovery_server_url, discoveryServerUrl) == 0) {
                 UA_LOG_INFO(&server->config.logger, UA_LOGCATEGORY_SERVER,
                             "There is already a register callback for '%s' in place. Removing the older one.", discoveryServerUrl);
-                UA_Server_removeRepeatedCallback(server, rs->callback->id);
+                removeCallback(server, rs->callback->id);
                 LIST_REMOVE(rs, pointers);
                 UA_free(rs->callback->discovery_server_url);
                 UA_free(rs->callback);
@@ -664,8 +676,10 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server,
     struct PeriodicServerRegisterCallback* cb =
         (struct PeriodicServerRegisterCallback*)
         UA_malloc(sizeof(struct PeriodicServerRegisterCallback));
-    if(!cb)
+    if(!cb) {
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADOUTOFMEMORY;
+    }
 
     /* Start repeating a failed register after 1s, then increase the delay. Set
      * to 500ms, as the delay is doubled before changing the callback
@@ -678,19 +692,21 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server,
     cb->discovery_server_url = (char*)UA_malloc(len+1);
     if (!cb->discovery_server_url) {
         UA_free(cb);
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
     memcpy(cb->discovery_server_url, discoveryServerUrl, len+1);
 
     /* Add the callback */
     UA_StatusCode retval =
-        UA_Server_addRepeatedCallback(server, periodicServerRegister,
-                                      cb, delayFirstRegisterMs, &cb->id);
+        addRepeatedCallback(server, periodicServerRegister,
+                            cb, delayFirstRegisterMs, &cb->id);
     if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_ERROR(&server->config.logger, UA_LOGCATEGORY_SERVER,
                      "Could not create periodic job for server register. "
                      "StatusCode %s", UA_StatusCode_name(retval));
         UA_free(cb);
+        UA_UNLOCK(server->serviceMutex);
         return retval;
     }
 
@@ -699,8 +715,9 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server,
     periodicServerRegisterCallback_entry *newEntry =
             (periodicServerRegisterCallback_entry *)UA_malloc(sizeof(periodicServerRegisterCallback_entry));
     if(!newEntry) {
-        UA_Server_removeRepeatedCallback(server, cb->id);
+        removeCallback(server, cb->id);
         UA_free(cb);
+        UA_UNLOCK(server->serviceMutex);
         return UA_STATUSCODE_BADOUTOFMEMORY;
     }
     newEntry->callback = cb;
@@ -709,6 +726,7 @@ UA_Server_addPeriodicServerRegisterCallback(UA_Server *server,
 
     if(periodicCallbackId)
         *periodicCallbackId = cb->id;
+    UA_UNLOCK(server->serviceMutex);
     return UA_STATUSCODE_GOOD;
 }
 
@@ -716,8 +734,10 @@ void
 UA_Server_setRegisterServerCallback(UA_Server *server,
                                     UA_Server_registerServerCallback cb,
                                     void* data) {
+    UA_LOCK(server->serviceMutex);
     server->discoveryManager.registerServerCallback = cb;
     server->discoveryManager.registerServerCallbackData = data;
+    UA_UNLOCK(server->serviceMutex);
 }
 
 #endif /* UA_ENABLE_DISCOVERY */

+ 2 - 0
src/server/ua_services_discovery_multicast.c

@@ -255,8 +255,10 @@ void
 UA_Server_setServerOnNetworkCallback(UA_Server *server,
                                      UA_Server_serverOnNetworkCallback cb,
                                      void* data) {
+    UA_LOCK(server->serviceMutex);
     server->discoveryManager.serverOnNetworkCallback = cb;
     server->discoveryManager.serverOnNetworkCallbackData = data;
+    UA_UNLOCK(server->serviceMutex);
 }
 
 static void

+ 1 - 1
src/server/ua_services_monitoreditem.c

@@ -248,7 +248,7 @@ Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session, struct cre
     /* Register MonitoredItem in userland */
     if(server->config.monitoredItemRegisterCallback) {
         void *targetContext = NULL;
-        UA_Server_getNodeContext(server, request->itemToMonitor.nodeId, &targetContext);
+        getNodeContext(server, request->itemToMonitor.nodeId, &targetContext);
         UA_UNLOCK(server->serviceMutex);
         server->config.monitoredItemRegisterCallback(server, &session->sessionId,
                                                      session->sessionHandle,

+ 27 - 6
src/server/ua_services_nodemanagement.c

@@ -33,6 +33,15 @@
 UA_StatusCode
 UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
                          void **nodeContext) {
+    UA_LOCK(server->serviceMutex);
+    UA_StatusCode retval = getNodeContext(server, nodeId, nodeContext);
+    UA_UNLOCK(server->serviceMutex);
+    return retval;
+}
+
+UA_StatusCode
+getNodeContext(UA_Server *server, UA_NodeId nodeId,
+                         void **nodeContext) {
     const UA_Node *node = UA_Nodestore_getNode(server->nsCtx, &nodeId);
     if(!node)
         return UA_STATUSCODE_BADNODEIDUNKNOWN;
@@ -66,8 +75,11 @@ editNodeContext(UA_Server *server, UA_Session* session,
 UA_StatusCode
 UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
                          void *nodeContext) {
-    return UA_Server_editNode(server, &server->adminSession, &nodeId,
+    UA_LOCK(server->serviceMutex);
+    UA_StatusCode retval = UA_Server_editNode(server, &server->adminSession, &nodeId,
                               (UA_EditNodeCallback)editNodeContext, nodeContext);
+    UA_UNLOCK(server->serviceMutex);
+    return retval;
 }
 
 /**********************/
@@ -1479,20 +1491,26 @@ recursiveDeconstructNode(UA_Server *server, UA_Session *session,
                 lifecycle = &((const UA_ObjectTypeNode*)type)->lifecycle;
             else
                 lifecycle = &((const UA_VariableTypeNode*)type)->lifecycle;
-            if(lifecycle->destructor)
+            if(lifecycle->destructor) {
+                UA_UNLOCK(server->serviceMutex);
                 lifecycle->destructor(server,
                                       &session->sessionId, session->sessionHandle,
                                       &type->nodeId, type->context,
                                       &node->nodeId, &context);
+                UA_LOCK(server->serviceMutex);
+            }
             UA_Nodestore_releaseNode(server->nsCtx, type);
         }
     }
 
     /* Call the global destructor */
-    if(server->config.nodeLifecycle.destructor)
+    if(server->config.nodeLifecycle.destructor) {
+        UA_UNLOCK(server->serviceMutex);
         server->config.nodeLifecycle.destructor(server, &session->sessionId,
                                                 session->sessionHandle,
                                                 &node->nodeId, context);
+        UA_LOCK(server->serviceMutex);
+    }
 
     /* Set the constructed flag to false */
     UA_Server_editNode(server, &server->adminSession, &node->nodeId,
@@ -2233,7 +2251,10 @@ setNodeTypeLifecycle(UA_Server *server, UA_Session *session,
 UA_StatusCode
 UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
                                UA_NodeTypeLifecycle lifecycle) {
-    return UA_Server_editNode(server, &server->adminSession, &nodeId,
-                              (UA_EditNodeCallback)setNodeTypeLifecycle,
-                              &lifecycle);
+    UA_LOCK(server->serviceMutex);
+    UA_StatusCode retval = UA_Server_editNode(server, &server->adminSession, &nodeId,
+                                             (UA_EditNodeCallback)setNodeTypeLifecycle,
+                                              &lifecycle);
+    UA_UNLOCK(server->serviceMutex);
+    return retval;
 }

+ 3 - 3
src/server/ua_subscription.c

@@ -563,8 +563,8 @@ Subscription_registerPublishCallback(UA_Server *server, UA_Subscription *sub) {
         return UA_STATUSCODE_GOOD;
 
     UA_StatusCode retval =
-        UA_Server_addRepeatedCallback(server, (UA_ServerCallback)publishCallback,
-                                      sub, (UA_UInt32)sub->publishingInterval, &sub->publishCallbackId);
+        addRepeatedCallback(server, (UA_ServerCallback)publishCallback,
+                            sub, (UA_UInt32)sub->publishingInterval, &sub->publishCallbackId);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
@@ -580,7 +580,7 @@ Subscription_unregisterPublishCallback(UA_Server *server, UA_Subscription *sub)
     if(!sub->publishCallbackIsRegistered)
         return;
 
-    UA_Server_removeRepeatedCallback(server, sub->publishCallbackId);
+    removeCallback(server, sub->publishCallbackId);
     sub->publishCallbackIsRegistered = false;
 }
 

+ 1 - 1
src/server/ua_subscription_datachange.c

@@ -307,7 +307,7 @@ sampleCallbackWithValue(UA_Server *server, UA_Session *session,
     if(!sub) {
         UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*) mon;
         void *nodeContext = NULL;
-        UA_Server_getNodeContext(server, mon->monitoredNodeId, &nodeContext);
+        getNodeContext(server, mon->monitoredNodeId, &nodeContext);
         UA_UNLOCK(server->serviceMutex);
         localMon->callback.dataChangeCallback(server, mon->monitoredItemId,
                                               localMon->context,

+ 7 - 4
src/server/ua_subscription_monitoreditem.c

@@ -231,13 +231,15 @@ UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *monitoredItem) {
 
         /* Get the node context */
         void *targetContext = NULL;
-        UA_Server_getNodeContext(server, monitoredItem->monitoredNodeId, &targetContext);
+        getNodeContext(server, monitoredItem->monitoredNodeId, &targetContext);
 
         /* Deregister */
+        UA_UNLOCK(server->serviceMutex);
         server->config.monitoredItemRegisterCallback(server, &session->sessionId,
                                                      session->sessionHandle,
                                                      &monitoredItem->monitoredNodeId,
                                                      targetContext, monitoredItem->attributeId, true);
+        UA_LOCK(server->serviceMutex);
     }
 
     /* Remove the monitored item */
@@ -352,8 +354,8 @@ UA_MonitoredItem_registerSampleCallback(UA_Server *server, UA_MonitoredItem *mon
         return UA_STATUSCODE_GOOD;
 
     UA_StatusCode retval =
-        UA_Server_addRepeatedCallback(server, (UA_ServerCallback)UA_MonitoredItem_sampleCallback,
-                                      mon, mon->samplingInterval, &mon->sampleCallbackId);
+        addRepeatedCallback(server, (UA_ServerCallback)UA_MonitoredItem_sampleCallback,
+                            mon, mon->samplingInterval, &mon->sampleCallbackId);
     if(retval == UA_STATUSCODE_GOOD)
         mon->sampleCallbackIsRegistered = true;
     return retval;
@@ -361,9 +363,10 @@ UA_MonitoredItem_registerSampleCallback(UA_Server *server, UA_MonitoredItem *mon
 
 void
 UA_MonitoredItem_unregisterSampleCallback(UA_Server *server, UA_MonitoredItem *mon) {
+    UA_LOCK_ASSERT(server->serviceMutex, 1);
     if(!mon->sampleCallbackIsRegistered)
         return;
-    UA_Server_removeRepeatedCallback(server, mon->sampleCallbackId);
+    removeCallback(server, mon->sampleCallbackId);
     mon->sampleCallbackIsRegistered = false;
 }