Events: Overview

The first method for synchronizing threads is to control them using events.

Events consist of information provided to an event structure. By calling functions available in the SDK, an event can be generated to signal moribund threads that are waiting for an event. If a waiting thread fulfills the specified conditions, its state can be changed from waiting to runnable.

Event Structure

The event structure's data is of type OSEvent, and has the following members:

Member Name Type Usage
flag u32 Event flag. Stores the flag of the given event.
queue OSThreadQueue Thread queue. Used to pause (put in the waiting state) or start threads.

Initializing the Event Structure

Before making a thread wait for an event, the structure must be initialized.
The initialization function is OS_InitEvent.

OS_InitEvent( &event );

Waiting for Events

To wait for an event, you must take an event structure that has been initialized with the OS_InitEvent function and pass it to the OS_WaitEvent function.

To specify the completion conditions when waiting for an event, use the arguments of the OS_WaitEvent function. These are specified as a bit pattern (pattern) and a mode (mode). Depending on the mode, waiting will complete when either (1) all bits in the event flag's bit pattern become 1, or (2) any of the bits in the event flag's bit pattern become 1.

Value of mode Completion Conditions
OS_EVENT_MODE_AND Stop waiting when all bits become 1
OS_EVENT_MODE_OR Stop waiting when any bits become 1


Until the specified condition is fulfilled, threads for which this function has been called will be in the waiting state. Strictly speaking, there will be a short time required to find out whether the condition has been fulfilled, but the thread will enter the waiting state immediately if the condition has not been fulfilled. In other words, calling this function may cause execution to switch to a separate thread.

Use the OS_WaitEventEx function if you want to clear the event flag once the condition is fulfilled.

The return value will be the value of the event flag when the condition is fulfilled. If you have specified that the event flag should be cleared with the OS_WaitEventEx function, the flag value before the clear operation will be returned.

OS_WaitEvent( &event, pattern, mode );
OS_WaitEventEx( &event, pattern, mode, clearBit );


If the completion conditions have already been fulfilled, control will return immediately without a thread function being called.

Setting Event Flags

Call the OS_SignalEvent function to set an event flag and signal a waiting thread.

OS_SignalEvent( &event, setBit );


Internally, after setting the event, this function will use the thread queue within the event structure to reschedule.Calling this function may cause execution to switch to a separate thread.

Clearing Event Flags

Call the OS_ClearEvent function to clear a particular bit in the event structure's event flag. To clear all bits, call the OS_ClearAllEvent function.

OS_ClearEvent( &event, clearBit );
OS_ClearAllEvent( &event )


Control will not switch to another thread as a result of this function.

Polling Event Flags

The standard procedure for waiting for events is to use the OS_WaitEvent thread function, but it is also possible to poll the OS_PollEvent function to determine whether the conditions are fulfilled on your own.

OS_PollEvent( &event, pattern, mode );
OS_PollEventEx( &event, pattern, mode, clearBit );


Here, the completion conditions for waiting are the same as those for the OS_WaitEvent* functions.

If the return value is nonzero, the conditions will be deemed to have been fulfilled, and that return value will be the value of the event flag. If the return value is 0, the conditions are not fulfilled.

Like the OS_WaitEventEx function, the OS_PollEventEx function allows you to clear specified bits using a clear flag when the conditions have been fulfilled.

Example 1

Here, let's consider the case where we have three threads: a thread waiting for events, thread 1, and thread 2. In this example, the thread waiting for events is waiting for MY_EVENT1 (thread 1) and MY_EVENT2 (thread 2) to be signaled. It will continue waiting until both are signaled.

OSEvent event;

#define MY_EVENT1 0x00000001
#define MY_EVENT2 0x00000002
#define MY_EVENT (MY_EVENT1 | MY_EVENT2)

//-------- thread waiting on events
func()
{
OS_InitEvent( &event );
:
(void)OS_WaitEvent( &event, MY_EVENT, OS_EVENT_MODE_AND );
OS_Printf( "signaled EVENT1 and EVENT2\n" );
:
}

//-------- thread 1
thread1()
{
:
OS_SignalEvent( &event, MY_EVENT1 );
:
}

//-------- thread 2
thread2()
{
:
OS_SignalEvent( &event, MY_EVENT2 );
:
}


In the example above, the waiting thread waited until both MY_EVENT1 and MY_EVENT2 were signaled. Only one change, shown below, is necessary to change this so that it will wait only until either one is signaled.

// Part of func() in the example above has been changed.

(void)OS_WaitEvent( &event, MY_EVENT, OS_EVENT_MODE_OR );
OS_Printf( "signaled EVENT1 or EVENT2\n" );

Example 2

In this example we have two threads: a thread waiting for events, and thread 1, which signals MY_EVENT1 periodically. The thread waiting for events will start up each time MY_EVENT1 is signaled. Once its processing completes, it will go back to waiting for events and enter the moribund state.

OSEvent event;

#define MY_EVENT1 0x00000001

//-------- this thread waits for an event
func()
{
OS_InitEvent( &event );
:
while(1)
{
(void)OS_WaitEventEx( &event, MY_EVENT1,
OS_EVENT_MODE_AND,
MY_EVENT1);

OS_Printf( "signaled EVENT1\n" );
}
:
}

//-------- Thread 1
thread1()
{
:
OS_SignalEvent( &event, MY_EVENT1 );
:
OS_SignalEvent( &event, MY_EVENT1 );
:
}

In this example, we use the OS_WaitEventEx function to clear MY_EVENT1 when the event completes. This is done in order to accept events again.

If this code is changed so that the waiting thread waits for events with the OS_WaitEvent function and clears flag by itself after completion, and an interrupt occurs after the OS_WaitEvent function completes but before flag is cleared, it will not be possible to catch the next single time MY_EVENT1 is signaled. (This is not a problem if interrupts are prohibited for the duration of this sequence, but that would be no different from using the OS_WaitEventEx function.)

// By changing func() as shown below, some events may be dropped.

func()
{
OS_InitEvent( &event );
:
while(1)
{
(void)OS_WaitEvent( &event, MY_EVENT1,
OS_EVENT_MODE_AND );

// When the event occurs here
// Immediately cleared on the line below
event->flag = 0;
OS_Printf( "signaled EVENT1\n" );
}
:
}


See Also

OS_InitEvent
OS_WaitEvent*
OS_SignalEvent
OS_Clear*Event
OS_PollEvent*

Revision History

2007/12/04 Initial version.


CONFIDENTIAL