Kaynağa Gözat

Improve adding new timed work

Julius Pfrommer 10 yıl önce
ebeveyn
işleme
582e042a51
2 değiştirilmiş dosya ile 40 ekleme ve 21 silme
  1. 1 1
      src/server/ua_server.c
  2. 39 20
      src/server/ua_server_worker.c

+ 1 - 1
src/server/ua_server.c

@@ -131,7 +131,7 @@ static void UA_Server_cleanup(UA_Server *server, void *nothing) {
 #define SOFTWARE_VERSION TOSTRING(VERSION)
 #define BUILD_NUMBER "0"
 
-static void getBulidInfo(const UA_Server* server, UA_BuildInfo *buildInfo){
+static void getBulidInfo(const UA_Server* server, UA_BuildInfo *buildInfo) {
     buildInfo->productUri = UA_STRING_ALLOC(PRODUCT_URI);
     buildInfo->manufacturerName = UA_STRING_ALLOC(MANUFACTURER_NAME);
     buildInfo->productName = UA_STRING_ALLOC(PRODUCT_NAME);

+ 39 - 20
src/server/ua_server_worker.c

@@ -135,32 +135,53 @@ static void emptyDispatchQueue(UA_Server *server) {
 /* Timed Work */
 /**************/
 
+/**
+ * The TimedWork structure contains an array of workitems that are either executed at the same time
+ * or in the same repetition inverval. The linked list is sorted, so we can stop traversing when the
+ * first element has nextTime > now.
+ */
 struct TimedWork {
     LIST_ENTRY(TimedWork) pointers;
     UA_DateTime nextTime;
-    UA_UInt32 interval; ///> in ms resolution, 0 means no repetition
+    UA_UInt32 interval; ///> in 100ns resolution, 0 means no repetition
     size_t workSize;
     UA_WorkItem *work;
     UA_Guid workIds[];
 };
 
-/* The item is copied and not freed by this function. The interval is in 100ns (as UA_DateTime) */
+/* Traverse the list until there is a TimedWork to which the item can be added or we reached the
+   end. The item is copied into the TimedWork and not freed by this function. The interval is in
+   100ns resolution */
 static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA_DateTime firstTime,
                                   UA_UInt32 interval, UA_Guid *resultWorkGuid) {
-    struct TimedWork *lastTw = UA_NULL, *matchingTw = UA_NULL;
+    struct TimedWork *matchingTw = UA_NULL; // add the item here
+    struct TimedWork *lastTw = UA_NULL; // if there is no matchingTw, add a new TimedWork after this entry
+    struct TimedWork *tempTw;
+
     /* search for matching entry */
+    tempTw = LIST_FIRST(&server->timedWork);
     if(interval == 0) {
-        LIST_FOREACH(lastTw, &server->timedWork, pointers) {
-            if(lastTw->nextTime == firstTime) {
-                if(lastTw->nextTime == firstTime)
-                    matchingTw = lastTw;
+        /* single execution. the time needs to match */
+        while(tempTw) {
+            if(tempTw->nextTime >= firstTime) {
+                if(tempTw->nextTime == firstTime)
+                    matchingTw = tempTw;
                 break;
             }
+            lastTw = tempTw;
+            tempTw = LIST_NEXT(lastTw, pointers);
         }
     } else {
-        LIST_FOREACH(matchingTw, &server->timedWork, pointers) {
-            if(interval == matchingTw->interval)
+        /* repeated execution. the interval needs to match */
+        while(tempTw) {
+            if(interval == tempTw->interval) {
+                matchingTw = tempTw;
                 break;
+            }
+            if(tempTw->nextTime > firstTime)
+                break;
+            lastTw = tempTw;
+            tempTw = LIST_NEXT(lastTw, pointers);
         }
     }
     
@@ -174,11 +195,8 @@ static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA
         if(matchingTw->pointers.le_prev)
             *matchingTw->pointers.le_prev = matchingTw;
         UA_WorkItem *newItems = UA_realloc(matchingTw->work, sizeof(UA_WorkItem)*(matchingTw->workSize + 1));
-        if(!newItems){
-            UA_free(matchingTw);
+        if(!newItems)
             return UA_STATUSCODE_BADOUTOFMEMORY;
-        }
-
         matchingTw->work = newItems;
     } else {
         /* create a new entry */
@@ -193,21 +211,22 @@ static UA_StatusCode addTimedWork(UA_Server *server, const UA_WorkItem *item, UA
         matchingTw->workSize = 0;
         matchingTw->nextTime = firstTime;
         matchingTw->interval = interval;
+        if(lastTw)
+            LIST_INSERT_AFTER(lastTw, matchingTw, pointers);
+        else
+            LIST_INSERT_HEAD(&server->timedWork, matchingTw, pointers);
     }
+    matchingTw->work[matchingTw->workSize] = *item;
+    matchingTw->workSize++;
+
+    /* create a guid for finding and deleting the timed work later on */
     if(resultWorkGuid) {
         matchingTw->workIds[matchingTw->workSize] = UA_Guid_random(&server->random_seed);
         *resultWorkGuid = matchingTw->workIds[matchingTw->workSize];
     }
-    matchingTw->work[matchingTw->workSize] = *item;
-    matchingTw->workSize++;
-    if(lastTw)
-        LIST_INSERT_AFTER(lastTw, matchingTw, pointers);
-    else
-        LIST_INSERT_HEAD(&server->timedWork, matchingTw, pointers);
     return UA_STATUSCODE_GOOD;
 }
 
-// Currently, these functions need to get the server mutex, but should be sufficiently fast
 UA_StatusCode UA_Server_addTimedWorkItem(UA_Server *server, const UA_WorkItem *work, UA_DateTime executionTime,
                                          UA_Guid *resultWorkGuid) {
     return addTimedWork(server, work, executionTime, 0, resultWorkGuid);