468 * condition variable. |
469 * condition variable. |
469 * |
470 * |
470 * The same callback function is called by the timers of all client nodes. The id of the client node |
471 * The same callback function is called by the timers of all client nodes. The id of the client node |
471 * in question will be passed as a parameter to the call back function. |
472 * in question will be passed as a parameter to the call back function. |
472 */ |
473 */ |
473 void __client_node_timer_callback_function(union sigval sigev_value) { |
474 void __client_node_timer_callback_function(int client_node_id) { |
474 /* signal the client node's condition variable on which the client node's thread should be waiting... */ |
475 /* signal the client node's condition variable on which the client node's thread should be waiting... */ |
475 /* Since the communication cycle is run with the mutex locked, we use trylock() instead of lock() */ |
476 /* Since the communication cycle is run with the mutex locked, we use trylock() instead of lock() */ |
476 //pthread_mutex_lock (&(client_nodes[sigev_value.sival_int].mutex)); |
477 if (pthread_mutex_trylock (&(client_nodes[client_node_id].mutex)) != 0) |
477 if (pthread_mutex_trylock (&(client_nodes[sigev_value.sival_int].mutex)) != 0) |
|
478 /* we never get to signal the thread for activation. But that is OK. |
478 /* we never get to signal the thread for activation. But that is OK. |
479 * If it still in the communication cycle (during which the mutex is kept locked) |
479 * If it still in the communication cycle (during which the mutex is kept locked) |
480 * then that means that the communication cycle is falling behing in the periodic |
480 * then that means that the communication cycle is falling behing in the periodic |
481 * communication cycle, and we therefore need to skip a period. |
481 * communication cycle, and we therefore need to skip a period. |
482 */ |
482 */ |
483 return; |
483 return; |
484 client_nodes[sigev_value.sival_int].execute_req = 1; // tell the thread to execute |
484 client_nodes[client_node_id].execute_req = 1; // tell the thread to execute |
485 client_nodes[sigev_value.sival_int].periodic_act = 1; // tell the thread the activation was done by periodic timer |
485 client_nodes[client_node_id].periodic_act = 1; // tell the thread the activation was done by periodic timer |
486 pthread_cond_signal (&(client_nodes[sigev_value.sival_int].condv)); |
486 pthread_cond_signal (&(client_nodes[client_node_id].condv)); |
487 pthread_mutex_unlock(&(client_nodes[sigev_value.sival_int].mutex)); |
487 pthread_mutex_unlock(&(client_nodes[client_node_id].mutex)); |
488 } |
488 } |
489 |
489 |
|
490 |
|
491 |
|
492 static int stop_mb_client_timer_thread; |
|
493 static void *__mb_client_timer_thread(void *_index) { |
|
494 sigset_t set; |
|
495 int signum = SIGALRM; |
|
496 int client_node_id = (char *)_index - (char *)NULL; // Use pointer arithmetic (more portable than cast) |
|
497 printf("%%d\n", client_node_id); |
|
498 /* initialize the timer that will be used to periodically activate the client node */ |
|
499 { |
|
500 // start off by reseting the flag that will be set whenever the timer expires |
|
501 client_nodes[client_node_id].periodic_act = 0; |
|
502 |
|
503 struct sigevent evp = {0}; |
|
504 evp.sigev_notify = SIGEV_THREAD_ID; /* Notification method - call a function in a new thread context */ |
|
505 evp.sigev_signo = SIGALRM; |
|
506 evp.sigev_value.sival_int = client_node_id; /* Data passed to function upon notification - used to indentify which client node to activate */ |
|
507 |
|
508 if (timer_create(CLOCK_MONOTONIC, &evp, &(client_nodes[client_node_id].timer_id)) < 0) { |
|
509 fprintf(stderr, "Modbus plugin: Error (%%s) creating timer for modbus client node %%s\n", strerror(errno), client_nodes[client_node_id].location); |
|
510 return NULL; |
|
511 } |
|
512 } |
|
513 |
|
514 stop_mb_client_timer_thread = 0; |
|
515 while(!stop_mb_client_timer_thread) { |
|
516 if(sigwait (&set, &signum) == -1) |
|
517 perror ("sigwait"); |
|
518 if(stop_mb_client_timer_thread) |
|
519 break; |
|
520 __client_node_timer_callback_function(client_node_id); |
|
521 } |
|
522 |
|
523 // timer was created, so we try to destroy it! |
|
524 int res = timer_delete(client_nodes[client_node_id].timer_id); |
|
525 if (res < 0) |
|
526 fprintf(stderr, "Modbus plugin: Error destroying timer for modbus client node %%s\n", client_nodes[client_node_id].location); |
|
527 |
|
528 return NULL; |
|
529 } |
490 |
530 |
491 |
531 |
492 int __cleanup_%(locstr)s (); |
532 int __cleanup_%(locstr)s (); |
493 int __init_%(locstr)s (int argc, char **argv){ |
533 int __init_%(locstr)s (int argc, char **argv){ |
494 int index; |
534 int index; |
579 goto error_exit; |
619 goto error_exit; |
580 } |
620 } |
581 client_nodes[index].execute_req = 0; //variable associated with condition variable |
621 client_nodes[index].execute_req = 0; //variable associated with condition variable |
582 client_nodes[index].init_state = 3; // we have created the condition variable |
622 client_nodes[index].init_state = 3; // we have created the condition variable |
583 |
623 |
584 /* initialize the timer that will be used to periodically activate the client node */ |
624 /* launch a thread to handle this client node timer */ |
585 { |
625 { |
586 // start off by reseting the flag that will be set whenever the timer expires |
626 int res = 0; |
587 client_nodes[index].periodic_act = 0; |
627 pthread_attr_t attr; |
588 |
628 res |= pthread_attr_init(&attr); |
589 struct sigevent evp; |
629 res |= pthread_create(&(client_nodes[index].timer_thread_id), &attr, &__mb_client_timer_thread, (void *)((char *)NULL + index)); |
590 evp.sigev_notify = SIGEV_THREAD; /* Notification method - call a function in a new thread context */ |
630 if (res != 0) { |
591 evp.sigev_value.sival_int = index; /* Data passed to function upon notification - used to indentify which client node to activate */ |
631 fprintf(stderr, "Modbus plugin: Error starting timer thread for modbus client node %%s\n", client_nodes[index].location); |
592 evp.sigev_notify_function = __client_node_timer_callback_function; /* function to call upon timer expiration */ |
632 goto error_exit; |
593 evp.sigev_notify_attributes = NULL; /* attributes for new thread in which sigev_notify_function will be called/executed */ |
633 } |
594 |
634 } |
595 if (timer_create(CLOCK_MONOTONIC, &evp, &(client_nodes[index].timer_id)) < 0) { |
|
596 fprintf(stderr, "Modbus plugin: Error creating timer for modbus client node %%s\n", client_nodes[index].location); |
|
597 goto error_exit; |
|
598 } |
|
599 } |
|
600 client_nodes[index].init_state = 4; // we have created the timer |
635 client_nodes[index].init_state = 4; // we have created the timer |
601 |
636 |
602 /* launch a thread to handle this client node */ |
637 /* launch a thread to handle this client node */ |
603 { |
638 { |
604 int res = 0; |
639 int res = 0; |
752 } |
787 } |
753 res |= close; |
788 res |= close; |
754 |
789 |
755 close = 0; |
790 close = 0; |
756 if (client_nodes[index].init_state >= 4) { |
791 if (client_nodes[index].init_state >= 4) { |
757 // timer was created, so we try to destroy it! |
792 stop_mb_client_timer_thread = 1; |
758 close = timer_delete(client_nodes[index].timer_id); |
793 pthread_kill(client_nodes[index].timer_thread_id, SIGALRM); |
|
794 // thread was launched, so we try to cancel it! |
|
795 close = pthread_cancel(client_nodes[index].timer_thread_id); |
|
796 close |= pthread_join (client_nodes[index].timer_thread_id, NULL); |
759 if (close < 0) |
797 if (close < 0) |
760 fprintf(stderr, "Modbus plugin: Error destroying timer for modbus client node %%s\n", client_nodes[index].location); |
798 fprintf(stderr, "Modbus plugin: Error closing timer thread for modbus client node %%s\n", client_nodes[index].location); |
|
799 |
761 } |
800 } |
762 res |= close; |
801 res |= close; |
763 |
802 |
764 close = 0; |
803 close = 0; |
765 if (client_nodes[index].init_state >= 3) { |
804 if (client_nodes[index].init_state >= 3) { |