Using counting semaphores on Mac OS X

The POSIX runtime extension includes counting semaphores, specified by functions such as sem_wait, sem_post, and sem_create. Unfortunately, OS X does not implement sem_create for counting (unnamed) semaphores, only implementing it for named semaphores. This certainly creates quite an issue if you want the ease of use (or power in some cases), of a counting semaphore.

I thought I was at a loss for using them until I stumbled upon the Mach kernel primitive semaphores, which happen to be, thank goodness, counting semaphores. The Mach kernel specifies the following functions for using semaphores, as defined by <mach/semaphore.h> and <mach/task.h> (Note: I have only listed the important ones that have POSIX relatives):

kern_return_t semaphore_create(task_t task, semaphore_t *semaphore,
    int policy, int value)
kern_return_t semaphore_signal(semaphore_t semaphore)
kern_return_t semaphore_signal_all(semaphore_t semaphore)
kern_return_t semaphore_wait(semaphore_t semaphore)
kern_return_t semaphore_destroy(task_t task, semaphore_t semaphore)
kern_return_t semaphore_signal_thread(semaphore_t semaphore,
    thread_act_t thread_act)

By looking at them, you can probably guess what they do, and if you don’t, you can always look it up in the documentation, or click here to view it on Apple’s developer website.

You may however, be wondering what the task_t type is, and how you might possibly retrieve the correct task_t struct. But never fear, in <mach/task.h>, there are two methods for getting the current task: current_task and mach_task_self, which both return the current task, but in different forms. For user space programming, you should use mach_task_self, which returns a pointer to the kernel’s virtual memory map. If you are doing kernel programming, however, you would not want to use mach_task_self, and instead you want to use current_task. Do not attempt to use current_task in user-space programming, since linking of your code will fail since the symbol is only available to Kernel extensions.

Below is an example using the counting semaphore primitives. Basically, we are counting up and counting down a static variable by the same amount on two separate threads. With the semaphores, the final value should be zero. If you remove the semaphores, you will not get zero, and you will get some arbitrary value.

#include <stdio.h>
#include <pthread.h>

#include <mach/semaphore.h>
#include <mach/task.h>

static int x = 0;
semaphore_t sem = 0;

void * countUp(void *param)
{
    semaphore_wait(sem);

    unsigned i = 0;
    for (i = 0; i < 100000000; i++)
        x++;

    semaphore_signal(sem);
    return NULL;
}

void * countDown(void * param)
{
    semaphore_wait(sem);
    unsigned i = 0;
    for (i = 0; i < 100000000; i++)
        x--;

    semaphore_signal(sem);
    return NULL;
}

int main (int argc, const char * argv[])
{
    // Create our semaphore. SYNC_POLICY_FIFO is how we handle threads that are
    // waiting on the semaphore. I am pretty sure that POSIX uses FIFO, so I
    // think it is best to use that here, though there are other options defined
    // in .
    int initialValue = 1;
    semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, initialValue);

    pthread_t up, down;
    pthread_create(&up, NULL, countUp, NULL);
    pthread_create(&down, NULL, countDown, NULL);

    pthread_join(up, NULL);
    pthread_join(down, NULL);

    printf(”%d\n”, x);  // Should print 0.

    return 0;
}

Now the only problem with this code is that it is not platform independent, and will not compile on Linux. If you wanted, you could make platform independent versions of semaphore creating, posting, and waiting functions, as implemented in the example below:

#ifdef __APPLE__
#include <mach/semaphore.h>
#include <mach/task.h>
#else
#include <semaphore.h>
#endif

void platform_sem_create(void * semStructure, int initialValue)
{
    #ifdef __APPLE__
    semaphore_create(mach_task_self(), (semaphore_t *)semStructure, SYNC_POLICY_FIFO, initialValue);
    #else
    int pshared = 0;
    sem_init((sem_t *)semStructure, pshared, initialValue);
    #endif
}

void platform_sem_signal(void * semStructure)
{
    #ifdef __APPLE__
    semaphore_signal(*((semaphore_t *)semStructure));
    #else
    sem_post((sem_t *)semStructure);
    #endif
}

void platform_sem_wait(void * semStructure)
{
    #ifdef __APPLE__
    semaphore_wait(*((semaphore_t *)semStructure));
    #else
    sem_wait((sem_t *)semStructure);
    #endif
}

Then in your code, just use platform_sem_create, platform_sem_signal, and platform_sem_wait instead of functions like sem_wait, semaphore_create, etc.

And that’s the magic to using counting semaphores on Mac OS X.