Explorar el Código

remove last uses of thread_local variables

thread_local is now only used for test-builds.
This introduces an additional context-variable to service calls.
Julius Pfrommer hace 7 años
padre
commit
d783f983c7

+ 4 - 3
src/server/ua_server_internal.h

@@ -218,12 +218,14 @@ const UA_Node * getNodeType(UA_Server *server, const UA_Node *node);
 /* Many services come as an array of operations. This function generalizes the
  * processing of the operations. */
 typedef void (*UA_ServiceOperation)(UA_Server *server, UA_Session *session,
+                                    void *context,
                                     const void *requestOperation,
                                     void *responseOperation);
 
 UA_StatusCode
 UA_Server_processServiceOperations(UA_Server *server, UA_Session *session,
                                    UA_ServiceOperation operationCallback,
+                                   void *context,
                                    const size_t *requestOperations,
                                    const UA_DataType *requestOperationsType,
                                    size_t *responseOperations,
@@ -334,9 +336,8 @@ UA_Discovery_removeRecord(UA_Server *server, const UA_String *servername,
 
 /* Creates a new node in the nodestore. */
 UA_StatusCode
-Operation_addNode_begin(UA_Server *server, UA_Session *session,
-                        const UA_AddNodesItem *item, void *nodeContext,
-                        UA_NodeId *outNewNodeId);
+Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
+                        const UA_AddNodesItem *item, UA_NodeId *outNewNodeId);
 
 /* Children, references, type-checking, constructors. */
 UA_StatusCode

+ 2 - 2
src/server/ua_server_ns0.c

@@ -23,7 +23,7 @@ addNode_begin(UA_Server *server, UA_NodeClass nodeClass,
     item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
     item.nodeAttributes.content.decoded.data = attributes;
     item.nodeAttributes.content.decoded.type = attributesType;
-    return Operation_addNode_begin(server, &adminSession, &item, NULL, NULL);
+    return Operation_addNode_begin(server, &adminSession, NULL, &item, NULL);
 }
 
 static UA_StatusCode
@@ -35,7 +35,7 @@ addNode_finish(UA_Server *server, UA_UInt32 nodeId,
     UA_NodeId referenceType = UA_NODEID_NUMERIC(0, referenceTypeId);
     UA_NodeId typeDefinition = UA_NODEID_NUMERIC(0, typeDefinitionId);
     return Operation_addNode_finish(server, &adminSession, &node, &parentNode,
-                             &referenceType, &typeDefinition);
+                                    &referenceType, &typeDefinition);
 }
 
 static UA_StatusCode

+ 3 - 2
src/server/ua_server_utils.c

@@ -85,7 +85,7 @@ UA_NumericRange_parseFromString(UA_NumericRange *range, const UA_String *str) {
 /* Information Model Operations */
 /********************************/
 
-/**
+/*
  * Keeps track of already visited nodes to detect circular references
  */
 struct ref_history {
@@ -383,6 +383,7 @@ UA_Server_editNode(UA_Server *server, UA_Session *session,
 UA_StatusCode
 UA_Server_processServiceOperations(UA_Server *server, UA_Session *session,
                                    UA_ServiceOperation operationCallback,
+                                   void *context,
                                    const size_t *requestOperations,
                                    const UA_DataType *requestOperationsType,
                                    size_t *responseOperations,
@@ -402,7 +403,7 @@ UA_Server_processServiceOperations(UA_Server *server, UA_Session *session,
     /* No padding after size_t */
     uintptr_t reqOp = *(uintptr_t*)((uintptr_t)requestOperations + sizeof(size_t));
     for(size_t i = 0; i < ops; i++) {
-        operationCallback(server, session, (void*)reqOp, (void*)respOp);
+        operationCallback(server, session, context, (void*)reqOp, (void*)respOp);
         reqOp += requestOperationsType->memSize;
         respOp += responseOperationsType->memSize;
     }

+ 4 - 5
src/server/ua_services_attribute.c

@@ -1245,7 +1245,7 @@ copyAttributeIntoNode(UA_Server *server, UA_Session *session,
 }
 
 static void
-Operation_Write(UA_Server *server, UA_Session *session,
+Operation_Write(UA_Server *server, UA_Session *session, void *context,
                 UA_WriteValue *wv, UA_StatusCode *result) {
     *result = UA_Server_editNode(server, session, &wv->nodeId,
                         (UA_EditNodeCallback)copyAttributeIntoNode, wv);
@@ -1265,10 +1265,9 @@ Service_Write(UA_Server *server, UA_Session *session,
     }
 
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_Write,
-                  &request->nodesToWriteSize, &UA_TYPES[UA_TYPES_WRITEVALUE],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_Write, NULL,
+                                           &request->nodesToWriteSize, &UA_TYPES[UA_TYPES_WRITEVALUE],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
 }
 
 UA_StatusCode

+ 6 - 8
src/server/ua_services_call.c

@@ -194,9 +194,8 @@ callWithMethodAndObject(UA_Server *server, UA_Session *session,
 }
 
 static void
-Operation_CallMethod(UA_Server *server, UA_Session *session,
-                     const UA_CallMethodRequest *request,
-                     UA_CallMethodResult *result) {
+Operation_CallMethod(UA_Server *server, UA_Session *session, void *context,
+                     const UA_CallMethodRequest *request, UA_CallMethodResult *result) {
     /* Get the method node */
     const UA_MethodNode *method = (const UA_MethodNode*)
         server->config.nodestore.getNode(server->config.nodestore.context,
@@ -240,17 +239,16 @@ void Service_Call(UA_Server *server, UA_Session *session,
     }
 
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_CallMethod,
-                  &request->methodsToCallSize, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_CALLMETHODRESULT]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_CallMethod, NULL,
+                                           &request->methodsToCallSize, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_CALLMETHODRESULT]);
 }
 
 UA_CallMethodResult UA_EXPORT
 UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request) {
     UA_CallMethodResult result;
     UA_CallMethodResult_init(&result);
-    Operation_CallMethod(server, &adminSession, request, &result);
+    Operation_CallMethod(server, &adminSession, NULL, request, &result);
     return result;
 }
 

+ 43 - 62
src/server/ua_services_nodemanagement.c

@@ -333,8 +333,8 @@ copyChildNodes(UA_Server *server, UA_Session *session,
                const UA_NodeId *destinationNodeId);
 
 static void
-addReference(UA_Server *server, UA_Session *session,
-             const UA_AddReferencesItem *item, UA_StatusCode *retval);
+Operation_addReference(UA_Server *server, UA_Session *session, void *context,
+                       const UA_AddReferencesItem *item, UA_StatusCode *retval);
 
 
 /*
@@ -441,7 +441,7 @@ copyChildNode(UA_Server *server, UA_Session *session,
         newItem.isForward = true;
         newItem.targetNodeId = rd->nodeId;
         newItem.targetNodeClass = UA_NODECLASS_METHOD;
-        addReference(server, session, &newItem, &retval);
+        Operation_addReference(server, session, NULL, &newItem, &retval);
         return retval;
     }
 
@@ -601,7 +601,7 @@ addTypeDefRef(UA_Server *server, UA_Session *session,
     addref.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASTYPEDEFINITION);
     addref.isForward = true;
     addref.targetNodeId.nodeId = type->nodeId;
-    addReference(server, session, &addref, &retval);
+    Operation_addReference(server, session, NULL, &addref, &retval);
     return retval;
 }
 
@@ -617,7 +617,7 @@ addParentRef(UA_Server *server, UA_Session *session,
     ref_item.referenceTypeId = *referenceTypeId;
     ref_item.isForward = false;
     ref_item.targetNodeId.nodeId = *parentNodeId;
-    addReference(server, session, &ref_item, &retval);
+    Operation_addReference(server, session, NULL, &ref_item, &retval);
     return retval;
 }
 
@@ -627,9 +627,8 @@ addParentRef(UA_Server *server, UA_Session *session,
 
 /* Prepare the node, then add it to the nodestore */
 UA_StatusCode
-Operation_addNode_begin(UA_Server *server, UA_Session *session,
-                        const UA_AddNodesItem *item, void *nodeContext,
-                        UA_NodeId *outNewNodeId) {
+Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
+                        const UA_AddNodesItem *item, UA_NodeId *outNewNodeId) {
     /* Check the namespaceindex */
     if(item->requestedNewNodeId.nodeId.namespaceIndex >= server->namespacesSize) {
         UA_LOG_INFO_SESSION(server->config.logger, session,
@@ -930,8 +929,8 @@ Operation_addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId
 }
 
 static void
-Operation_addNode(UA_Server *server, UA_Session *session, const UA_AddNodesItem *item,
-                  void *nodeContext, UA_AddNodesResult *result) {
+Operation_addNode(UA_Server *server, UA_Session *session, void *nodeContext,
+                  const UA_AddNodesItem *item, UA_AddNodesResult *result) {
     /* Do not check access for server */
     if(session != &adminSession && server->config.accessControl.allowAddNode &&
        !server->config.accessControl.allowAddNode(&session->sessionId, session->sessionHandle, item)) {
@@ -939,8 +938,8 @@ Operation_addNode(UA_Server *server, UA_Session *session, const UA_AddNodesItem
         return;
     }
 
-    result->statusCode = Operation_addNode_begin(server, session, item, nodeContext,
-                                                 &result->addedNodeId);
+    result->statusCode = Operation_addNode_begin(server, session, nodeContext,
+                                                 item, &result->addedNodeId);
     if(result->statusCode != UA_STATUSCODE_GOOD)
         return;
 
@@ -955,13 +954,6 @@ Operation_addNode(UA_Server *server, UA_Session *session, const UA_AddNodesItem
         UA_NodeId_deleteMembers(&result->addedNodeId);
 }
 
-static void
-Service_AddNode(UA_Server *server, UA_Session *session,
-                const UA_AddNodesItem *item,
-                UA_AddNodesResult *result) {
-    Operation_addNode(server, session, item, NULL, result);
-}
-
 void
 Service_AddNodes(UA_Server *server, UA_Session *session,
                       const UA_AddNodesRequest *request,
@@ -976,10 +968,9 @@ Service_AddNodes(UA_Server *server, UA_Session *session,
     }
 
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Service_AddNode,
-                  &request->nodesToAddSize, &UA_TYPES[UA_TYPES_ADDNODESITEM],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_addNode, NULL,
+                                           &request->nodesToAddSize, &UA_TYPES[UA_TYPES_ADDNODESITEM],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
 }
 
 UA_StatusCode
@@ -1008,7 +999,7 @@ __UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
     /* Call the normal addnodes service */
     UA_AddNodesResult result;
     UA_AddNodesResult_init(&result);
-    Operation_addNode(server, &adminSession, &item, nodeContext, &result);
+    Operation_addNode(server, &adminSession, nodeContext, &item, &result);
     if(outNewNodeId)
         *outNewNodeId = result.addedNodeId;
     else
@@ -1032,8 +1023,8 @@ UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
     item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
     item.nodeAttributes.content.decoded.type = attributeType;
     item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr;
-    return Operation_addNode_begin(server, &adminSession, &item,
-                                   nodeContext, outNewNodeId);
+    return Operation_addNode_begin(server, &adminSession, nodeContext,
+                                   &item, outNewNodeId);
 }
 
 UA_StatusCode
@@ -1050,9 +1041,8 @@ UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId,
 /****************/
 
 static void
-deleteReference(UA_Server *server, UA_Session *session,
-                const UA_DeleteReferencesItem *item,
-                UA_StatusCode *retval);
+Operation_deleteReference(UA_Server *server, UA_Session *session, void *context,
+                          const UA_DeleteReferencesItem *item, UA_StatusCode *retval);
 
 /* Remove references to this node (in the other nodes) */
 static void
@@ -1069,7 +1059,7 @@ removeIncomingReferences(UA_Server *server, UA_Session *session,
         item.referenceTypeId = refs->referenceTypeId;
         for(size_t j = 0; j < refs->targetIdsSize; ++j) {
             item.sourceNodeId = refs->targetIds[j].nodeId;
-            deleteReference(server, session, &item, &dummy);
+            Operation_deleteReference(server, session, NULL, &item, &dummy);
         }
     }
 }
@@ -1105,7 +1095,7 @@ deconstructNode(UA_Server *server, UA_Session *session,
 }
 
 static void
-deleteNodeOperation(UA_Server *server, UA_Session *session,
+deleteNodeOperation(UA_Server *server, UA_Session *session, void *context,
                     const UA_DeleteNodesItem *item, UA_StatusCode *result);
 
 static void
@@ -1138,7 +1128,7 @@ removeChildren(UA_Server *server, UA_Session *session,
             continue;
         item.nodeId = rd->nodeId.nodeId;
         UA_StatusCode retval;
-        deleteNodeOperation(server, session, &item, &retval);
+        deleteNodeOperation(server, session, NULL, &item, &retval);
     }
 
     UA_BrowseResult_deleteMembers(&br);
@@ -1160,7 +1150,7 @@ removeDeconstructedNode(UA_Server *server, UA_Session *session,
 }
 
 static void
-deleteNodeOperation(UA_Server *server, UA_Session *session,
+deleteNodeOperation(UA_Server *server, UA_Session *session, void *context,
                     const UA_DeleteNodesItem *item, UA_StatusCode *result) {
     /* Do not check access for server */
     if(session != &adminSession && server->config.accessControl.allowDeleteNode &&
@@ -1205,12 +1195,9 @@ void Service_DeleteNodes(UA_Server *server, UA_Session *session,
     }
 
     response->responseHeader.serviceResult =
-        UA_Server_processServiceOperations(server, session,
-                                           (UA_ServiceOperation)deleteNodeOperation,
-                                           &request->nodesToDeleteSize,
-                                           &UA_TYPES[UA_TYPES_DELETENODESITEM],
-                                           &response->resultsSize,
-                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)deleteNodeOperation, NULL,
+                                           &request->nodesToDeleteSize, &UA_TYPES[UA_TYPES_DELETENODESITEM],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
 }
 
 UA_StatusCode
@@ -1220,7 +1207,7 @@ UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
     item.deleteTargetReferences = deleteReferences;
     item.nodeId = nodeId;
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    deleteNodeOperation(server, &adminSession, &item, &retval);
+    deleteNodeOperation(server, &adminSession, NULL, &item, &retval);
     return retval;
 }
 
@@ -1241,8 +1228,8 @@ deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
 }
 
 static void
-addReference(UA_Server *server, UA_Session *session,
-             const UA_AddReferencesItem *item, UA_StatusCode *retval) {
+Operation_addReference(UA_Server *server, UA_Session *session, void *context,
+                       const UA_AddReferencesItem *item, UA_StatusCode *retval) {
     /* Do not check access for server */
     if(session != &adminSession && server->config.accessControl.allowAddReference &&
        !server->config.accessControl. allowAddReference(&session->sessionId, session->sessionHandle, item)) {
@@ -1300,12 +1287,9 @@ void Service_AddReferences(UA_Server *server, UA_Session *session,
     }
 
     response->responseHeader.serviceResult =
-        UA_Server_processServiceOperations(server, session,
-                                           (UA_ServiceOperation) addReference,
-                                           &request->referencesToAddSize,
-                                           &UA_TYPES[UA_TYPES_ADDREFERENCESITEM],
-                                           &response->resultsSize,
-                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_addReference, NULL,
+                                           &request->referencesToAddSize, &UA_TYPES[UA_TYPES_ADDREFERENCESITEM],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
 }
 
 UA_StatusCode
@@ -1321,7 +1305,7 @@ UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
     item.targetNodeId = targetId;
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    addReference(server, &adminSession, &item, &retval);
+    Operation_addReference(server, &adminSession, NULL, &item, &retval);
     return retval;
 }
 
@@ -1330,8 +1314,8 @@ UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
 /*********************/
 
 static void
-deleteReference(UA_Server *server, UA_Session *session,
-                const UA_DeleteReferencesItem *item, UA_StatusCode *retval) {
+Operation_deleteReference(UA_Server *server, UA_Session *session, void *context,
+                          const UA_DeleteReferencesItem *item, UA_StatusCode *retval) {
     /* Do not check access for server */
     if(session != &adminSession && server->config.accessControl.allowDeleteReference &&
        !server->config.accessControl.allowDeleteReference(&session->sessionId, session->sessionHandle, item)) {
@@ -1373,12 +1357,9 @@ Service_DeleteReferences(UA_Server *server, UA_Session *session,
     }
 
     response->responseHeader.serviceResult =
-        UA_Server_processServiceOperations(server, session,
-                                           (UA_ServiceOperation) deleteReference,
-                                           &request->referencesToDeleteSize,
-                                           &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM],
-                                           &response->resultsSize,
-                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_deleteReference, NULL,
+                                           &request->referencesToDeleteSize, &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
 }
 
 UA_StatusCode
@@ -1394,7 +1375,7 @@ UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
     item.deleteBidirectional = deleteBidirectional;
 
     UA_StatusCode retval = UA_STATUSCODE_GOOD;
-    deleteReference(server, &adminSession, &item, &retval);
+    Operation_deleteReference(server, &adminSession, NULL, &item, &retval);
     return retval;
 }
 
@@ -1444,8 +1425,8 @@ UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requested
         outNewNodeId = &newNodeId;
         deleteNodeId = UA_TRUE;
     }
-    UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, &item,
-                                                   nodeContext, outNewNodeId);
+    UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, nodeContext,
+                                                   &item, outNewNodeId);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
     retval = UA_Server_setVariableNode_dataSource(server, *outNewNodeId, dataSource);
@@ -1599,8 +1580,8 @@ UA_Server_addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
         outNewNodeId = &newId;
     }
 
-    UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, &item,
-                                                   nodeContext, outNewNodeId);
+    UA_StatusCode retval = Operation_addNode_begin(server, &adminSession, nodeContext,
+                                                   &item, outNewNodeId);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 

+ 68 - 75
src/server/ua_services_subscription.c

@@ -115,24 +115,18 @@ Service_ModifySubscription(UA_Server *server, UA_Session *session,
     response->revisedMaxKeepAliveCount = sub->maxKeepAliveCount;
 }
 
-static UA_THREAD_LOCAL UA_Boolean op_publishingEnabled;
-
 static void
 Operation_SetPublishingMode(UA_Server *Server, UA_Session *session,
-                            UA_UInt32 *subscriptionId,
+                            UA_Boolean *publishingEnabled, UA_UInt32 *subscriptionId,
                             UA_StatusCode *result) {
-    UA_Subscription *sub =
-        UA_Session_getSubscriptionById(session, *subscriptionId);
+    UA_Subscription *sub = UA_Session_getSubscriptionById(session, *subscriptionId);
     if(!sub) {
         *result = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return;
     }
 
-    /* Reset the subscription lifetime */
-    sub->currentLifetimeCount = 0; 
-
-    /* Set the publishing mode */
-    sub->publishingEnabled = op_publishingEnabled;
+    sub->currentLifetimeCount = 0; /* Reset the subscription lifetime */
+    sub->publishingEnabled = *publishingEnabled; /* Set the publishing mode */
 }
 
 void
@@ -141,13 +135,12 @@ Service_SetPublishingMode(UA_Server *server, UA_Session *session,
                           UA_SetPublishingModeResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing SetPublishingModeRequest");
-
-    op_publishingEnabled = request->publishingEnabled;
+    UA_Boolean publishingEnabled = request->publishingEnabled; /* request is const */
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_SetPublishingMode,
-                  &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_SetPublishingMode,
+                                           &publishingEnabled,
+                                           &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
 }
 
 static void
@@ -206,18 +199,20 @@ setMonitoredItemSettings(UA_Server *server, UA_MonitoredItem *mon,
 static const UA_String binaryEncoding = {sizeof("Default Binary")-1, (UA_Byte*)"Default Binary"};
 
 /* Thread-local variables to pass additional arguments into the operation */
-static UA_THREAD_LOCAL UA_Subscription *op_sub;
-static UA_THREAD_LOCAL UA_TimestampsToReturn op_timestampsToReturn2;
+struct createMonContext {
+    UA_Subscription *sub;
+    UA_TimestampsToReturn timestampsToReturn;
+};
 
 static void
-Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session,
+Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session, struct createMonContext *cmc,
                               const UA_MonitoredItemCreateRequest *request,
                               UA_MonitoredItemCreateResult *result) {
     /* Make an example read to get errors in the itemToMonitor. Allow return
      * codes "good" and "uncertain", as well as a list of statuscodes that might
      * be repaired inside the data source. */
     UA_DataValue v = UA_Server_readWithSession(server, session, &request->itemToMonitor,
-                                               op_timestampsToReturn2);
+                                               cmc->timestampsToReturn);
     if(v.hasStatus && (v.status >> 30) > 1 &&
        v.status != UA_STATUSCODE_BADRESOURCEUNAVAILABLE &&
        v.status != UA_STATUSCODE_BADCOMMUNICATIONERROR &&
@@ -259,14 +254,14 @@ Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session,
         MonitoredItem_delete(server, newMon);
         return;
     }
-    newMon->subscription = op_sub;
+    newMon->subscription = cmc->sub;
     newMon->attributeId = request->itemToMonitor.attributeId;
-    newMon->itemId = ++(op_sub->lastMonitoredItemId);
-    newMon->timestampsToReturn = op_timestampsToReturn2;
+    newMon->itemId = ++(cmc->sub->lastMonitoredItemId);
+    newMon->timestampsToReturn = cmc->timestampsToReturn;
     setMonitoredItemSettings(server, newMon, request->monitoringMode,
                              &request->requestedParameters);
 
-    UA_Subscription_addMonitoredItem(op_sub, newMon);
+    UA_Subscription_addMonitoredItem(cmc->sub, newMon);
 
     /* Create the first sample */
     if(request->monitoringMode == UA_MONITORINGMODE_REPORTING)
@@ -292,44 +287,45 @@ Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
         return;
     }
 
+    struct createMonContext cmc;
+
     /* Check if the timestampstoreturn is valid */
-    op_timestampsToReturn2 = request->timestampsToReturn;
-    if(op_timestampsToReturn2 > UA_TIMESTAMPSTORETURN_NEITHER) {
+    cmc.timestampsToReturn = request->timestampsToReturn;
+    if(cmc.timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
         return;
     }
 
     /* Find the subscription */
-    op_sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
-    if(!op_sub) {
+    cmc.sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
+    if(!cmc.sub) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return;
     }
 
     if((server->config.maxMonitoredItemsPerSubscription != 0) &&
-       ((UA_Subscription_getNumMonitoredItems(op_sub) + request->itemsToCreateSize) >
+       ((UA_Subscription_getNumMonitoredItems(cmc.sub) + request->itemsToCreateSize) >
         server->config.maxMonitoredItemsPerSubscription)) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYMONITOREDITEMS;
         return;
     }
 
     /* Reset the subscription lifetime */
-    op_sub->currentLifetimeCount = 0;
+    cmc.sub->currentLifetimeCount = 0;
 
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_CreateMonitoredItem,
-                  &request->itemsToCreateSize, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_CreateMonitoredItem, &cmc,
+                                           &request->itemsToCreateSize, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT]);
 }
 
 static void
-Operation_ModifyMonitoredItem(UA_Server *server, UA_Session *session,
+Operation_ModifyMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscription *sub,
                               const UA_MonitoredItemModifyRequest *request,
                               UA_MonitoredItemModifyResult *result) {
     /* Get the MonitoredItem */
     UA_MonitoredItem *mon =
-        UA_Subscription_getMonitoredItem(op_sub, request->monitoredItemId);
+        UA_Subscription_getMonitoredItem(sub, request->monitoredItemId);
     if(!mon) {
         result->statusCode = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
         return;
@@ -360,40 +356,41 @@ void Service_ModifyMonitoredItems(UA_Server *server, UA_Session *session,
     }
 
     /* Get the subscription */
-    op_sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
-    if(!op_sub) {
+    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
+    if(!sub) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return;
     }
 
-    /* Reset the subscription lifetime */
-    op_sub->currentLifetimeCount = 0;
+    sub->currentLifetimeCount = 0; /* Reset the subscription lifetime */
 
     response->responseHeader.serviceResult = 
         UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_ModifyMonitoredItem,
-                  &request->itemsToModifySize, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT]);
+                                           (UA_ServiceOperation)Operation_ModifyMonitoredItem, sub,
+                                           &request->itemsToModifySize, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT]);
 }
 
-/* Get the additional argument into the operation */
-static UA_THREAD_LOCAL UA_MonitoringMode op_monitoringMode;
+struct setMonitoringContext {
+    UA_Subscription *sub;
+    UA_MonitoringMode monitoringMode;
+};
 
 static void
 Operation_SetMonitoringMode(UA_Server *server, UA_Session *session,
-                            UA_UInt32 *monitoredItemId,
-                            UA_StatusCode *result) {
+                            struct setMonitoringContext *smc,
+                            UA_UInt32 *monitoredItemId, UA_StatusCode *result) {
     UA_MonitoredItem *mon =
-        UA_Subscription_getMonitoredItem(op_sub, *monitoredItemId);
+        UA_Subscription_getMonitoredItem(smc->sub, *monitoredItemId);
     if(!mon) {
         *result = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
         return;
     }
 
-    if(mon->monitoringMode == op_monitoringMode)
+    if(mon->monitoringMode == smc->monitoringMode)
         return;
 
-    mon->monitoringMode = op_monitoringMode;
+    mon->monitoringMode = smc->monitoringMode;
     if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING)
         MonitoredItem_registerSampleCallback(server, mon);
     else
@@ -413,21 +410,20 @@ void Service_SetMonitoringMode(UA_Server *server, UA_Session *session,
     }
 
     /* Get the subscription */
-    op_sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
-    if(!op_sub) {
+    struct setMonitoringContext smc;
+    smc.sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
+    if(!smc.sub) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return;
     }
 
-    /* Reset the subscription lifetime */
-    op_sub->currentLifetimeCount = 0;
+    smc.sub->currentLifetimeCount = 0; /* Reset the subscription lifetime */
 
-    op_monitoringMode = request->monitoringMode;
+    smc.monitoringMode = request->monitoringMode;
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_SetMonitoringMode,
-                  &request->monitoredItemIdsSize, &UA_TYPES[UA_TYPES_UINT32],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_SetMonitoringMode, &smc,
+                                           &request->monitoredItemIdsSize, &UA_TYPES[UA_TYPES_UINT32],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
 }
 
 /* TODO: Unify with senderror in ua_server_binary.c */
@@ -555,7 +551,7 @@ Service_Publish(UA_Server *server, UA_Session *session,
 }
 
 static void
-Operation_DeleteSubscription(UA_Server *server, UA_Session *session,
+Operation_DeleteSubscription(UA_Server *server, UA_Session *session, void *_,
                              UA_UInt32 *subscriptionId, UA_StatusCode *result) {
     *result = UA_Session_deleteSubscription(server, session, *subscriptionId);
     if(*result == UA_STATUSCODE_GOOD) {
@@ -577,10 +573,9 @@ Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
                          "Processing DeleteSubscriptionsRequest");
 
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_DeleteSubscription,
-                  &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_DeleteSubscription, NULL,
+                                           &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
 
     /* The session has at least one subscription */
     if(LIST_FIRST(&session->serverSubscriptions))
@@ -591,10 +586,9 @@ Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
 }
 
 static void
-Operation_DeleteMonitoredItem(UA_Server *server, UA_Session *session,
-                              UA_UInt32 *monitoredItemId,
-                              UA_StatusCode *result) {
-    *result = UA_Subscription_deleteMonitoredItem(server, op_sub, *monitoredItemId);
+Operation_DeleteMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscription *sub,
+                              UA_UInt32 *monitoredItemId, UA_StatusCode *result) {
+    *result = UA_Subscription_deleteMonitoredItem(server, sub, *monitoredItemId);
 }
 
 void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
@@ -610,20 +604,19 @@ void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
     }
 
     /* Get the subscription */
-    op_sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
-    if(!op_sub) {
+    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
+    if(!sub) {
         response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
         return;
     }
 
     /* Reset the subscription lifetime */
-    op_sub->currentLifetimeCount = 0;
+    sub->currentLifetimeCount = 0;
 
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_DeleteMonitoredItem,
-                  &request->monitoredItemIdsSize, &UA_TYPES[UA_TYPES_UINT32],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_DeleteMonitoredItem, sub,
+                                           &request->monitoredItemIdsSize, &UA_TYPES[UA_TYPES_UINT32],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
 }
 
 void Service_Republish(UA_Server *server, UA_Session *session,

+ 16 - 25
src/server/ua_services_view.c

@@ -292,8 +292,7 @@ Service_Browse_single(UA_Server *server, UA_Session *session,
 }
 
 void Service_Browse(UA_Server *server, UA_Session *session,
-                    const UA_BrowseRequest *request,
-                    UA_BrowseResponse *response) {
+                    const UA_BrowseRequest *request, UA_BrowseResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing BrowseRequest");
 
@@ -329,8 +328,7 @@ void Service_Browse(UA_Server *server, UA_Session *session,
 }
 
 UA_BrowseResult
-UA_Server_browse(UA_Server *server, UA_UInt32 maxrefs,
-                 const UA_BrowseDescription *descr) {
+UA_Server_browse(UA_Server *server, UA_UInt32 maxrefs, const UA_BrowseDescription *descr) {
     UA_BrowseResult result;
     UA_BrowseResult_init(&result);
     Service_Browse_single(server, &adminSession, NULL,
@@ -338,12 +336,9 @@ UA_Server_browse(UA_Server *server, UA_UInt32 maxrefs,
     return result;
 }
 
-/* Thread-local variables to pass additional arguments into the operation */
-static UA_THREAD_LOCAL UA_Boolean op_releaseContinuationPoint;
-
 static void
-Operation_BrowseNext(UA_Server *server, UA_Session *session,
-           const UA_ByteString *continuationPoint, UA_BrowseResult *result) {
+Operation_BrowseNext(UA_Server *server, UA_Session *session, UA_Boolean *releaseContinuationPoints,
+                     const UA_ByteString *continuationPoint, UA_BrowseResult *result) {
     /* Find the continuation point */
     ContinuationPointEntry *cp;
     LIST_FOREACH(cp, &session->continuationPoints, pointers) {
@@ -356,7 +351,7 @@ Operation_BrowseNext(UA_Server *server, UA_Session *session,
     }
 
     /* Do the work */
-    if(!op_releaseContinuationPoint)
+    if(!*releaseContinuationPoints)
         Service_Browse_single(server, session, cp, NULL, 0, result);
     else
         removeCp(cp, session);
@@ -368,14 +363,12 @@ Service_BrowseNext(UA_Server *server, UA_Session *session,
                    UA_BrowseNextResponse *response) {
     UA_LOG_DEBUG_SESSION(server->config.logger, session,
                          "Processing BrowseNextRequest");
-
-    op_releaseContinuationPoint = request->releaseContinuationPoints;
-
+    UA_Boolean releaseContinuationPoints = request->releaseContinuationPoints; /* request is const */
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_BrowseNext,
-                  &request->continuationPointsSize, &UA_TYPES[UA_TYPES_BYTESTRING],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSERESULT]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_BrowseNext,
+                                           &releaseContinuationPoints,
+                                           &request->continuationPointsSize, &UA_TYPES[UA_TYPES_BYTESTRING],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSERESULT]);
 }
 
 UA_BrowseResult
@@ -383,8 +376,7 @@ UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
                      const UA_ByteString *continuationPoint) {
     UA_BrowseResult result;
     UA_BrowseResult_init(&result);
-    op_releaseContinuationPoint = releaseContinuationPoint;
-    Operation_BrowseNext(server, &adminSession,
+    Operation_BrowseNext(server, &adminSession, &releaseContinuationPoint,
                          continuationPoint, &result);
     return result;
 }
@@ -601,7 +593,7 @@ walkBrowsePath(UA_Server *server, UA_Session *session, const UA_BrowsePath *path
 
 static void
 Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session,
-                                       const UA_BrowsePath *path,
+                                       void *context, const UA_BrowsePath *path,
                                        UA_BrowsePathResult *result) {
     if(path->relativePath.elementsSize <= 0) {
         result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
@@ -686,7 +678,7 @@ UA_Server_translateBrowsePathToNodeIds(UA_Server *server,
                                        const UA_BrowsePath *browsePath) {
     UA_BrowsePathResult result;
     UA_BrowsePathResult_init(&result);
-    Operation_TranslateBrowsePathToNodeIds(server, &adminSession, browsePath, &result);
+    Operation_TranslateBrowsePathToNodeIds(server, &adminSession, NULL, browsePath, &result);
     return result;
 }
 
@@ -704,10 +696,9 @@ Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
     }
 
     response->responseHeader.serviceResult = 
-        UA_Server_processServiceOperations(server, session,
-                  (UA_ServiceOperation)Operation_TranslateBrowsePathToNodeIds,
-                  &request->browsePathsSize, &UA_TYPES[UA_TYPES_BROWSEPATH],
-                  &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSEPATHRESULT]);
+        UA_Server_processServiceOperations(server, session, (UA_ServiceOperation)Operation_TranslateBrowsePathToNodeIds,
+                                           NULL, &request->browsePathsSize, &UA_TYPES[UA_TYPES_BROWSEPATH],
+                                           &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSEPATHRESULT]);
 }
 
 void Service_RegisterNodes(UA_Server *server, UA_Session *session,

+ 1 - 0
src/ua_securechannel.h

@@ -19,6 +19,7 @@ extern "C" {
 #define UA_SECURE_CONVERSATION_MESSAGE_HEADER_LENGTH 12
 #define UA_SECURE_MESSAGE_HEADER_LENGTH 24
 
+/* Thread-local variables to force failure modes during testing */
 #ifdef UA_ENABLE_UNIT_TEST_FAILURE_HOOKS
 extern UA_THREAD_LOCAL UA_StatusCode decrypt_verifySignatureFailure;
 extern UA_THREAD_LOCAL UA_StatusCode sendAsym_sendFailure;

+ 3 - 5
src/ua_util.h

@@ -19,9 +19,9 @@ extern "C" {
 
 /* Thread-Local Storage
  * --------------------
- * If thread-local storage is not supported but still detected with the
- * following macros, it can be manually disabled by defining
- * ``UA_NO_THREAD_LOCAL``. This can result in some minor slowdowns. */
+ * Thread-local storage is not required by the main library functionality. It is
+ * only used for some testing strategies. ``UA_THREAD_LOCAL`` is empty if the
+ * feature is not available. */
 
 #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
 # define UA_THREAD_LOCAL _Thread_local /* C11 */
@@ -32,9 +32,7 @@ extern "C" {
 #elif defined(_MSC_VER)
 # define UA_THREAD_LOCAL __declspec(thread) /* MSVC extension */
 #else
-# define UA_NO_THREAD_LOCAL
 # define UA_THREAD_LOCAL
-# warning The compiler does not support thread-local variables
 #endif
 
 /* Integer Shortnames