# HG changeset patch # User Edouard Tisserant # Date 1592913021 -7200 # Node ID 5d8a4deacfe1d37f668f0be83406dfc693473b6f # Parent 4d3320fdab1934ba51a2f2b9c4ef8759704fb3cc Modbus add a timer thread, and switch timer to SIGEV_THREAD_ID to follow xenomai posix skin restrictions. diff -r 4d3320fdab19 -r 5d8a4deacfe1 modbus/mb_runtime.c --- a/modbus/mb_runtime.c Fri Jun 19 11:07:25 2020 +0200 +++ b/modbus/mb_runtime.c Tue Jun 23 13:50:21 2020 +0200 @@ -25,6 +25,7 @@ #include #include /* required for memcpy() */ +#include #include #include #include "mb_slave_and_master.h" @@ -470,23 +471,62 @@ * The same callback function is called by the timers of all client nodes. The id of the client node * in question will be passed as a parameter to the call back function. */ -void __client_node_timer_callback_function(union sigval sigev_value) { +void __client_node_timer_callback_function(int client_node_id) { /* signal the client node's condition variable on which the client node's thread should be waiting... */ /* Since the communication cycle is run with the mutex locked, we use trylock() instead of lock() */ - //pthread_mutex_lock (&(client_nodes[sigev_value.sival_int].mutex)); - if (pthread_mutex_trylock (&(client_nodes[sigev_value.sival_int].mutex)) != 0) + if (pthread_mutex_trylock (&(client_nodes[client_node_id].mutex)) != 0) /* we never get to signal the thread for activation. But that is OK. * If it still in the communication cycle (during which the mutex is kept locked) * then that means that the communication cycle is falling behing in the periodic * communication cycle, and we therefore need to skip a period. */ return; - client_nodes[sigev_value.sival_int].execute_req = 1; // tell the thread to execute - client_nodes[sigev_value.sival_int].periodic_act = 1; // tell the thread the activation was done by periodic timer - pthread_cond_signal (&(client_nodes[sigev_value.sival_int].condv)); - pthread_mutex_unlock(&(client_nodes[sigev_value.sival_int].mutex)); -} - + client_nodes[client_node_id].execute_req = 1; // tell the thread to execute + client_nodes[client_node_id].periodic_act = 1; // tell the thread the activation was done by periodic timer + pthread_cond_signal (&(client_nodes[client_node_id].condv)); + pthread_mutex_unlock(&(client_nodes[client_node_id].mutex)); +} + + + +static int stop_mb_client_timer_thread; +static void *__mb_client_timer_thread(void *_index) { + sigset_t set; + int signum = SIGALRM; + int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast) + printf("%%d\n", client_node_id); + /* initialize the timer that will be used to periodically activate the client node */ + { + // start off by reseting the flag that will be set whenever the timer expires + client_nodes[client_node_id].periodic_act = 0; + + struct sigevent evp = {0}; + evp.sigev_notify = SIGEV_THREAD_ID; /* Notification method - call a function in a new thread context */ + evp.sigev_signo = SIGALRM; + evp.sigev_value.sival_int = client_node_id; /* Data passed to function upon notification - used to indentify which client node to activate */ + + if (timer_create(CLOCK_MONOTONIC, &evp, &(client_nodes[client_node_id].timer_id)) < 0) { + fprintf(stderr, "Modbus plugin: Error (%%s) creating timer for modbus client node %%s\n", strerror(errno), client_nodes[client_node_id].location); + return NULL; + } + } + + stop_mb_client_timer_thread = 0; + while(!stop_mb_client_timer_thread) { + if(sigwait (&set, &signum) == -1) + perror ("sigwait"); + if(stop_mb_client_timer_thread) + break; + __client_node_timer_callback_function(client_node_id); + } + + // timer was created, so we try to destroy it! + int res = timer_delete(client_nodes[client_node_id].timer_id); + if (res < 0) + fprintf(stderr, "Modbus plugin: Error destroying timer for modbus client node %%s\n", client_nodes[client_node_id].location); + + return NULL; +} int __cleanup_%(locstr)s (); @@ -581,22 +621,17 @@ client_nodes[index].execute_req = 0; //variable associated with condition variable client_nodes[index].init_state = 3; // we have created the condition variable - /* initialize the timer that will be used to periodically activate the client node */ - { - // start off by reseting the flag that will be set whenever the timer expires - client_nodes[index].periodic_act = 0; - - struct sigevent evp; - evp.sigev_notify = SIGEV_THREAD; /* Notification method - call a function in a new thread context */ - evp.sigev_value.sival_int = index; /* Data passed to function upon notification - used to indentify which client node to activate */ - evp.sigev_notify_function = __client_node_timer_callback_function; /* function to call upon timer expiration */ - evp.sigev_notify_attributes = NULL; /* attributes for new thread in which sigev_notify_function will be called/executed */ - - if (timer_create(CLOCK_MONOTONIC, &evp, &(client_nodes[index].timer_id)) < 0) { - fprintf(stderr, "Modbus plugin: Error creating timer for modbus client node %%s\n", client_nodes[index].location); - goto error_exit; - } - } + /* launch a thread to handle this client node timer */ + { + int res = 0; + pthread_attr_t attr; + res |= pthread_attr_init(&attr); + res |= pthread_create(&(client_nodes[index].timer_thread_id), &attr, &__mb_client_timer_thread, (void *)((char *)NULL + index)); + if (res != 0) { + fprintf(stderr, "Modbus plugin: Error starting timer thread for modbus client node %%s\n", client_nodes[index].location); + goto error_exit; + } + } client_nodes[index].init_state = 4; // we have created the timer /* launch a thread to handle this client node */ @@ -754,10 +789,14 @@ close = 0; if (client_nodes[index].init_state >= 4) { - // timer was created, so we try to destroy it! - close = timer_delete(client_nodes[index].timer_id); + stop_mb_client_timer_thread = 1; + pthread_kill(client_nodes[index].timer_thread_id, SIGALRM); + // thread was launched, so we try to cancel it! + close = pthread_cancel(client_nodes[index].timer_thread_id); + close |= pthread_join (client_nodes[index].timer_thread_id, NULL); if (close < 0) - fprintf(stderr, "Modbus plugin: Error destroying timer for modbus client node %%s\n", client_nodes[index].location); + fprintf(stderr, "Modbus plugin: Error closing timer thread for modbus client node %%s\n", client_nodes[index].location); + } res |= close; diff -r 4d3320fdab19 -r 5d8a4deacfe1 modbus/mb_runtime.h --- a/modbus/mb_runtime.h Fri Jun 19 11:07:25 2020 +0200 +++ b/modbus/mb_runtime.h Tue Jun 23 13:50:21 2020 +0200 @@ -106,6 +106,7 @@ u64 comm_period;// period to use when periodically sending requests to remote server int prev_error; // error code of the last printed error message (0 when no error) pthread_t thread_id; // thread handling all communication for this client node + pthread_t timer_thread_id; // thread handling periodical timer for this client node timer_t timer_id; // timer used to periodically activate this client node's thread pthread_mutex_t mutex; // mutex to be used with the following condition variable pthread_cond_t condv; // used to signal the client thread when to start new modbus transactions