1.4.2.1 Semaphore Operations

The semaphore implements a method for thread synchronization. This synchronization can be either between one thread and another or between an ISR and a thread. A semaphore once signalled will unblock the highest priority thread currently pending on it.

A semaphore can be used to lock a shared resource, although it is more normal to use a mutex for such an activity. Once obtained a semaphore should be posted back to enable it to be retaken at a later time or in another thread.

/* mainline code prior to OS start */
    /* declare a variable of type semaphore handle */
    OSAL_SEM_DECLARE(semSync);
    /* create the semaphore */
    OSAL_SEM_Create(&semSync, OSAL_SEM_TYPE_BINARY, 0, 0);


/* thread one */
    ...
    /* take the semaphore without waiting */
    OSAL_SEM_Pend(semSync, 0);
    ... perform some actions
    /* return the semaphore */
    OSAL_SEM_Post(semSync);
    ...

/* thread two must not execute until thread one has finished its operations*/
    ...
    /* block on the semaphore */
    OSAL_SEM_Pend(semSync, OSAL_WAIT_FOREVER);
    ... perform some more actions
    /* return the semaphore */
    OSAL_SEM_Post(semSync);

A semaphore can be signalled multiple times and so provides a method for an ISR to release a thread waiting on it. Even though the blocked thread never returns the semaphore, because the asynchronous ISR repeatedly posts it the next time the thread wants to pend on the semaphore it will be available.

By moving the majority of interrupt service processing from the ISR to a high priority thread the system response time is improved and the eventual processing can take advantage of OSAL features such as mutexes and queues which would normally be harder to implement inside the ISR. This technique is known as deferred interrupt processing.

/* an example interrupt handler called from an ISR that performs task synchronization using a semaphore */
void _ISRTasksRX(void) /* N.B. pseudo-code ISR */
{
    ...

    _DRV_USART_InterruptSourceStatusClear(_DRV_USART_GET_INT_SRC_RX(_DRV_USART_OBJ(dObj, rxInterruptSource)));

    /* Release the receive semaphore unblocking any tasks */
    OSAL_SEM_PostISR(_DRV_USART_OBJ(dObj, rxSemID));

} /* DRV_USART_TasksRX */