modbus/mb_runtime.c
changeset 2688 4dd67aa45855
parent 2687 c79c5d49ba34
child 2716 ebb2595504f0
equal deleted inserted replaced
2687:c79c5d49ba34 2688:4dd67aa45855
   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