AllocSignal()
to allocate a signal bit (1 bit within a 32-bit word) for a signal.
WaitSignal()
to enter a wait state until it receives a signal on the bit it allocated.
SendSignal()
to send a signal to Task A. Task B must provide SendSignal()
with the item of that task to signal, and the signals to send the task.
FreeSignal()
to free the signal bit when it's no longer needed.
int32 AllocSignal( uint32 sigMask )
AllocSignal()
accepts as its sole argument a 32-bit word (sigMask
) which specifies which signal bits to allocate. There are 31 signal bits for each task. The lower-8 bits (bits 0-7) are reserved for system use and cannot be allocated. Bits 8-30 can be allocated for task use. To specify a particular signal bit to allocate, just set the corresponding bit in the sigMask
parameter. For example, to allocate bit 21, you set sigMask
to 0x00200000. If you don't care which signal bit you get, you can use AllocSignal(0)
, in which case the kernel chooses a free bit and allocates it for you. It is most common to simply use AllocSignal(0)
instead of requesting specific signal bits.
AllocSignal()
returns a signal mask with bits set to 1 where signals were successfully allocated. If no bits were available for allocation, the call returns 0. If there was an error in allocation, the call returns an error code (a negative number).
The code fragment in example 8-1 demonstrates using AllocSignal()
to allocate a signal bit. In this program, a parent task creates two threads, and it uses the signal mechanisms for the threads to communicate with the parent task. Here, the parent task allocates two of its signal bits, one for each thread. First, it declares two global variables, threadSig1
and threadSig2
, to use as signal mask variables for each of the threads:
Example 1: Allocating a signal bit.
The two calls to
/* Global variables shared by all threads. */
static int32 thread1Sig;
static int32 thread2Sig;
...
...
/* allocate one signal bit for each thread */
thread1Sig = AllocSignal(0);
thread2Sig = AllocSignal(0);
if ((thread1Sig == 0) || (thread2Sig == 0))
{
/* could not allocate the needed signal bits */
}
AllocSignal()
allocate 2 available signal bits. If successful, the variables threadSig1
and threadSig2
each contain a signal mask with a specially allocated bit for each thread to use.
int32 WaitSignal( uint32 sigMask )
WaitSignal()
accepts a signal mask that specifies which of the task's allocated signal bits to wait for. It can specify more than one bit to wait for, but it can't specify any bits that haven't already been allocated. If unallocated bits are specified, the call returns a negative value (an error code) when it executes. Before returning, WaitSignal()
clears the signal bits.
When the allocated bits are specified and the call executes, the task enters the wait state until a signal is sent to one of the signal bits it specified in WaitSignal()
. The task then exits the wait state and returns to the ready queue. The call returns a signal mask with 1 set in each bit where a signal was received.
A task can receive signals before it enters a wait state, in which case they're kept as pending signals in a pending signals mask maintained in the task's control block (TCB). There is no signal queue-that is, no more than one signal can be kept pending for each allocated signal bit. When a task calls WaitSignal()
, any pending signals that match the signal mask given to WaitSignal()
cause the call to return immediately, and the task never enters the wait state. The signal bits that the task was waiting for are cleared before returning.
GetCurrentSignals
():
int32 GetCurrentSignals(void);
You can forcibly set the signal bits of your task by using SendSignal()
with 0 for the task item. This is sometimes useful to set the initial state of the task's signals.
You can also forcibly clear signal bits of a task by using the ClearCurrentSignals()
macro.
Err ClearCurrentSignals(int32 signalMask);
Err SendSignal( Item task, uint32 sigMask )
SendSignal()
is allocated by the receiving task. If it's not, then the call returns a negative number (an error code).
If all specified bits are allocated by the receiving task, then the kernel performs a logical OR between the SendSignal()
signal mask and the pending signals mask maintained in the receiving task's TCB. This is how the pending signals mask maintains a record of pending signals. When the receiving task uses WaitSignal(),
the kernel checks the pending signals mask, and if any bits are set to 1, the task immediately returns to execution.
Err FreeSignal( uint32 sigMask )
FreeSignal()
, frees the specified bits when executed. It returns 0 if it was successful, and a negative number (an error code) if unsuccessful.
The main()
routine uses WaitSignal()
to wait for signals from the two threads. The threads use SendSignal()
to send their signals to the parent task.
Example 2: Complete code sample for signals.
#include "types.h"
#include "task.h"
#include "kernel.h"
#include "stdio.h"
#include "operror.h"
/*****************************************************************************/
/* Global variables shared by all threads. */
static int32 thread1Sig;
static int32 thread2Sig;
static Item parentItem;
static uint32 thread1Cnt;
static uint32 thread2Cnt;
/*****************************************************************************/
/* This routine shared by both threads */
static void DoThread(int32 signal, uint32 amount, uint32 *counter)
{
uint32 i;
while (TRUE)
{
for (i = 0; i < amount; i++)
{
(*counter)++;
SendSignal(parentItem,signal);
}
}
}
/*****************************************************************************/
static void Thread1Func(void)
{
DoThread(thread1Sig, 100000, &thread1Cnt);
}
/*****************************************************************************/
static void Thread2Func(void)
{
DoThread(thread2Sig, 200000,&thread2Cnt);
}
/*****************************************************************************/
int main(int32 argc, char **argv)
{
uint8 parentPri;
Item thread1Item;
Item thread2Item;
uint32 count;
int32 sigs;
/* get the priority of the parent task */
parentPri = CURRENTTASK->t.n_Priority;
/* get the item number of the parent task */
parentItem = CURRENTTASK->t.n_Item;
/* allocate one signal bits for each thread */
thread1Sig = AllocSignal(0);
thread2Sig = AllocSignal(0);
/* spawn two threads that will run in parallel */
thread1Item = CreateThread("Thread1", parentPri, Thread1Func, 2048);
thread2Item = CreateThread("Thread2", parentPri, Thread2Func, 2048);
/* enter a loop until we receive 10 signals */
count = 0;
while (count < 10)
{
sigs = WaitSignal(thread1Sig | thread2Sig);
printf("Thread 1 at %d, thread 2 at %d\n",thread1Cnt,thread2Cnt);
if (sigs & thread1Sig)
printf("Signal from thread 1\n");
if (sigs & thread2Sig)
printf("Signal from thread 2\n");
count++;
}
/* nuke both threads */
DeleteThread(thread1Item);
DeleteThread(thread2Item);
}