434 return NULL; |
434 return NULL; |
435 } |
435 } |
436 |
436 |
437 |
437 |
438 |
438 |
439 /* Function to activate a client node's thread */ |
|
440 /* returns -1 if it could not send the signal */ |
|
441 static int __signal_client_thread(int client_node_id) { |
|
442 /* We TRY to signal the client thread. |
|
443 * We do this because this function can be called at the end of the PLC scan cycle |
|
444 * and we don't want it to block at that time. |
|
445 */ |
|
446 if (pthread_mutex_trylock(&(client_nodes[client_node_id].mutex)) != 0) |
|
447 return -1; |
|
448 client_nodes[client_node_id].execute_req = 1; // tell the thread to execute |
|
449 pthread_cond_signal (&(client_nodes[client_node_id].condv)); |
|
450 pthread_mutex_unlock(&(client_nodes[client_node_id].mutex)); |
|
451 return 0; |
|
452 } |
|
453 |
|
454 |
|
455 |
|
456 /* Function that will be called whenever a client node's periodic timer expires. */ |
|
457 /* The client node's thread will be waiting on a condition variable, so this function simply signals that |
|
458 * condition variable. |
|
459 * |
|
460 * The same callback function is called by the timers of all client nodes. The id of the client node |
|
461 * in question will be passed as a parameter to the call back function. |
|
462 */ |
|
463 void __client_node_timer_callback_function(int client_node_id) { |
|
464 /* signal the client node's condition variable on which the client node's thread should be waiting... */ |
|
465 /* Since the communication cycle is run with the mutex locked, we use trylock() instead of lock() */ |
|
466 if (pthread_mutex_trylock (&(client_nodes[client_node_id].mutex)) != 0) |
|
467 /* we never get to signal the thread for activation. But that is OK. |
|
468 * If it still in the communication cycle (during which the mutex is kept locked) |
|
469 * then that means that the communication cycle is falling behing in the periodic |
|
470 * communication cycle, and we therefore need to skip a period. |
|
471 */ |
|
472 return; |
|
473 client_nodes[client_node_id].execute_req = 1; // tell the thread to execute |
|
474 client_nodes[client_node_id].periodic_act = 1; // tell the thread the activation was done by periodic timer |
|
475 pthread_cond_signal (&(client_nodes[client_node_id].condv)); |
|
476 pthread_mutex_unlock(&(client_nodes[client_node_id].mutex)); |
|
477 } |
|
478 |
|
479 |
439 |
480 |
440 |
481 /* Thread that simply implements a periodic 'timer', |
441 /* Thread that simply implements a periodic 'timer', |
482 * i.e. periodically sends signal to the thread running __mb_client_thread() |
442 * i.e. periodically sends signal to the thread running __mb_client_thread() |
483 * |
443 * |
526 next_cycle = now; |
486 next_cycle = now; |
527 timespec_add(next_cycle, period_sec, period_nsec); |
487 timespec_add(next_cycle, period_sec, period_nsec); |
528 } |
488 } |
529 |
489 |
530 while (0 != clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle, NULL)); |
490 while (0 != clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next_cycle, NULL)); |
531 __client_node_timer_callback_function(client_node_id); |
491 |
|
492 /* signal the client node's condition variable on which the client node's thread should be waiting... */ |
|
493 /* Since the communication cycle is run with the mutex locked, we use trylock() instead of lock() */ |
|
494 if (pthread_mutex_trylock (&(client_nodes[client_node_id].mutex)) == 0) { |
|
495 client_nodes[client_node_id].execute_req = 1; // tell the thread to execute |
|
496 client_nodes[client_node_id].periodic_act = 1; // tell the thread the activation was done by periodic timer |
|
497 pthread_cond_signal (&(client_nodes[client_node_id].condv)); |
|
498 pthread_mutex_unlock(&(client_nodes[client_node_id].mutex)); |
|
499 } else { |
|
500 /* We never get to signal the thread for activation. But that is OK. |
|
501 * If it still in the communication cycle (during which the mutex is kept locked) |
|
502 * then that means that the communication cycle is falling behing in the periodic |
|
503 * communication cycle, and we therefore need to skip a period. |
|
504 */ |
|
505 } |
532 } |
506 } |
533 |
507 |
534 return NULL; |
508 return NULL; // humour the compiler -> will never be executed! |
535 } |
509 } |
536 |
510 |
537 |
511 |
538 int __cleanup_%(locstr)s (); |
512 int __cleanup_%(locstr)s (); |
539 int __init_%(locstr)s (int argc, char **argv){ |
513 int __init_%(locstr)s (int argc, char **argv){ |
741 * requests to execute a specific MB transaction in this __publish_() |
715 * requests to execute a specific MB transaction in this __publish_() |
742 * function. |
716 * function. |
743 */ |
717 */ |
744 if ((client_requests[index].flag_exec_req != 0) && (0 == client_requests[index].flag_exec_started)) { |
718 if ((client_requests[index].flag_exec_req != 0) && (0 == client_requests[index].flag_exec_started)) { |
745 int client_node_id = client_requests[index].client_node_id; |
719 int client_node_id = client_requests[index].client_node_id; |
746 if (__signal_client_thread(client_node_id) >= 0) { |
720 |
747 /* - upon success, set flag_exec_started |
721 /* We TRY to signal the client thread. |
748 * - both flags (flag_exec_req and flag_exec_started) will be reset |
722 * We do this because this function can be called at the end of the PLC scan cycle |
749 * once the transaction has completed. |
723 * and we don't want it to block at that time. |
750 */ |
724 */ |
751 client_requests[index].flag_exec_started = 1; |
725 if (pthread_mutex_trylock(&(client_nodes[client_node_id].mutex)) == 0) { |
752 } |
726 client_nodes[client_node_id].execute_req = 1; // tell the thread to execute |
|
727 pthread_cond_signal (&(client_nodes[client_node_id].condv)); |
|
728 pthread_mutex_unlock(&(client_nodes[client_node_id].mutex)); |
|
729 /* - upon success, set flag_exec_started |
|
730 * - both flags (flag_exec_req and flag_exec_started) will be reset |
|
731 * once the transaction has completed. |
|
732 */ |
|
733 client_requests[index].flag_exec_started = 1; |
|
734 } else { |
|
735 /* The mutex is locked => the client thread is currently executing MB transactions. |
|
736 * We will try to activate it in the next PLC cycle... |
|
737 * For now, do nothing. |
|
738 */ |
|
739 } |
753 } |
740 } |
754 } |
741 } |
755 } |
742 } |
756 |
743 |
757 |
744 |