Difference between revisions of "OCEOS/oceos inter-task communication/mutex"
Okhoruzhyy (talk | contribs) (→Mutex) |
Okhoruzhyy (talk | contribs) (→Mutex) |
||
(One intermediate revision by the same user not shown) | |||
Line 1: | Line 1: | ||
=<span style="color:#0000ff">'''Mutex'''</span>= | =<span style="color:#0000ff">'''Mutex'''</span>= | ||
==<span style="color:#0000ff">Introduction</span>== | ==<span style="color:#0000ff">Mutex Introduction</span>== | ||
In OCEOS all mutexes are defined at compile time when the tasks that use them are known. A | In OCEOS all mutexes are defined at compile time when the tasks that use them are known. A task obtains and returns a mutex by [[OCEOS/oceos_inter-task_communication/mutex#oceos_mutex_wait()|oceos_mutex_wait()]] and [[OCEOS/oceos_inter-task_communication/mutex#oceos_mutex_signal()|oceos_mutex_signal()]] calls to OCEOS. | ||
<blockquote style="background-color: #c6e2f7; border-left-style: solid; border-left-width: 3px; border-left-color: blue; "> '''Note'''<br> | |||
Each mutex has a priority ceiling, the priority | Each mutex has a priority ceiling, the task with lower priority or equal priority can ‘wait’ for that mutex. This is identified by the application developer and used in defining the mutex. | ||
</blockquote > | |||
At compile time it is possible to determine the maximum time for which a mutex can be held by examining the source code of each task that uses the mutex.<br> | At compile time it is possible to determine the maximum time for which a mutex can be held by examining the source code of each task that uses the mutex.<br> | ||
Line 13: | Line 13: | ||
The maximum time across all mutexes for which a mutex can be held gives the maximum time for which a higher priority task can be blocked waiting for a mutex (assuming mutex overlaps are nested). | The maximum time across all mutexes for which a mutex can be held gives the maximum time for which a higher priority task can be blocked waiting for a mutex (assuming mutex overlaps are nested). | ||
In OCEOS when a mutex | In OCEOS when a mutex [[OCEOS/oceos_inter-task_communication/mutex#oceos_mutex_wait()|oceos_mutex_wait()]] call succeeds, the current system priority ceiling value is replaced by a value derived from the mutex and the current system priority ceiling. | ||
When a mutex | When a mutex [[OCEOS/oceos_inter-task_communication/mutex#oceos_mutex_signal()|oceos_mutex_signal()]] call succeeds, the previous system priority ceiling is restored and OCEOS automatically reschedules and pre-empts if appropriate. | ||
In OCEOS a pending job only becomes active if its priority is higher than the system priority ceiling. As a result when a job becomes active no mutex that could block it is currently held. | In OCEOS a pending job only becomes active if its priority is higher than the system priority ceiling. As a result when a job becomes active no mutex that could block it is currently held. | ||
Line 24: | Line 24: | ||
In OCEOS if a job terminates while holding a mutex the ‘signal’ operation is performed automatically for all mutexes held by the job and this is logged and the system state updated. | In OCEOS if a job terminates while holding a mutex the ‘signal’ operation is performed automatically for all mutexes held by the job and this is logged and the system state updated. | ||
<blockquote style="background-color: #c6e2f7; border-left-style: solid; border-left-width: 3px; border-left-color: blue; "> '''Note'''<br> | |||
Mutexes can be read by interrupt handling code but do not provide mutual exclusion for such code. Mutual exclusion in interrupt handling code is achieved by enabling and disabling traps/interrupts. | Mutexes can be read by interrupt handling code but do not provide mutual exclusion for such code. Mutual exclusion in interrupt handling code is achieved by enabling and disabling traps/interrupts. | ||
</blockquote > | |||
A mutex has a unique mutex ID, an unsigned integer usually defined in the application header file as an enum MUTEX_NAME{} thus allowing a user-friendly name be associated with each mutex ID. Mutex IDs are used as indices into both fixed and dynamic data arrays and must cover the range 0 to ((number of mutexes) -1). This is facilitated by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....<br> | A mutex has a unique mutex ID, an unsigned integer usually defined in the application header file as an enum MUTEX_NAME{} thus allowing a user-friendly name be associated with each mutex ID. Mutex IDs are used as indices into both fixed and dynamic data arrays and must cover the range 0 to ((number of mutexes) -1). This is facilitated by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....<br> | ||
The priority ceiling of a mutex is specified when the mutex is created and does not change subsequently. Priority ceilings are stored in the fixed data area as an array U8_t mutexCeilings[] indexed by the mutex ID. Mutex dynamic data such as its current state and the job holding it are stored in the dynamic data area in an array of U32_t mutexDynamic[] also indexed by the mutex ID.<br> | The priority ceiling of a mutex is specified when the mutex is created and does not change subsequently. Priority ceilings are stored in the fixed data area as an array U8_t mutexCeilings[] indexed by the mutex ID. Mutex dynamic data such as its current state and the job holding it are stored in the dynamic data area in an array of U32_t mutexDynamic[] also indexed by the mutex ID.<br> | ||
==<span style="color:#0000ff">Mutex Configuration</span>== | |||
<blockquote> | |||
User must define NUMBER_OF_MUTEXES. If NUMBER_OF_MUTEXES is zero, mutexes are not used. The example can be found in OCEOS demo projects.<br> | |||
User must create defined number of NUMBER_OF_MUTEXES before calling [[OCEOS/oceos kernel/initialisation#oceos_init_finish()|oceos_init_finish()]] | |||
<syntaxhighlight lang="C"> | |||
#define NUMBER_OF_MUTEXES 2 | |||
/* | |||
* Create the application configuration structure | |||
*/ | |||
struct application_configuration app_config = {0}; | |||
app_config.number_of_mutexes = NUMBER_OF_MUTEXES; | |||
</syntaxhighlight> | |||
</blockquote> | |||
==<span style="color:#0000ff">API Functions</span>== | ==<span style="color:#0000ff">API Functions</span>== |
Latest revision as of 15:51, 22 March 2022
Mutex
Mutex Introduction
In OCEOS all mutexes are defined at compile time when the tasks that use them are known. A task obtains and returns a mutex by oceos_mutex_wait() and oceos_mutex_signal() calls to OCEOS.
Note
Each mutex has a priority ceiling, the task with lower priority or equal priority can ‘wait’ for that mutex. This is identified by the application developer and used in defining the mutex.
At compile time it is possible to determine the maximum time for which a mutex can be held by examining the source code of each task that uses the mutex.
If a job holds more than one mutex, these should be acquired and released in a nested manner. To help ensure this is the case, a record is kept of the number of mutexes a job already holds when it acquires a mutex, and this is compared with the number of mutexes the job holds after the mutex is released. A warning is given if these are not the same.
Note
If a job simultaneously holds more than one mutex, this must be done in a LIFO nested way, e.g. Wait1, Wait2, Wait3, Signal3, Signal2, Signal1.
The maximum time across all mutexes for which a mutex can be held gives the maximum time for which a higher priority task can be blocked waiting for a mutex (assuming mutex overlaps are nested).
In OCEOS when a mutex oceos_mutex_wait() call succeeds, the current system priority ceiling value is replaced by a value derived from the mutex and the current system priority ceiling.
When a mutex oceos_mutex_signal() call succeeds, the previous system priority ceiling is restored and OCEOS automatically reschedules and pre-empts if appropriate.
In OCEOS a pending job only becomes active if its priority is higher than the system priority ceiling. As a result when a job becomes active no mutex that could block it is currently held.
In OCEOS if a job does a mutex ‘wait’ and then a ‘wait’ on the same mutex without an intervening ‘signal’ the second ‘wait’ is treated as a no-operation but is logged and the system state updated.
In OCEOS a ‘signal’ by a job on a mutex not currently held by the job is treated as a no-operation but is logged and the system state updated.
In OCEOS if a job terminates while holding a mutex the ‘signal’ operation is performed automatically for all mutexes held by the job and this is logged and the system state updated.
Note
Mutexes can be read by interrupt handling code but do not provide mutual exclusion for such code. Mutual exclusion in interrupt handling code is achieved by enabling and disabling traps/interrupts.
A mutex has a unique mutex ID, an unsigned integer usually defined in the application header file as an enum MUTEX_NAME{} thus allowing a user-friendly name be associated with each mutex ID. Mutex IDs are used as indices into both fixed and dynamic data arrays and must cover the range 0 to ((number of mutexes) -1). This is facilitated by using enum MUTEX_NAME{} to automatically assign names to IDs 0,1,....
The priority ceiling of a mutex is specified when the mutex is created and does not change subsequently. Priority ceilings are stored in the fixed data area as an array U8_t mutexCeilings[] indexed by the mutex ID. Mutex dynamic data such as its current state and the job holding it are stored in the dynamic data area in an array of U32_t mutexDynamic[] also indexed by the mutex ID.
Mutex Configuration
User must define NUMBER_OF_MUTEXES. If NUMBER_OF_MUTEXES is zero, mutexes are not used. The example can be found in OCEOS demo projects.
User must create defined number of NUMBER_OF_MUTEXES before calling oceos_init_finish()#define NUMBER_OF_MUTEXES 2 /* * Create the application configuration structure */ struct application_configuration app_config = {0}; app_config.number_of_mutexes = NUMBER_OF_MUTEXES;
API Functions
Directive | Description | main | task | IRQ handler |
---|---|---|---|---|
oceos_mutex_create() | Create Mutex | * | ||
oceos_mutex_wait() | Wait on mutex with ID | * | ||
oceos_mutex_signal() | Signal a mutex with ID | * | ||
oceos_mutex_get_value() | Get current value of mutex with ID | * | * |
oceos_mutex_create()
Header File
mutex.h
Description
Creates a mutex with priority ceiling.
This function should only be called after OCEOS is initialized with oceos_init() and before initialization ends with oceos_init_finish() and scheduling starts with oceos_start()
Prototype
enum DIRECTIVE_STATUS oceos_mutex_create( const unsigned int id, // mutex ID, must be in range 0 to 62 const U8_t priority // mutex priority ceiling );Parameters
Parameter Description id Mutex ID, must be in range 0 to 62 priority Mutex priority ceiling from 1 to 254 (high to low task priority) Returns
This function returns enum DIRECTIVE_STATUS.
enum DIRECTIVE_STATUS Description INCORRECT_STATE System Meta pointer is NULL or corrupt INVALID_ID Failed mutex id check INVALID_NAME Mutex ID is not available INVALID_NUMBER Mutex priority is not valid TOO_MANY Mutex configuration max value reached SUCCESSFUL All OK Example Usage
//mutex names - all start with m_ to avoid confusion with other names enum MUTEX_NAME{ m_apple, m_grape }; ... enum DIRECTIVE_STATUS status; status = oceos_mutex_create(m_apple, 3); if(SUCCESSFUL != status){ // Handle ERROR } // if
oceos_mutex_wait()
Header File
mutex.h
Description
Wait on mutex with ID.
If task succeeds in grabbing mutex, system level priority rises to priority of this mutex, so tasks with lower or equal priority will not be able to start till mutex is released.
If successful, assigns a mutex to a job and replaces the current system priority ceiling with the ceiling specified when the mutex was created.
If the mutex is already held by another task, task with the same priority as mutex or lower will not be started.This should only be called after OCEOS scheduling has started with oceos_start().
Note
This directive can not be called from IRQ Handler.
Prototype
enum DIRECTIVE_STATUS oceos_mutex_wait( const unsigned int id // mutex ID, must be in range 0 to 62 );Parameters
Parameter Description id Mutex ID, must be in range 0 to 62 Returns
This function returns enum DIRECTIVE_STATUS.
enum DIRECTIVE_STATUS Description NOT_CONFIGURED System Meta pointer is NULL or corrupt INTERNAL_ERROR Mutex Dynamic pointer is NULL or Scheduling is not started or Inconsistent Mutex state (check log)
INVALID_ID Mutex ID is out of range SUCCESSFUL All OK Example Usage
//mutex names - all start with m_ to avoid confusion with other names enum MUTEX_NAME{ m_apple, m_grape }; ... enum DIRECTIVE_STATUS status; status = oceos_mutex_wait(m_apple); if(SUCCESSFUL != status){ // Handle ERROR } // if
oceos_mutex_signal()
Header File
mutex.h
Description
Signal a mutex with ID.
This directive releases a mutex from a job, restores the previous system priority ceiling, and calls schedualer. If the mutex is not currently held by the job then nothing is done and an appropriate status returned.This should only be called after OCEOS scheduling has started with oceos_start().
Note
This directive can not be called from IRQ Handler.
Prototype
enum DIRECTIVE_STATUS oceos_mutex_signal( const unsigned int id // mutex ID, must be in range 0 to 62 );Parameters
Parameter Description id Mutex ID, must be in range 0 to 62 Returns
This function returns enum DIRECTIVE_STATUS.
enum DIRECTIVE_STATUS Description NOT_CONFIGURED System Meta pointer is NULL or corrupt INTERNAL_ERROR Mutex Dynamic pointer is NULL or Scheduling is not started or Inconsistent Mutex state (check log)
INVALID_ID Mutex ID is out of range SUCCESSFUL All OK Example Usage
//mutex names - all start with m_ to avoid confusion with other names enum MUTEX_NAME{ m_apple, m_grape }; ... enum DIRECTIVE_STATUS status; status = oceos_mutex_signal(m_apple); if(SUCCESSFUL != status){ // Handle ERROR } // if
oceos_mutex_get_value()
Header File
mutex.h
Description
Get current value of mutex with ID.
This should only be called after OCEOS scheduling has started with oceos_start().
Prototype
unsigned int oceos_mutex_get_value( const unsigned int id // mutex ID, must be in range 0 to 62 );Parameters
Parameter Description id Mutex ID, must be in range 0 to 62 Returns
This function returns unsigned int.
unsigned int Description 0 Mutex is Unavailable 1 Mutex is Available STATUS_INVALID (== 0xffffffff) ERROR Example Usage
//mutex names - all start with m_ to avoid confusion with other names enum MUTEX_NAME{ m_apple, m_grape }; ... unsigned int status; status = oceos_mutex_get_value(m_apple); if(STATUS_INVALID == status){ // Handle ERROR } // if