Thread Synchronization¶
The TI-RTOS kernel provides several modules for synchronizing tasks such as Semaphore, Event, and Queue. The following sections discuss these common TI-RTOS primitives.
Semaphores¶
Semaphores are commonly used for task synchronization and mutual exclusions
throughout TI-RTOS applications. Figure 17. shows the semaphore
functionality. Semaphores can be counting semaphores or binary semaphores.
Counting semaphores keep track of the number of times the semaphore is posted
with Semaphore_post()
. When a group of resources are shared between tasks,
this function is useful. Such tasks might call Semaphore_pend()
to see if a
resource is available before using one. Binary semaphores can have only two
states: available (count = 1) and unavailable (count = 0). Binary semaphores
can be used to share a single resource between tasks or for a basic-signaling
mechanism where the semaphore can be posted multiple times. Binary semaphores
do not keep track of the count; they track only whether the semaphore has been
posted.
Initializing a Semaphore¶
The following code depicts how a semaphore is initialized in TI-RTOS. Semaphores can be created and constructed as explained in Creating vs. Constructing.
See Listing 2. on how to create a Semaphore.
See Listing 3. on how to construct a Semaphore.
Pending on a Semaphore¶
Semaphore_pend()
is a blocking function call. This call may only be called
from within a Task context. A task calling this function will allow lower
priority tasks to execute, if they are ready to run. A task calling
Semaphore_pend()
will block if its counter is 0, otherwise it will
decrement the counter by one. The task will remain blocked until another thread
calls Semaphore_post()
or if the supplied system tick timeout has occurred;
whichever comes first. By reading the return value of Semaphore_pend()
it
is possible to distinguish if a semaphore was posted or if it timed out.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | bool isSuccessful;
uint32_t timeout = 1000 * (1000/Clock_tickPeriod);
/* Pend (approximately) up to 1 second */
isSuccessful = Semaphore_pend(sem, timeoutInTicks);
if (isSuccessful)
{
System_printf("Semaphore was posted");
}
else
{
System_printf("Semaphore timed out");
}
|
Note
The default TI-RTOS system tick period is 1 millisecond. This default is
reconfigured to 10 microseconds for CC13x0 by
setting Clock.tickPeriod = 10
in the .cfg
file.
Given a system tick of 10 microseconds, timeout
in
Listing 4. will be approximately 1 second.
Posting a Semaphore¶
Posting a semaphore is accomplished via a call to Semaphore_post()
. A task
that is pending on a posted semaphore will transition from a blocked state to
a ready state. If no higher priority thread is ready to run, it will allow
the previously pending task to execute. If no task is pending on the semaphore,
a call to Semaphore_post()
will increment its counter. Binary semaphores
have a maximum count of 1.
1 | Semaphore_post(sem);
|
Event¶
Semaphores themselves provide rudimentary synchronization between threads. There are cases just the Semaphore itself is enough to understand on what process needs to be triggered. Often however, a specific causes for the synchronization need to be passed across threads as well. To help accomplish this, one can utilize the TI-RTOS Event module.
Events are similar to Semaphores in a sense that each instance of an Event object actually contains a Semaphore. The added advantage of using Events lie in the fact that tasks can be notified of specific events in a thread-safe manner.
Initializing an Event¶
Creating and constructing Events follow the same guidelines as explained in Creating vs. Constructing. Shown in Listing 6. is an example on how to construct an Event instance.
1 2 3 4 5 6 7 8 9 | Event_Handle event;
Event_Params eventParams;
Event_Struct structEvent; /* Memory allocated at build time */
Event_Params_init(&eventParams);
Event_construct(&structEvent, 0, &eventParams);
/* It's optional to store the handle */
event = Event_handle(&structEvent);
|
Pending on an Event¶
Similar to Semaphore_pend()
, a Task thread would typically block on an
Event_pend()
until an event is posted via an Event_post()
or if the
specified timeout expired. Shown in Listing 7. is a
snippet of a task pending on any of the 3 sample event IDs shown below.
BIOS_WAIT_FOREVER
is used to prevent a timeout from occurring. As a result,
Event_pend()
will have one or more events posted in the returned bit-masked
value.
Each event returned from Event_pend()
has been automatically cleared within
the event instance in a thread-safe manner. Therefore, it is only necessary to
keep a local copy of posted events. For full details on how to use
Event_pend()
, see the TI-RTOS Kernel User Guide.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #define START_ADVERTISING_EVT Event_Id_00
#define START_CONN_UPDATE_EVT Event_Id_01
#define CONN_PARAM_TIMEOUT_EVT Event_Id_02
void TaskFxn(..)
{
/* Local copy of events that have been posted */
uint32_t events;
while(1)
{
/* Wait for an event to be posted */
events = Event_pend(event,
Event_Id_NONE,
START_ADVERTISING_EVT |
START_CONN_UPDATE_EVT |
CONN_PARAM_TIMEOUT_EVT,
BIOS_WAIT_FOREVER);
if (events & START_ADVERTISING_EVT)
{
/* Process this event */
}
if (events & START_CONN_UPDATE_EVT)
{
/* Process this event */
}
if (events & CONN_PARAM_TIMEOUT_EVT)
{
/* Process this event */
}
}
}
|
Note
The default TI-RTOS system tick period is 1 millisecond. This default is
reconfigured to 10 microseconds for CC26xx and CC13xx devices by setting
Clock.tickPeriod = 10
in the .cfg
file.
Given a system tick of 10 microseconds, timeout
in
Listing 4. will be approximately 1 second.
Posting an Event¶
Events may be posted from any TI-RTOS kernel contexts and is simply done by
calling Event_post()
of the Event instance and the Event ID.
Listing 8. shows how a high priority thread such as a Swi
could post a specific event.
1 2 3 4 5 6 7 8 | #define START_ADVERTISING_EVT Event_Id_00
#define START_CONN_UPDATE_EVT Event_Id_01
#define CONN_PARAM_TIMEOUT_EVT Event_Id_02
void SwiFxn(UArg arg)
{
Event_post(event, START_ADVERTISING_EVT);
}
|