Browse Source

repeated jobs can remove themselves

Julius Pfrommer 8 years ago
parent
commit
dcf1e52d15
4 changed files with 100 additions and 2 deletions
  1. 1 2
      include/ua_server.h
  2. 9 0
      src/server/ua_server_worker.c
  3. 4 0
      tests/CMakeLists.txt
  4. 86 0
      tests/check_server_jobs.c

+ 1 - 2
include/ua_server.h

@@ -192,8 +192,7 @@ UA_StatusCode UA_EXPORT
 UA_Server_addRepeatedJob(UA_Server *server, UA_Job job,
                          UA_UInt32 interval, UA_Guid *jobId);
 
-/* Remove repeated job. The entry will be removed asynchronously during the next
- * iteration of the server main loop.
+/* Remove repeated job.
  *
  * @param server The server object.
  * @param jobId The id of the job that shall be removed.

+ 9 - 0
src/server/ua_server_worker.c

@@ -222,7 +222,16 @@ processRepeatedJobs(UA_Server *server, UA_DateTime current) {
 #ifdef UA_ENABLE_MULTITHREADING
         dispatchJob(server, &rj->job);
 #else
+        struct RepeatedJob **previousNext = rj->next.le_prev;
         processJob(server, &rj->job);
+        /* See if the current job was deleted during processJob. That means the
+           le_next field of the previous repeated job (could also be the list
+           header) does no longer point to the current repeated job */
+        if((void*)*previousNext != (void*)rj) {
+            UA_LOG_WARNING(server->config.logger, UA_LOGCATEGORY_SERVER,
+                         "The current repeated job removed itself");
+            continue;
+        }
 #endif
 
         /* Set the time for the next execution */

+ 4 - 0
tests/CMakeLists.txt

@@ -64,6 +64,10 @@ add_executable(check_session check_session.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_session ${LIBS})
 add_test(session ${CMAKE_CURRENT_BINARY_DIR}/check_session)
 
+add_executable(check_server_jobs check_server_jobs.c $<TARGET_OBJECTS:open62541-object>)
+target_link_libraries(check_server_jobs ${LIBS})
+add_test(check_server_jobs ${CMAKE_CURRENT_BINARY_DIR}/check_server_jobs)
+
 add_executable(check_server_userspace check_server_userspace.c $<TARGET_OBJECTS:open62541-object>)
 target_link_libraries(check_server_userspace ${LIBS})
 add_test(check_server_userspace ${CMAKE_CURRENT_BINARY_DIR}/check_server_userspace)

+ 86 - 0
tests/check_server_jobs.c

@@ -0,0 +1,86 @@
+#include "ua_server.h"
+#include "server/ua_server_internal.h"
+#include "ua_config_standard.h"
+
+#include "check.h"
+#include <unistd.h>
+
+UA_Server *server = NULL;
+
+static void setup(void) {
+    server = UA_Server_new(UA_ServerConfig_standard);
+    UA_Server_run_startup(server);
+}
+
+static void teardown(void) {
+    UA_Server_run_shutdown(server);
+    UA_Server_delete(server);
+}
+
+UA_Boolean *executed;
+
+static void
+dummyJob(UA_Server *server, void *data) {
+    *executed = true;
+}
+
+START_TEST(Server_addRemoveRepeatedJob) {
+    executed = UA_Boolean_new();
+    UA_Guid id;
+    UA_Job rj = (UA_Job){
+        .type = UA_JOBTYPE_METHODCALL,
+        .job.methodCall = {.data = NULL, .method = dummyJob}
+    };
+    UA_Server_addRepeatedJob(server, rj, 10, &id);
+
+    usleep(15*1000);
+    UA_Server_run_iterate(server, false);
+
+    ck_assert_uint_eq(*executed, true);
+
+    UA_Server_removeRepeatedJob(server, id);
+    UA_Boolean_delete(executed);
+}
+END_TEST
+
+UA_Guid *jobId;
+
+static void
+removeItselfJob(UA_Server *server, void *data) {
+    UA_Server_removeRepeatedJob(server, *jobId);
+}
+
+START_TEST(Server_repeatedJobRemoveItself) {
+    jobId = UA_Guid_new();
+    UA_Job rj = (UA_Job){
+        .type = UA_JOBTYPE_METHODCALL,
+        .job.methodCall = {.data = NULL, .method = removeItselfJob}
+    };
+    UA_Server_addRepeatedJob(server, rj, 10, jobId);
+
+    usleep(15*1000);
+    UA_Server_run_iterate(server, false);
+
+    UA_Guid_delete(jobId);
+}
+END_TEST
+
+static Suite* testSuite_Client(void) {
+    Suite *s = suite_create("Server Jobs");
+    TCase *tc_server = tcase_create("Server Repeated Jobs");
+    tcase_add_checked_fixture(tc_server, setup, teardown);
+    tcase_add_test(tc_server, Server_addRemoveRepeatedJob);
+    tcase_add_test(tc_server, Server_repeatedJobRemoveItself);
+    suite_add_tcase(s, tc_server);
+    return s;
+}
+
+int main(void) {
+    Suite *s = testSuite_Client();
+    SRunner *sr = srunner_create(s);
+    srunner_set_fork_status(sr, CK_NOFORK);
+    srunner_run_all(sr,CK_NORMAL);
+    int number_failed = srunner_ntests_failed(sr);
+    srunner_free(sr);
+    return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}