Browse Source

fix timed work, small cosmetic improvements

Julius Pfrommer 10 years ago
parent
commit
233c36ec1a

+ 1 - 1
CMakeLists.txt

@@ -1,5 +1,5 @@
 cmake_minimum_required(VERSION 2.8.8)
 cmake_minimum_required(VERSION 2.8.8)
-# set(CMAKE_VERBOSE_MAKEFILE on)
+# set(CMAKE_VERBOSE_MAKEFILE ON)
 
 
 project(open62541 C)
 project(open62541 C)
 set(open62541_VERSION_MAJOR 0)
 set(open62541_VERSION_MAJOR 0)

+ 3 - 3
examples/networklayer_tcp.c

@@ -377,9 +377,9 @@ static UA_Int32 ServerNetworkLayerTCP_getWork(ServerNetworkLayerTCP *layer, UA_W
                 break;
                 break;
         }
         }
         if(socket_recv(layer->mappings[i].connection, &buf, 0) == UA_STATUSCODE_GOOD) {
         if(socket_recv(layer->mappings[i].connection, &buf, 0) == UA_STATUSCODE_GOOD) {
-            items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
-            items[j].work.binaryNetworkMessage.message = buf;
-            items[j].work.binaryNetworkMessage.connection = layer->mappings[i].connection;
+            items[j].type = UA_WORKITEMTYPE_BINARYMESSAGE;
+            items[j].work.binaryMessage.message = buf;
+            items[j].work.binaryMessage.connection = layer->mappings[i].connection;
             buf.data = NULL;
             buf.data = NULL;
         } else {
         } else {
             items[j].type = UA_WORKITEMTYPE_CLOSECONNECTION;
             items[j].type = UA_WORKITEMTYPE_CLOSECONNECTION;

+ 3 - 3
examples/networklayer_udp.c

@@ -188,9 +188,9 @@ static UA_Int32 ServerNetworkLayerUDP_getWork(ServerNetworkLayerUDP *layer, UA_W
             c->connection.getBuffer = GetMallocedBuffer;
             c->connection.getBuffer = GetMallocedBuffer;
             c->connection.releaseBuffer = ReleaseMallocedBuffer;
             c->connection.releaseBuffer = ReleaseMallocedBuffer;
             c->connection.handle = layer;
             c->connection.handle = layer;
-            items[j].type = UA_WORKITEMTYPE_BINARYNETWORKMESSAGE;
-            items[j].work.binaryNetworkMessage.message = buf;
-            items[j].work.binaryNetworkMessage.connection = (UA_Connection*)c;
+            items[j].type = UA_WORKITEMTYPE_BINARYMESSAGE;
+            items[j].work.binaryMessage.message = buf;
+            items[j].work.binaryMessage.connection = (UA_Connection*)c;
             buf.data = NULL;
             buf.data = NULL;
             j++;
             j++;
         }
         }

+ 1 - 1
examples/server.c

@@ -203,7 +203,7 @@ int main(int argc, char** argv) {
 	// print the status every 2 sec
 	// print the status every 2 sec
 	UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
 	UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
 			.work.methodCall = {.method = printLedStatus, .data = NULL} };
 			.work.methodCall = {.method = printLedStatus, .data = NULL} };
-	UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL);
+	UA_Server_addRepeatedWorkItem(server, &work, 2000, NULL);
 
 
 	// add node with the datetime data source
 	// add node with the datetime data source
 	UA_DataSource dateDataSource = (UA_DataSource)
 	UA_DataSource dateDataSource = (UA_DataSource)

+ 1 - 1
examples/server_simple.c

@@ -71,7 +71,7 @@ int main(int argc, char** argv) {
 
 
     UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
     UA_WorkItem work = {.type = UA_WORKITEMTYPE_METHODCALL,
                         .work.methodCall = {.method = testCallback, .data = NULL} };
                         .work.methodCall = {.method = testCallback, .data = NULL} };
-    UA_Server_addRepeatedWorkItem(server, &work, 20000000, NULL); // call every 2 sec
+    UA_Server_addRepeatedWorkItem(server, &work, 2000, NULL); // call every 2 sec
 
 
 	// add a variable node to the adresspace
 	// add a variable node to the adresspace
     UA_Variant *myIntegerVariant = UA_Variant_new();
     UA_Variant *myIntegerVariant = UA_Variant_new();

+ 3 - 3
include/ua_server.h

@@ -112,7 +112,7 @@ typedef struct UA_WorkItem {
     enum {
     enum {
         UA_WORKITEMTYPE_NOTHING,
         UA_WORKITEMTYPE_NOTHING,
         UA_WORKITEMTYPE_CLOSECONNECTION,
         UA_WORKITEMTYPE_CLOSECONNECTION,
-        UA_WORKITEMTYPE_BINARYNETWORKMESSAGE,
+        UA_WORKITEMTYPE_BINARYMESSAGE,
         UA_WORKITEMTYPE_METHODCALL,
         UA_WORKITEMTYPE_METHODCALL,
         UA_WORKITEMTYPE_DELAYEDMETHODCALL,
         UA_WORKITEMTYPE_DELAYEDMETHODCALL,
     } type;
     } type;
@@ -121,7 +121,7 @@ typedef struct UA_WorkItem {
         struct {
         struct {
             UA_Connection *connection;
             UA_Connection *connection;
             UA_ByteString message;
             UA_ByteString message;
-        } binaryNetworkMessage;
+        } binaryMessage;
         struct {
         struct {
             void *data;
             void *data;
             void (*method)(UA_Server *server, void *data);
             void (*method)(UA_Server *server, void *data);
@@ -156,7 +156,7 @@ UA_Server_addTimedWorkItem(UA_Server *server, const UA_WorkItem *work,
  *        freed but copied to an internal representation.
  *        freed but copied to an internal representation.
  *
  *
  * @param interval The work that is executed repeatedly with the given interval
  * @param interval The work that is executed repeatedly with the given interval
- *        (in 100ns). If work with the same repetition interval already exists,
+ *        (in ms). If work with the same repetition interval already exists,
  *        the first execution might occur sooner.
  *        the first execution might occur sooner.
  *
  *
  * @param resultWorkGuid Upon success, the pointed value is set to the guid of
  * @param resultWorkGuid Upon success, the pointed value is set to the guid of

+ 12 - 14
src/server/ua_server.c

@@ -9,12 +9,10 @@
 
 
 const UA_ServerConfig UA_ServerConfig_standard = {
 const UA_ServerConfig UA_ServerConfig_standard = {
         UA_TRUE,
         UA_TRUE,
-
         UA_TRUE,
         UA_TRUE,
         (char *[]){"user1","user2"},
         (char *[]){"user1","user2"},
         (char *[]){"password","password1"},
         (char *[]){"password","password1"},
         2,
         2,
-
         "urn:unconfigured:open62541:open62541Server",
         "urn:unconfigured:open62541:open62541Server",
         "Unconfigured open62541 application"
         "Unconfigured open62541 application"
 };
 };
@@ -43,14 +41,14 @@ UA_Logger * UA_Server_getLogger(UA_Server *server) {
 
 
 void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer) {
 void UA_Server_addNetworkLayer(UA_Server *server, UA_ServerNetworkLayer networkLayer) {
     UA_ServerNetworkLayer *newlayers =
     UA_ServerNetworkLayer *newlayers =
-        UA_realloc(server->nls, sizeof(UA_ServerNetworkLayer)*(server->nlsSize+1));
+        UA_realloc(server->networkLayers, sizeof(UA_ServerNetworkLayer)*(server->networkLayersSize+1));
     if(!newlayers) {
     if(!newlayers) {
         UA_LOG_ERROR(server->logger, UA_LOGGERCATEGORY_SERVER, "Networklayer added");
         UA_LOG_ERROR(server->logger, UA_LOGGERCATEGORY_SERVER, "Networklayer added");
         return;
         return;
     }
     }
-    server->nls = newlayers;
-    server->nls[server->nlsSize] = networkLayer;
-    server->nlsSize++;
+    server->networkLayers = newlayers;
+    server->networkLayers[server->networkLayersSize] = networkLayer;
+    server->networkLayersSize++;
 
 
     if(networkLayer.discoveryUrl){
     if(networkLayer.discoveryUrl){
         if(server->description.discoveryUrlsSize < 0)
         if(server->description.discoveryUrlsSize < 0)
@@ -104,10 +102,10 @@ void UA_Server_delete(UA_Server *server) {
                     server->endpointDescriptionsSize);
                     server->endpointDescriptionsSize);
 
 
     // Delete the network layers
     // Delete the network layers
-    for(UA_Int32 i = 0; i < server->nlsSize; i++) {
-        server->nls[i].free(server->nls[i].nlHandle);
+    for(size_t i = 0; i < server->networkLayersSize; i++) {
+        server->networkLayers[i].free(server->networkLayers[i].nlHandle);
     }
     }
-    UA_free(server->nls);
+    UA_free(server->networkLayers);
 
 
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
     pthread_cond_destroy(&server->dispatchQueue_condition); // so the workers don't spin if the queue is empty
     pthread_cond_destroy(&server->dispatchQueue_condition); // so the workers don't spin if the queue is empty
@@ -308,8 +306,8 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
     server->random_seed = (UA_UInt32)UA_DateTime_now();
     server->random_seed = (UA_UInt32)UA_DateTime_now();
 
 
     // networklayers
     // networklayers
-    server->nls = UA_NULL;
-    server->nlsSize = 0;
+    server->networkLayers = UA_NULL;
+    server->networkLayersSize = 0;
 
 
     UA_ByteString_init(&server->serverCertificate);
     UA_ByteString_init(&server->serverCertificate);
 
 
@@ -387,9 +385,9 @@ UA_Server * UA_Server_new(UA_ServerConfig config) {
 
 
     server->nodestore = UA_NodeStore_new();
     server->nodestore = UA_NodeStore_new();
 
 
-    /* UA_WorkItem cleanup = {.type = UA_WORKITEMTYPE_METHODCALL, */
-    /*                        .work.methodCall = {.method = UA_Server_cleanup, .data = NULL} }; */
-    /* UA_Server_addRepeatedWorkItem(server, &cleanup, 100000, NULL); */
+    UA_WorkItem cleanup = {.type = UA_WORKITEMTYPE_METHODCALL,
+                           .work.methodCall = {.method = UA_Server_cleanup, .data = NULL} };
+    UA_Server_addRepeatedWorkItem(server, &cleanup, 10000, NULL);
 
 
     /**********************/
     /**********************/
     /* Server Information */
     /* Server Information */

+ 1 - 1
src/server/ua_server_addressspace.c

@@ -185,7 +185,7 @@ UA_Server_addReferenceWithSession(UA_Server *server, UA_Session *session, const
     // Is this for an external nodestore?
     // Is this for an external nodestore?
     UA_ExternalNodeStore *ensFirst = UA_NULL;
     UA_ExternalNodeStore *ensFirst = UA_NULL;
     UA_ExternalNodeStore *ensSecond = UA_NULL;
     UA_ExternalNodeStore *ensSecond = UA_NULL;
-    for(UA_Int32 j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
+    for(size_t j = 0;j<server->externalNamespacesSize && (!ensFirst || !ensSecond);j++) {
         if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index)
         if(item->sourceNodeId.namespaceIndex == server->externalNamespaces[j].index)
             ensFirst = &server->externalNamespaces[j].externalNodeStore;
             ensFirst = &server->externalNamespaces[j].externalNodeStore;
         if(item->targetNodeId.nodeId.namespaceIndex == server->externalNamespaces[j].index)
         if(item->targetNodeId.nodeId.namespaceIndex == server->externalNamespaces[j].index)

+ 21 - 20
src/server/ua_server_internal.h

@@ -20,52 +20,53 @@ typedef struct UA_ExternalNamespace {
 } UA_ExternalNamespace;
 } UA_ExternalNamespace;
 
 
 // forward declarations
 // forward declarations
-struct UA_TimedWork;
-typedef struct UA_TimedWork UA_TimedWork;
+struct TimedWork;
 
 
-struct UA_DelayedWork;
-typedef struct UA_DelayedWork UA_DelayedWork;
+struct DelayedWork;
 
 
 struct UA_Server {
 struct UA_Server {
+    /* Config */
+    UA_ServerConfig config;
+    UA_Logger logger;
+    UA_UInt32 random_seed;
+
+    /* Meta */
+    UA_DateTime startTime;
+    UA_DateTime buildDate;
     UA_ApplicationDescription description;
     UA_ApplicationDescription description;
     UA_Int32 endpointDescriptionsSize;
     UA_Int32 endpointDescriptionsSize;
     UA_EndpointDescription *endpointDescriptions;
     UA_EndpointDescription *endpointDescriptions;
 
 
+    /* Communication */
+    size_t networkLayersSize;
+    UA_ServerNetworkLayer *networkLayers;
+
+    /* Security */
     UA_ByteString serverCertificate;
     UA_ByteString serverCertificate;
     UA_SecureChannelManager secureChannelManager;
     UA_SecureChannelManager secureChannelManager;
     UA_SessionManager sessionManager;
     UA_SessionManager sessionManager;
-    UA_Logger logger;
 
 
+    /* Address Space */
     UA_NodeStore *nodestore;
     UA_NodeStore *nodestore;
-    UA_Int32 namespacesSize;
+    size_t namespacesSize;
     UA_String *namespaces;
     UA_String *namespaces;
-    UA_Int32 externalNamespacesSize;
+    size_t externalNamespacesSize;
     UA_ExternalNamespace *externalNamespaces;
     UA_ExternalNamespace *externalNamespaces;
 
 
-    UA_Int32 nlsSize;
-    UA_ServerNetworkLayer *nls;
-
-    UA_UInt32 random_seed;
+    /* Workload Management */
+    LIST_HEAD(TimedWorkList, TimedWork) timedWork;
 
 
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING
     UA_Boolean *running;
     UA_Boolean *running;
     UA_UInt16 nThreads;
     UA_UInt16 nThreads;
     UA_UInt32 **workerCounters;
     UA_UInt32 **workerCounters;
-    UA_DelayedWork *delayedWork;
+    struct DelayedWork *delayedWork;
 
 
     // worker threads wait on the queue
     // worker threads wait on the queue
 	struct cds_wfcq_head dispatchQueue_head;
 	struct cds_wfcq_head dispatchQueue_head;
 	struct cds_wfcq_tail dispatchQueue_tail;
 	struct cds_wfcq_tail dispatchQueue_tail;
     pthread_cond_t dispatchQueue_condition; // so the workers don't spin if the queue is empty
     pthread_cond_t dispatchQueue_condition; // so the workers don't spin if the queue is empty
 #endif
 #endif
-
-    LIST_HEAD(UA_TimedWorkList, UA_TimedWork) timedWork;
-
-    UA_DateTime startTime;
-    UA_DateTime buildDate;
-
-    /* Config */
-    UA_ServerConfig config;
 };
 };
 
 
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *msg);
 void UA_Server_processBinaryMessage(UA_Server *server, UA_Connection *connection, UA_ByteString *msg);

+ 90 - 105
src/server/ua_server_worker.c

@@ -6,10 +6,8 @@
  *
  *
  * 1. Ordinary WorkItems (that are dispatched to worker threads if
  * 1. Ordinary WorkItems (that are dispatched to worker threads if
  *    multithreading is activated)
  *    multithreading is activated)
- *
  * 2. Timed work that is executed at a precise date (with an optional repetition
  * 2. Timed work that is executed at a precise date (with an optional repetition
  *    interval)
  *    interval)
- *
  * 3. Delayed work that is executed at a later time when it is guaranteed that
  * 3. Delayed work that is executed at a later time when it is guaranteed that
  *    all previous work has actually finished (only for multithreading)
  *    all previous work has actually finished (only for multithreading)
  */
  */
@@ -21,18 +19,20 @@ static void processWork(UA_Server *server, UA_WorkItem *work, UA_Int32 workSize)
     for(UA_Int32 i = 0; i < workSize; i++) {
     for(UA_Int32 i = 0; i < workSize; i++) {
         UA_WorkItem *item = &work[i];
         UA_WorkItem *item = &work[i];
         switch(item->type) {
         switch(item->type) {
-        case UA_WORKITEMTYPE_BINARYNETWORKMESSAGE:
-            UA_Server_processBinaryMessage(server, item->work.binaryNetworkMessage.connection,
-                                           &item->work.binaryNetworkMessage.message);
-            item->work.binaryNetworkMessage.connection->releaseBuffer(item->work.binaryNetworkMessage.connection,
-                                                                      &item->work.binaryNetworkMessage.message);
+        case UA_WORKITEMTYPE_BINARYMESSAGE:
+            UA_Server_processBinaryMessage(server, item->work.binaryMessage.connection,
+                                           &item->work.binaryMessage.message);
+            item->work.binaryMessage.connection->releaseBuffer(item->work.binaryMessage.connection,
+                                                               &item->work.binaryMessage.message);
+            break;
+        case UA_WORKITEMTYPE_CLOSECONNECTION:
+            UA_Connection_detachSecureChannel(item->work.closeConnection);
+            item->work.closeConnection->close(item->work.closeConnection);
             break;
             break;
-
         case UA_WORKITEMTYPE_METHODCALL:
         case UA_WORKITEMTYPE_METHODCALL:
         case UA_WORKITEMTYPE_DELAYEDMETHODCALL:
         case UA_WORKITEMTYPE_DELAYEDMETHODCALL:
             item->work.methodCall.method(server, item->work.methodCall.data);
             item->work.methodCall.method(server, item->work.methodCall.data);
             break;
             break;
-
         default:
         default:
             break;
             break;
         }
         }
@@ -135,76 +135,67 @@ static void emptyDispatchQueue(UA_Server *server) {
 /* Timed Work */
 /* Timed Work */
 /**************/
 /**************/
 
 
-struct UA_TimedWork {
-    LIST_ENTRY(UA_TimedWork) pointers;
-    UA_UInt16 workSize;
-    UA_WorkItem *work;
-    UA_Guid *workIds;
-    UA_DateTime time;
-    UA_UInt32 repetitionInterval; // in 100ns resolution, 0 means no repetition
+struct TimedWork {
+    LIST_ENTRY(TimedWork) pointers;
+    UA_DateTime nextTime;
+    UA_UInt32 interval; ///> in ms resolution, 0 means no repetition
+    size_t workSize;
+    struct {
+        UA_WorkItem work;
+        UA_Guid workId;
+    } work[];
 };
 };
 
 
 /* The item is copied and not freed by this function. */
 /* The item is copied and not freed by this function. */
 static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA_DateTime firstTime,
 static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA_DateTime firstTime,
                                   UA_UInt32 repetitionInterval, UA_Guid *resultWorkGuid) {
                                   UA_UInt32 repetitionInterval, UA_Guid *resultWorkGuid) {
-    UA_TimedWork *tw, *lastTw = UA_NULL;
-
-    // search for matching entry
-    LIST_FOREACH(tw, &server->timedWork, pointers) {
-        if(tw->repetitionInterval == repetitionInterval &&
-           (repetitionInterval > 0 || tw->time == firstTime))
-            break; // found a matching entry
-        lastTw = tw;
-        if(tw->time > firstTime) {
-            tw = UA_NULL; // not matchin entry exists
-            break;
+    struct TimedWork *lastTw = UA_NULL, *matchingTw = UA_NULL;
+
+    /* search for matching entry */
+    if(repetitionInterval == 0) {
+        LIST_FOREACH(lastTw, &server->timedWork, pointers) {
+            if(lastTw->nextTime == firstTime) {
+                if(lastTw->nextTime == firstTime)
+                    matchingTw = lastTw;
+                break;
+            }
+        }
+    } else {
+        LIST_FOREACH(matchingTw, &server->timedWork, pointers) {
+            if(repetitionInterval == matchingTw->interval)
+                break;
         }
         }
     }
     }
     
     
-    if(tw) {
-        // append to matching entry
-        tw->workSize++;
-        UA_WorkItem *biggerWorkArray = UA_realloc(tw->work, sizeof(UA_WorkItem)*tw->workSize);
-        if(!biggerWorkArray)
+    struct TimedWork *newWork;
+    if(matchingTw) {
+        /* append to matching entry */
+        newWork = UA_realloc(matchingTw, sizeof(struct TimedWork) + (sizeof(UA_WorkItem)*matchingTw->workSize + 1));
+        if(!newWork)
             return UA_STATUSCODE_BADOUTOFMEMORY;
             return UA_STATUSCODE_BADOUTOFMEMORY;
-        tw->work = biggerWorkArray;
-        UA_Guid *biggerWorkIds = UA_realloc(tw->workIds, sizeof(UA_Guid)*tw->workSize);
-        if(!biggerWorkIds)
+        if(newWork->pointers.le_next)
+            newWork->pointers.le_next->pointers.le_prev = &newWork->pointers.le_next;
+        if(newWork->pointers.le_prev)
+            *newWork->pointers.le_prev = newWork;
+    } else {
+        /* create a new entry */
+        newWork = UA_malloc(sizeof(struct TimedWork) + sizeof(UA_WorkItem));
+        if(!newWork)
             return UA_STATUSCODE_BADOUTOFMEMORY;
             return UA_STATUSCODE_BADOUTOFMEMORY;
-        tw->workIds = biggerWorkIds;
-        tw->work[tw->workSize-1] = *item;
-        tw->workIds[tw->workSize-1] = UA_Guid_random(&server->random_seed);
-        if(resultWorkGuid)
-            *resultWorkGuid = tw->workIds[tw->workSize-1];
-        return UA_STATUSCODE_GOOD;
-    }
-
-    // create a new entry
-    if(!(tw = UA_malloc(sizeof(UA_TimedWork))))
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    if(!(tw->work = UA_malloc(sizeof(UA_WorkItem)))) {
-        UA_free(tw);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+        newWork->workSize = 0;
+        newWork->nextTime = firstTime;
+        newWork->interval = repetitionInterval;
+        if(lastTw)
+            LIST_INSERT_AFTER(lastTw, newWork, pointers);
+        else
+            LIST_INSERT_HEAD(&server->timedWork, newWork, pointers);
     }
     }
-    if(!(tw->workIds = UA_malloc(sizeof(UA_Guid)))) {
-        UA_free(tw->work);
-        UA_free(tw);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
+    newWork->work[newWork->workSize].work = *item;
+    if(resultWorkGuid) {
+        newWork->work[newWork->workSize].workId = UA_Guid_random(&server->random_seed);
+        *resultWorkGuid = newWork->work[matchingTw->workSize - 1].workId;
     }
     }
-
-    tw->workSize = 1;
-    tw->time = firstTime;
-    tw->repetitionInterval = repetitionInterval;
-    tw->work[0] = *item;
-    tw->workIds[0] = UA_Guid_random(&server->random_seed);
-    if(lastTw)
-        LIST_INSERT_AFTER(lastTw, tw, pointers);
-    else
-        LIST_INSERT_HEAD(&server->timedWork, tw, pointers);
-
-    if(resultWorkGuid)
-        *resultWorkGuid = tw->workIds[0];
-
+    newWork->workSize++;
     return UA_STATUSCODE_GOOD;
     return UA_STATUSCODE_GOOD;
 }
 }
 
 
@@ -216,18 +207,18 @@ UA_StatusCode UA_Server_addTimedWorkItem(UA_Server *server, const UA_WorkItem *w
 
 
 UA_StatusCode UA_Server_addRepeatedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_UInt32 interval,
 UA_StatusCode UA_Server_addRepeatedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_UInt32 interval,
                                             UA_Guid *resultWorkGuid) {
                                             UA_Guid *resultWorkGuid) {
-    return addTimedWork(server, work, UA_DateTime_now() + interval, interval, resultWorkGuid);
+    return addTimedWork(server, work, UA_DateTime_now() + interval * 1000, interval * 1000, resultWorkGuid);
 }
 }
 
 
 /** Dispatches timed work, returns the timeout until the next timed work in ms */
 /** Dispatches timed work, returns the timeout until the next timed work in ms */
 static UA_UInt16 processTimedWork(UA_Server *server) {
 static UA_UInt16 processTimedWork(UA_Server *server) {
     UA_DateTime current = UA_DateTime_now();
     UA_DateTime current = UA_DateTime_now();
-    UA_TimedWork *next = LIST_FIRST(&server->timedWork);
-    UA_TimedWork *tw = UA_NULL;
+    struct TimedWork *next = LIST_FIRST(&server->timedWork);
+    struct TimedWork *tw = UA_NULL;
 
 
     while(next) {
     while(next) {
         tw = next;
         tw = next;
-        if(tw->time > current)
+        if(tw->nextTime > current)
             break;
             break;
         next = LIST_NEXT(tw, pointers);
         next = LIST_NEXT(tw, pointers);
 
 
@@ -239,9 +230,9 @@ static UA_UInt16 processTimedWork(UA_Server *server) {
             dispatchWork(server, tw->workSize, workCopy); // frees the work pointer
             dispatchWork(server, tw->workSize, workCopy); // frees the work pointer
             tw->time += tw->repetitionInterval;
             tw->time += tw->repetitionInterval;
 
 
-            UA_TimedWork *prevTw = tw; // after which tw do we insert?
+            struct TimedWork *prevTw = tw; // after which tw do we insert?
             while(UA_TRUE) {
             while(UA_TRUE) {
-                UA_TimedWork *n = LIST_NEXT(prevTw, pointers);
+                struct TimedWork *n = LIST_NEXT(prevTw, pointers);
                 if(!n || n->time > tw->time)
                 if(!n || n->time > tw->time)
                     break;
                     break;
                 prevTw = n;
                 prevTw = n;
@@ -261,12 +252,12 @@ static UA_UInt16 processTimedWork(UA_Server *server) {
         processWork(server, tw->work, tw->workSize); // does not free the work
         processWork(server, tw->work, tw->workSize); // does not free the work
 
 
         // 2) If the work is repeated, add it back into the list. Otherwise remove it.
         // 2) If the work is repeated, add it back into the list. Otherwise remove it.
-        if(tw->repetitionInterval > 0) {
-            tw->time += tw->repetitionInterval;
-            UA_TimedWork *prevTw = tw;
+        if(tw->interval > 0) {
+            tw->nextTime += tw->interval * 10;
+            struct TimedWork *prevTw = tw;
             while(UA_TRUE) {
             while(UA_TRUE) {
-                UA_TimedWork *n = LIST_NEXT(prevTw, pointers);
-                if(!n || n->time > tw->time)
+                struct TimedWork *n = LIST_NEXT(prevTw, pointers);
+                if(!n || n->nextTime > tw->nextTime)
                     break;
                     break;
                 prevTw = n;
                 prevTw = n;
             }
             }
@@ -276,35 +267,29 @@ static UA_UInt16 processTimedWork(UA_Server *server) {
             }
             }
         } else {
         } else {
             LIST_REMOVE(tw, pointers);
             LIST_REMOVE(tw, pointers);
-            UA_free(tw->work);
-            UA_free(tw->workIds);
             UA_free(tw);
             UA_free(tw);
         }
         }
 #endif
 #endif
     }
     }
 
 
     // check if the next timed work is sooner than the usual timeout
     // check if the next timed work is sooner than the usual timeout
-    UA_TimedWork *first = LIST_FIRST(&server->timedWork);
-    UA_Int32 timeout = MAXTIMEOUT;
+    struct TimedWork *first = LIST_FIRST(&server->timedWork);
+    UA_UInt16 timeout = MAXTIMEOUT;
     if(first) {
     if(first) {
-        timeout = (first->time - current)/10;
+        timeout = (first->nextTime - current)/10000;
         if(timeout > MAXTIMEOUT)
         if(timeout > MAXTIMEOUT)
             return MAXTIMEOUT;
             return MAXTIMEOUT;
-        if(timeout < 0)
-            return 0;
     }
     }
     return timeout;
     return timeout;
 }
 }
 
 
 void UA_Server_deleteTimedWork(UA_Server *server) {
 void UA_Server_deleteTimedWork(UA_Server *server) {
-    UA_TimedWork *current;
-    UA_TimedWork *next = LIST_FIRST(&server->timedWork);
+    struct TimedWork *current;
+    struct TimedWork *next = LIST_FIRST(&server->timedWork);
     while(next) {
     while(next) {
         current = next;
         current = next;
         next = LIST_NEXT(current, pointers);
         next = LIST_NEXT(current, pointers);
         LIST_REMOVE(current, pointers);
         LIST_REMOVE(current, pointers);
-        UA_free(current->work);
-        UA_free(current->workIds);
         UA_free(current);
         UA_free(current);
     }
     }
 }
 }
@@ -317,15 +302,15 @@ void UA_Server_deleteTimedWork(UA_Server *server) {
 
 
 #define DELAYEDWORKSIZE 100 // Collect delayed work until we have DELAYEDWORKSIZE items
 #define DELAYEDWORKSIZE 100 // Collect delayed work until we have DELAYEDWORKSIZE items
 
 
-struct UA_DelayedWork {
-    UA_DelayedWork *next;
+struct DelayedWork {
+    struct DelayedWork *next;
     UA_UInt32 *workerCounters; // initially UA_NULL until a workitem gets the counters
     UA_UInt32 *workerCounters; // initially UA_NULL until a workitem gets the counters
     UA_UInt32 workItemsCount; // the size of the array is DELAYEDWORKSIZE, the count may be less
     UA_UInt32 workItemsCount; // the size of the array is DELAYEDWORKSIZE, the count may be less
     UA_WorkItem *workItems; // when it runs full, a new delayedWork entry is created
     UA_WorkItem *workItems; // when it runs full, a new delayedWork entry is created
 };
 };
 
 
 // Dispatched as a methodcall-WorkItem when the delayedwork is added
 // Dispatched as a methodcall-WorkItem when the delayedwork is added
-static void getCounters(UA_Server *server, UA_DelayedWork *delayed) {
+static void getCounters(UA_Server *server, DelayedWork *delayed) {
     UA_UInt32 *counters = UA_malloc(server->nThreads * sizeof(UA_UInt32));
     UA_UInt32 *counters = UA_malloc(server->nThreads * sizeof(UA_UInt32));
     for(UA_UInt16 i = 0;i<server->nThreads;i++)
     for(UA_UInt16 i = 0;i<server->nThreads;i++)
         counters[i] = *server->workerCounters[i];
         counters[i] = *server->workerCounters[i];
@@ -336,9 +321,9 @@ static void getCounters(UA_Server *server, UA_DelayedWork *delayed) {
 // server->delayedWork. processDelayedWorkQueue modifies the "next" (after the
 // server->delayedWork. processDelayedWorkQueue modifies the "next" (after the
 // head).
 // head).
 static void addDelayedWork(UA_Server *server, UA_WorkItem work) {
 static void addDelayedWork(UA_Server *server, UA_WorkItem work) {
-    UA_DelayedWork *dw = server->delayedWork;
+    struct DelayedWork *dw = server->delayedWork;
     if(!dw || dw->workItemsCount >= DELAYEDWORKSIZE) {
     if(!dw || dw->workItemsCount >= DELAYEDWORKSIZE) {
-        UA_DelayedWork *newwork = UA_malloc(sizeof(UA_DelayedWork));
+        struct DelayedWork *newwork = UA_malloc(sizeof(DelayedWork));
         newwork->workItems = UA_malloc(sizeof(UA_WorkItem)*DELAYEDWORKSIZE);
         newwork->workItems = UA_malloc(sizeof(UA_WorkItem)*DELAYEDWORKSIZE);
         newwork->workItemsCount = 0;
         newwork->workItemsCount = 0;
         newwork->workerCounters = UA_NULL;
         newwork->workerCounters = UA_NULL;
@@ -361,10 +346,10 @@ static void addDelayedWork(UA_Server *server, UA_WorkItem work) {
 }
 }
 
 
 static void processDelayedWork(UA_Server *server) {
 static void processDelayedWork(UA_Server *server) {
-    UA_DelayedWork *dw = server->delayedWork;
+    struct DelayedWork *dw = server->delayedWork;
     while(dw) {
     while(dw) {
         processWork(server, dw->workItems, dw->workItemsCount);
         processWork(server, dw->workItems, dw->workItemsCount);
-        UA_DelayedWork *next = dw->next;
+        struct DelayedWork *next = dw->next;
         UA_free(dw->workerCounters);
         UA_free(dw->workerCounters);
         UA_free(dw->workItems);
         UA_free(dw->workItems);
         UA_free(dw);
         UA_free(dw);
@@ -374,9 +359,9 @@ static void processDelayedWork(UA_Server *server) {
 
 
 // Execute this every N seconds (repeated work) to execute delayed work that is ready
 // Execute this every N seconds (repeated work) to execute delayed work that is ready
 static void dispatchDelayedWork(UA_Server *server, void *data /* not used, but needed for the signature*/) {
 static void dispatchDelayedWork(UA_Server *server, void *data /* not used, but needed for the signature*/) {
-    UA_DelayedWork *dw = UA_NULL;
-    UA_DelayedWork *readydw = UA_NULL;
-    UA_DelayedWork *beforedw = server->delayedWork;
+    struct DelayedWork *dw = UA_NULL;
+    struct DelayedWork *readydw = UA_NULL;
+    struct DelayedWork *beforedw = server->delayedWork;
 
 
     // start at the second...
     // start at the second...
     if(beforedw)
     if(beforedw)
@@ -444,8 +429,8 @@ UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *r
 #endif
 #endif
 
 
     // 2) Start the networklayers
     // 2) Start the networklayers
-    for(UA_Int32 i=0;i<server->nlsSize;i++)
-        server->nls[i].start(server->nls[i].nlHandle, &server->logger);
+    for(size_t i = 0; i <server->networkLayersSize; i++)
+        server->networkLayers[i].start(server->networkLayers[i].nlHandle, &server->logger);
 
 
     //3) The loop
     //3) The loop
     while(1) {
     while(1) {
@@ -453,17 +438,17 @@ UA_StatusCode UA_Server_run(UA_Server *server, UA_UInt16 nThreads, UA_Boolean *r
         UA_UInt16 timeout = processTimedWork(server);
         UA_UInt16 timeout = processTimedWork(server);
 
 
         // 3.2) Get work from the networklayer and dispatch it
         // 3.2) Get work from the networklayer and dispatch it
-        for(UA_Int32 i=0;i<server->nlsSize;i++) {
-            UA_ServerNetworkLayer *nl = &server->nls[i];
+        for(size_t i = 0; i < server->networkLayersSize; i++) {
+            UA_ServerNetworkLayer *nl = &server->networkLayers[i];
             UA_WorkItem *work;
             UA_WorkItem *work;
             UA_Int32 workSize;
             UA_Int32 workSize;
             if(*running) {
             if(*running) {
-            	if(i == server->nlsSize-1)
+            	if(i == server->networkLayersSize-1)
             		workSize = nl->getWork(nl->nlHandle, &work, timeout);
             		workSize = nl->getWork(nl->nlHandle, &work, timeout);
             	else
             	else
             		workSize = nl->getWork(nl->nlHandle, &work, 0);
             		workSize = nl->getWork(nl->nlHandle, &work, 0);
             } else {
             } else {
-                workSize = server->nls[i].stop(nl->nlHandle, &work);
+                workSize = server->networkLayers[i].stop(nl->nlHandle, &work);
             }
             }
 
 
 #ifdef UA_MULTITHREADING
 #ifdef UA_MULTITHREADING

+ 3 - 3
src/server/ua_services_attribute.c

@@ -371,7 +371,7 @@ void Service_Read(UA_Server *server, UA_Session *session, const UA_ReadRequest *
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
-    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
+    for(size_t j = 0;j<server->externalNamespacesSize;j++) {
         size_t indexSize = 0;
         size_t indexSize = 0;
         for(size_t i = 0;i < size;i++) {
         for(size_t i = 0;i < size;i++) {
             if(request->nodesToRead[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
             if(request->nodesToRead[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
@@ -589,9 +589,9 @@ void Service_Write(UA_Server *server, UA_Session *session,
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToWriteSize);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * request->nodesToWriteSize);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToWriteSize);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean)*request->nodesToWriteSize);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToWriteSize);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * request->nodesToWriteSize);
-    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
+    for(size_t j = 0; j < server->externalNamespacesSize; j++) {
         UA_UInt32 indexSize = 0;
         UA_UInt32 indexSize = 0;
-        for(UA_Int32 i = 0;i < request->nodesToWriteSize;i++) {
+        for(UA_Int32 i = 0; i < request->nodesToWriteSize; i++) {
             if(request->nodesToWrite[i].nodeId.namespaceIndex !=
             if(request->nodesToWrite[i].nodeId.namespaceIndex !=
                server->externalNamespaces[j].index)
                server->externalNamespaces[j].index)
                 continue;
                 continue;

+ 7 - 7
src/server/ua_services_nodemanagement.c

@@ -247,7 +247,7 @@ void Service_AddNodes(UA_Server *server, UA_Session *session, const UA_AddNodesR
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
-    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
+    for(size_t j = 0; j <server->externalNamespacesSize; j++) {
         size_t indexSize = 0;
         size_t indexSize = 0;
         for(size_t i = 0;i < size;i++) {
         for(size_t i = 0;i < size;i++) {
             if(request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex !=
             if(request->nodesToAdd[i].requestedNewNodeId.nodeId.namespaceIndex !=
@@ -291,21 +291,21 @@ void Service_AddReferences(UA_Server *server, UA_Session *session, const UA_AddR
 	UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
 	UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
 	UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
 	UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
 	UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
 	UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
-	for(UA_Int32 j = 0; j < server->externalNamespacesSize; j++) {
-		size_t indexSize = 0;
+	for(size_t j = 0; j < server->externalNamespacesSize; j++) {
+		size_t indicesSize = 0;
 		for(size_t i = 0;i < size;i++) {
 		for(size_t i = 0;i < size;i++) {
 			if(request->referencesToAdd[i].sourceNodeId.namespaceIndex
 			if(request->referencesToAdd[i].sourceNodeId.namespaceIndex
 					!= server->externalNamespaces[j].index)
 					!= server->externalNamespaces[j].index)
 				continue;
 				continue;
 			isExternal[i] = UA_TRUE;
 			isExternal[i] = UA_TRUE;
-			indices[indexSize] = i;
-			indexSize++;
+			indices[indicesSize] = i;
+			indicesSize++;
 		}
 		}
-		if (indexSize == 0)
+		if (indicesSize == 0)
 			continue;
 			continue;
 		UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
 		UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
 		ens->addReferences(ens->ensHandle, &request->requestHeader, request->referencesToAdd,
 		ens->addReferences(ens->ensHandle, &request->requestHeader, request->referencesToAdd,
-                           indices, indexSize, response->results, response->diagnosticInfos);
+                           indices, indicesSize, response->results, response->diagnosticInfos);
 	}
 	}
 	/* ### End External Namespaces */
 	/* ### End External Namespaces */
 
 

+ 2 - 4
src/server/ua_services_view.c

@@ -288,7 +288,7 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
-    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
+    for(size_t j = 0; j < server->externalNamespacesSize; j++) {
         size_t indexSize = 0;
         size_t indexSize = 0;
         for(size_t i = 0;i < size;i++) {
         for(size_t i = 0;i < size;i++) {
             if(request->nodesToBrowse[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
             if(request->nodesToBrowse[i].nodeId.namespaceIndex != server->externalNamespaces[j].index)
@@ -299,7 +299,6 @@ void Service_Browse(UA_Server *server, UA_Session *session, const UA_BrowseReque
         }
         }
         if(indexSize == 0)
         if(indexSize == 0)
             continue;
             continue;
-
         UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
         UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
         ens->browseNodes(ens->ensHandle, &request->requestHeader, request->nodesToBrowse, indices, indexSize,
         ens->browseNodes(ens->ensHandle, &request->requestHeader, request->nodesToBrowse, indices, indexSize,
                          request->requestedMaxReferencesPerNode, response->results, response->diagnosticInfos);
                          request->requestedMaxReferencesPerNode, response->results, response->diagnosticInfos);
@@ -498,7 +497,7 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_Boolean *isExternal = UA_alloca(sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_memset(isExternal, UA_FALSE, sizeof(UA_Boolean) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
     UA_UInt32 *indices = UA_alloca(sizeof(UA_UInt32) * size);
-    for(UA_Int32 j = 0;j<server->externalNamespacesSize;j++) {
+    for(size_t j = 0; j < server->externalNamespacesSize; j++) {
     	size_t indexSize = 0;
     	size_t indexSize = 0;
     	for(size_t i = 0;i < size;i++) {
     	for(size_t i = 0;i < size;i++) {
     		if(request->browsePaths[i].startingNode.namespaceIndex != server->externalNamespaces[j].index)
     		if(request->browsePaths[i].startingNode.namespaceIndex != server->externalNamespaces[j].index)
@@ -509,7 +508,6 @@ void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *sessio
     	}
     	}
     	if(indexSize == 0)
     	if(indexSize == 0)
     		continue;
     		continue;
-
     	UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
     	UA_ExternalNodeStore *ens = &server->externalNamespaces[j].externalNodeStore;
     	ens->translateBrowsePathsToNodeIds(ens->ensHandle, &request->requestHeader, request->browsePaths,
     	ens->translateBrowsePathsToNodeIds(ens->ensHandle, &request->requestHeader, request->browsePaths,
     			indices, indexSize, response->results, response->diagnosticInfos);
     			indices, indexSize, response->results, response->diagnosticInfos);