CHAPTER 8 EXTENDED SYNCHRONIZATION AND COMMUNICATION FUNCTIONS


This chapter describes the extended synchronization and communication functions performed by the RI600PX.

8.1 Outline

The extended synchronization and communication function of the RI600PX provides Mutexes for implementing exclusive control between tasks, and Message Buffers for transferring messages of he arbitrary size by copying the message.

8.2 Mutexes

Multitask processing requires the function to prevent contentions on using the limited number of resources (A/D converter, coprocessor, files, or the like) simultaneously by tasks operating in parallel (exclusive control function). To resolve such problems, the RI600PX therefore provides "mutexes".

The following shows a processing flow when using a mutex.

The mutexes provided in the RI600PX supports the priority ceiling protocol.

Figure 8-1 Processing Flow (Mutex)



8.2.1 Priority inversion problem

When a semaphore is used for exclusive control of a resource, a problem called priority inversion may arise. This refers to the situation where a task that is not using a resource delays the execution of a task requesting the resource.

Figure 8-2 illustrates this problem. In this figure, tasks A and C are using the same resource, which task B does not use. Task A attempts to acquire a semaphore so that it can use the resource but enters the WAITING state because task C is already using the resource. Task B has a priority higher than task C and lower than task A. Thus, if task B is executed before task C has released the semaphore, release of the semaphore is delayed by the execution of task B. This also delays acquisition of the semaphore by task A. From the viewpoint of task A, a lower-priority task that is not even competing for the resource gets priority over task A.

To avoid this problem, use a mutex instead of a semaphore.

Figure 8-2 Priority Inversion Problem



8.2.2 Current priority and base priority

A task has two priority levels: base priority and current priority. Tasks are scheduled according to current priority.

While a task does not have a mutex locked, its current priority is always the same as its base priority.

When a task locks a mutex, only its current priority is raised to the ceiling priority of the mutex.

When priority-changing service call chg_pri or ichg_pri is issued, both the base priority and current priority are changed if the specified task does not have a mutex locked. When the specified task locks a mutex, only the base priority is changed. When the specified task has a mutex locked or is waiting to lock a mutex, these service calls returns "E_ILUSE" if a priority higher than the ceiling priority of the mutex is specified.

The current priority can be checked through service call get_pri or iget_pri. And both the current priority and base priority can be referred by ref_tsk or iref_tsk.

8.2.3 Simplified priority ceiling protocol

Original behavior of the priority ceiling protocol is to make the current priority of the task to the highest ceiling priority of mutexes which are locked by the task. This behavior is achieved by controlling the current priority of the task as follows.

- When a task locks a mutex, changes the current priority of the task to the highest ceiling priority of mutexes which are locked by the task.

- When a task unlocks a mutex, changes the current priority of the task to the highest ceiling priority of mutexes which continues to be locked by the task. When there is no mutex locked by the task after unlock, returns the current priority of the task to the base priority.

However, the RI600PX adopts simplified priority ceiling protocol because of reducing overhead. Therefore, the underlined part is not processed.

8.2.4 Differences from semaphores

The mutex operates similarly to semaphores (binary semaphore) whose the maximum resource count is 1, but they differ in the following points.

- The current priority of the task which locks a mutex raises to the ceiling priority of the mutex until the task unlocks the mutex. As a result, the priority inversion problem is evaded.

--> The current priority is not changed by using semaphore.

- A locked mutex can be unlocked (equivalent to returning of resources) only by the task that locked the mutex

--> Semaphores can return resources via any task and handler.

- Unlocking is automatically performed when a task that locked the mutex is terminated (ext_tsk or ter_tsk)

--> Semaphores do not return resources automatically, so they end with resources acquired.

- Semaphores can manage multiple resources (the maximum resource count can be assigned), but the maximum number of resources assigned to a mutex is fixed to 1.

8.2.5 Create mutex

Mutexes are created by one of the following methods.

1 ) Creation by the system configuration file
The static API mutex[] described in the system configuration file creates a mutex.
Refer to 20.15 Mutex Information (mutex[]) for the details of mutex[].



2 ) Creation by cre_mtx or acre_mtx
The cre_mtx creates a mutex with mutex ID indicated by parameter mtxid according to the content of parameter pk_cmtx.
The acre_mtx creates a mutex according to the content of parameter pk_cmtx, and returns the created mutex ID.
The information specified is shown below.



- Mutex attribute (mtxatr)
Only TA_CEILING (Priority ceiling protocol) can be specified for mtxatr.
Note, task wait queue is managed in task current priority order.



- Ceiling priority (ceilpri)

These service calls can be called from tasks that belong to Trusted Domain.
The following describes an example for coding acre_mtx as a representative.


 #include    "kernel.h"              /*Standard header file definition*/
 #include    "kernel_id.h"           /*Header file generated by cfg600px*/
 #pragma task Task1                  /*Refer to note*/
 void Task1 (VP_INT exinf);          /*Refer to note*/
 void Task1 (VP_INT exinf)
 {
     ER      mtxid;              /*Declares variable*/
     T_CMTX  pk_cmtx = {         /*Declares and initializes variable*/
         TA_CEILING,                 /*Mutex attribute (mtxatr)*/
         1                           /*Ceiling priority (ceilpri)*/
     };
 
     /* ......... */
 
     mtxid = acre_mtx ( &pk_cmtx );  /*Create mutex/
 
     /* ......... */
 }


Note These statements are unnecessary for the task which is created by the system configuration file because the cfg600px generates these statement into the "kernel_id.h".

8.2.6 Delete mutex

- del_mtx
This service call deletes the mutex specified by parameter mtxid.
When either of task locks the target mutex, the lock by the task is cancelled. As a result, the current task priority of the task is returned to the base priority when there is no mutex being locked by the task. The task is not notified that the mutex has been deleted. If an attempt is later made to unlock the mutex by using unl_mtx, an error E_NOEXS is returned.
When there are waiting tasks for the target mutex by using loc_mtx or tloc_mtx, this service call cancels the WAITING state of the tasks and returns E_DLT as a return value of the loc_mtx or tloc_mtx.
This service call can be called from tasks that belong to Trusted Domain.
The following describes an example for coding this service call.






 #include    "kernel.h"              /*Standard header file definition*/
 #include    "kernel_id.h"           /*Header file generated by cfg600px*/
 #pragma task Task1                  /*Refer to note*/
 void Task1 (VP_INT exinf);          /*Refer to note*/
 void Task1 (VP_INT exinf)
 {
     ID      mtxid = 8;          /*Declares and initializes variable*/
 
     /* ......... */
 
     ercd = del_mtx ( mtxid );   /*Delete semaphore*/
 
     /* ......... */
 }


Note These statements are unnecessary for the task which is created by the system configuration file because the cfg600px generates these statement into the "kernel_id.h".

8.2.7 Lock mutex

Mutexes can be locked by issuing the following service call from the processing program.

- loc_mtx (Wait)

- ploc_mtx (Polling)

- tloc_mtx (Wait with time-out)

- loc_mtx (Wait)
This service call locks the mutex specified by parameter mtxid.
If the target mutex could not be locked (another task has been locked) when this service call is issued, this service call queues the invoking task to the target mutex wait queue and moves it from the RUNNING state to the WAITING state (mutex wait state).
The WAITING state for a mutex is cancelled in the following cases.




WAITING State for a Mutex Cancel Operation

Return Value

The locked state of the target mutex was cancelled as a result of issuing unl_mtx.

E_OK

The locked state of the target mutex was cancelled as a result of issuing ext_tsk.

E_OK

The locked state of the target mutex was cancelled as a result of issuing exd_tsk.

E_OK

The locked state of the target mutex was cancelled as a result of issuing ter_tsk.

E_OK

Forced release from waiting (accept rel_wai while waiting).

E_RLWAI

Forced release from waiting (accept irel_wai while waiting).

E_RLWAI

Forced release from waiting (accept del_mtx while waiting).

E_DLT



When the mutex is locked, this service call changes the current priority of the invoking task to the ceiling priority of the target mutex. However, this service call does not change the current priority when the invoking task has locked other mutexes and the ceiling priority of the target mutex is lower than or equal to the ceiling priority of the locked mutexes.
The following describes an example for coding this service call.


 #include    "kernel.h"              /*Standard header file definition*/
 #include    "kernel_id.h"           /*Header file generated by cfg600px*/
 #pragma task Task1                  /*Refer to note 3*/
 void Task1 (VP_INT exinf);          /*Refer to note 3*/
 void Task1 (VP_INT exinf)
 {
     ER      ercd;                   /*Declares variable*/
     ID      mtxid = 8;              /*Declares and initializes variable*/
 
     /* ......... */
 
     ercd = loc_mtx (mtxid);         /*Lock mutex*/
 
     if (ercd == E_OK) {
         /* ......... */             /*Locked state*/
 
         unl_mtx (mtxid);            /*Unlock mutex*/
     } else if (ercd == E_RLWAI) {
         /* ......... */             /*Forced termination processing*/
     }
 
     /* ......... */
 }


Note 1 Invoking tasks are queued to the target mutex wait queue in the priority order. Among tasks with the same priority, they are queued in FIFO order.

Note 2 This service call returns "E_ILUSE" if this service call is re-issued for the mutex that has been locked by the invoking task (multiple-locking of mutex).

Note 3 These statements are unnecessary for the task which is created by the system configuration file because the cfg600px generates these statement into the "kernel_id.h".

- ploc_mtx (Polling)
This service call locks the mutex specified by parameter mtxid.
If the target mutex could not be locked (another task has been locked) when this service call is issued but E_TMOUT is returned.
When the mutex is locked, this service call changes the current priority of the invoking task to the ceiling priority of the target mutex. However, the this service call does not change the current priority when the invoking task has locked other mutexes and the ceiling priority of the target mutex is lower than or equal to the ceiling priority of the locked mutexes.
The following describes an example for coding this service call.





 #include    "kernel.h"              /*Standard header file definition*/
 #include    "kernel_id.h"           /*Header file generated by cfg600px*/
 #pragma task Task1                  /*Refer to note 2*/
 void Task1 (VP_INT exinf);          /*Refer to note 2*/
 void Task1 (VP_INT exinf)
 {
     ER      ercd;                   /*Declares variable*/
     ID      mtxid = 8;              /*Declares and initializes variable*/
 
     /* ......... */
 
     ercd = ploc_mtx (mtxid);        /*Lock mutex*/
 
     if (ercd == E_OK) {
         /* ......... */             /*Polling success processing*/
 
         unl_mtx (mtxid);            /*Unlock mutex*/
     } else if (ercd == E_TMOUT) {
         /* ......... */             /*Polling failure processing*/
     }
 
     /* ......... */
 }


Note 1 This service call returns "E_ILUSE" if this service call is re-issued for the mutex that has been locked by the invoking task (multiple-locking of mutex).

Note 2 These statements are unnecessary for the task which is created by the system configuration file because the cfg600px generates these statement into the "kernel_id.h".

- tloc_mtx (Wait with time-out)
This service call locks the mutex specified by parameter mtxid.
If the target mutex could not be locked (another task has been locked) when this service call is issued, this service call queues the invoking task to the target mutex wait queue and moves it from the RUNNING state to the WAITING state with time-out (mutex wait state).
The WAITING state for a mutex is cancelled in the following cases.




WAITING State for a Mutex Cancel Operation

Return Value

The locked state of the target mutex was cancelled as a result of issuing unl_mtx.

E_OK

The locked state of the target mutex was cancelled as a result of issuing ext_tsk.

E_OK

The locked state of the target mutex was cancelled as a result of issuing exd_tsk.

E_OK

The locked state of the target mutex was cancelled as a result of issuing ter_tsk.

E_OK

Forced release from waiting (accept rel_wai while waiting).

E_RLWAI

Forced release from waiting (accept irel_wai while waiting).

E_RLWAI

The time specified by tmout has elapsed.

E_TMOUT

Forced release from waiting (accept del_mtx while waiting).

E_DLT



When the mutex is locked, this service call changes the current priority of the invoking task to the ceiling priority of the target mutex. However, the this service call does not change the current priority when the invoking task has locked other mutexes and the ceiling priority of the target mutex is lower than or equal to the ceiling priority of the locked mutexes.
The following describes an example for coding this service call.


 #include    "kernel.h"              /*Standard header file definition*/
 #include    "kernel_id.h"           /*Header file generated by cfg600px*/
 #pragma task Task1                  /*Refer to note 4*/
 void Task1 (VP_INT exinf);          /*Refer to note 4*/
 void Task1 (VP_INT exinf)
 {
     ER      ercd;                   /*Declares variable*/
     ID      mtxid = 8;              /*Declares and initializes variable*/
     TMO     tmout = 3600;           /*Declares and initializes variable*/
 
     /* ......... */
     ercd = tloc_mtx (mtxid, tmout); /*Lock mutex*/
     if (ercd == E_OK) {
         /* ......... */             /*Locked state*/
         unl_mtx (mtxid);            /*Unlock mutex*/
     } else if (ercd == E_RLWAI) {
         /* ......... */             /*Forced termination processing*/
     } else if (ercd == E_TMOUT) {
         /* ......... */             /*Time-out processing*/
     }
     /* ......... */
 }


Note 1 Invoking tasks are queued to the target mutex wait queue in the priority order. Among tasks with the same priority, they are queued in FIFO order.

Note 2 This service call returns "E_ILUSE" if this service call is re-issued for the mutex that has been locked by the invoking task (multiple-locking of mutex).

Note 3 TMO_FEVR is specified for wait time tmout, processing equivalent to loc_mtx will be executed. When TMO_POL is specified, processing equivalent to ploc_mtx will be executed.

Note 4 These statements are unnecessary for the task which is created by the system configuration file because the cfg600px generates these statement into the "kernel_id.h".

8.2.8 Unlock mutex

The mutex locked state can be cancelled by issuing the following service call from the processing program.

- unl_mtx
This service call unlocks the locked mutex specified by parameter mtxid.
If a task has been queued to the target mutex wait queue when this service call is issued, mutex lock processing is performed by the task (the first task in the wait queue) immediately after mutex unlock processing.
As a result, the task is unlinked from the wait queue and moves from the WAITING state (mutex wait state) to the READY state, or from the WAITING-SUSPENDED state to the SUSPENDED state. And this service call changes the current priority of the task to the ceiling priority of the target mutex. However, this service call does not change the current priority when the task has locked other mutexes and the ceiling priority of the target mutex is lower than or equal to the ceiling priority of the locked mutexes.
The following describes an example for coding this service call.




 #include    "kernel.h"              /*Standard header file definition*/
 #include    "kernel_id.h"           /*Header file generated by cfg600px*/
 #pragma task Task1                  /*Refer to note 3*/
 void Task1 (VP_INT exinf);          /*Refer to note 3*/
 void Task1 (VP_INT exinf)
 {
     ER      ercd;                   /*Declares variable*/
     ID      mtxid = 8;              /*Declares and initializes variable*/
 
     /* ......... */
 
     ercd = loc_mtx (mtxid);         /*Lock mutex*/
 
     if (ercd == E_OK) {
         /* ......... */             /*Locked state*/
 
         unl_mtx (mtxid);            /*Unlock mutex*/
     } else if (ercd == E_RLWAI) {
         /* ......... */             /*Forced termination processing*/
     }
 
     /* ......... */
 }


Note 1 A locked mutex can be unlocked only by the task that locked the mutex.
If this service call is issued for a mutex that was not locked by the invoking task, no processing is performed but "E_ILUSE" is returned.


Note 2 When terminating a task, the mutexes which are locked by the terminated task are unlocked.

Note 3 These statements are unnecessary for the task which is created by the system configuration file because the cfg600px generates these statement into the "kernel_id.h".

8.2.9 Reference mutex state

A mutex status is referenced by issuing the following service call from the processing program.

- ref_mtx,
This service call stores the detailed information of the mutex specified by parameter mtxid (existence of locked mutexes, waiting tasks, etc.) into the area specified by parameter pk_rmtx.
The following describes an example for coding this service call.



 #include    "kernel.h"              /*Standard header file definition*/
 #include    "kernel_id.h"           /*Header file generated by cfg600px*/
 #pragma task Task1                  /*Refer to note 2*/
 void Task1 (VP_INT exinf);          /*Refer to note 2*/
 void Task1 (VP_INT exinf)
 {
     ID      mtxid = 1;              /*Declares and initializes variable*/
     T_RMTX  pk_rmtx;                /*Declares data structure*/
     ID      htskid;                 /*Declares variable*/
     ID      wtskid;                 /*Declares variable*/
 
     /* ......... */
 
     ref_mtx (mbxid, &pk_rmtx);      /*Reference mutex state*/
 
     htskid = pk_rmtx.htskid;        /*Acquires existence of locked mutexes*/
     wtskid = pk_rmtx.wtskid;        /*Reference ID number of the task at the */
                                     /*head of the wait queue*/
 
     /* ......... */
 }


Note 1 For details about the mutex state packet, refer to "[Mutex state packet: T_RMTX]".

Note 2 These statements are unnecessary for the task which is created by the system configuration file because the cfg600px generates these statement into the "kernel_id.h".