CHAPTER 6 EXTENDED SYNCHRONIZATION AND COMMUNICATION FUNCTIONS
This chapter describes the extended synchronization and communication functions performed by the RI600V4.
The extended synchronization and communication function of the RI600V4 provides
Mutexes for implementing exclusive control between tasks, and
Message Buffers for transferring messages of he arbitrary size by copying the message.
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 RI600V4 therefore provides "mutexes".
The following shows a processing flow when using a mutex.
The mutexes provided in the RI600V4 supports the priority ceiling protocol.
Figure 6-1 Processing Flow (Mutex)
6.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 6-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 6-2 Priority Inversion Problem
6.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.
6.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 RI600V4 adopts simplified priority ceiling protocol because of reducing overhead. Therefore, the underlined part is not processed.
6.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.
In the RI600V4, the method of creating a mutex is limited to "static creation".
Mutexes therefore cannot be created dynamically using a method such as issuing a service call from a processing program.
Static mutex creation means defining of mutexes using static API "mutex[]" in the system configuration file.
Mutexes can be locked by issuing the following service call from the processing program.
-
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
|
|
The locked state of the target mutex was cancelled as a result of issuing unl_mtx.
|
|
The locked state of the target mutex was cancelled as a result of issuing ext_tsk.
|
|
The locked state of the target mutex was cancelled as a result of issuing ter_tsk.
|
|
Forced release from waiting (accept rel_wai while waiting).
|
|
Forced release from waiting (accept irel_wai while waiting).
|
|
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 cfg600*/
void task (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).
-
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 cfg600*/
void task (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 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).
-
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
|
|
The locked state of the target mutex was cancelled as a result of issuing unl_mtx.
|
|
The locked state of the target mutex was cancelled as a result of issuing ext_tsk.
|
|
The locked state of the target mutex was cancelled as a result of issuing ter_tsk.
|
|
Forced release from waiting (accept rel_wai while waiting).
|
|
Forced release from waiting (accept irel_wai while waiting).
|
|
The time specified by tmout has elapsed.
|
|
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 cfg600*/
void task (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.
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 cfg600*/
void task (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.
6.2.8 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 cfg600*/
void task (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*/
/* ......... */
}
|