A semaphore is a counter which tasks can wait for to be non-zero. When a semaphore is non-zero and a task waits on it then the semaphore value is decremented and the task continues execution. When a semaphore is zero and a task waits on it then the task will be suspended until the semaphore is signalled. When a semaphore is signalled and no tasks are waiting for it then the semaphore value is incremented. When a semaphore is signalled and tasks are waiting then one of the tasks is made runnable.

You allocate a semaphore by declaring it as a C variable

    CTL_SEMAPHORE_t s1;

An CTL_SEMAPHORE_t is a synonym for an unsigned type, so the maximum value of the counter is dependent upon the word size of the processor (either 16 or 32 bits).

You can initialise a semaphore using the ctl_semaphore_init function.

    ctl_semaphore_init(&s1, 1);

Note that initialisation should be done before any tasks can use a semaphore.

You can signal a semaphore using the ctl_semaphore_signal function.

    ctl_semaphore_signal(&s1);

The highest priority task waiting on the semphore pointed at by s1 will be made runnable by this call. If no tasks are waiting on the semaphore then the semaphore value is incremented.

You can wait for a semaphore with an optional timeout using the ctl_semaphore_wait function.

    ctl_semaphore_wait(&s1, 0, 0);

This example will block the task if the semaphore is zero, otherwise it will decrement the semaphore and continue execution.

    if (ctl_semaphore_wait(&s1, 1, ctl_get_current_time()+1000)==0)
      {
        // timeout occured
      }

This example uses a timeout and tests the return result to see if the timeout occured.

###### Task synchronisation in an interrupt service routine.

The following example illustrates synchronising a task with a function called from an interrupt service routine.

    CTL_SEMAPHORE_t s1;

    void ISRfn()
    {
      // do work
      ctl_semaphore_signal(&s1);
    }

    void task1(void *p)
    {
      while (1)
        {
          ctl_semaphore_wait(&s1, 0, 0);
          …
        }
    }

###### Resource serialisation

The following example illustrates resource serialisation of two tasks.

    CTL_SEMAPHORE_t s1=1;

    void task1(void)
    {
      for (;;)
        {
          ctl_semaphore_wait(&s1, 0, 0);
          /* resource has now been acquired */
          …
          ctl_semaphore_signal(&s1);
          /* resource has now been released */
        }
    }

    void task2(void)
    {
      for (;;)
        {
          ctl_semaphore_wait(&s1);
          /* resource has now been acquired */
          …
          ctl_semaphore_signal(&s1);
          /* resource has now been released */
        }
    }

    int
    main(void)
    {
      …
      ctl_semaphore_init(&s1, 1);
      …
    }

Note that s1 is initialised to one, without this neither task would acquire the resource.