Why are sem_init(), sem_getvalue(), sem_destroy() deprecated on Mac OS X — and what replaces them?

Jonathan Leffler picture Jonathan Leffler · Jan 2, 2015 · Viewed 18.8k times · Source

When I compile a program using the POSIX sem_init() function, I get a compilation warning (error because I normally use -Werror) that the function has been deprecated when I compile on Mac OS X 10.10.1 (Yosemite) with GCC 4.9.1 or the version of Clang (Apple LLVM version 6.0 (clang-600.0.56) (based on LLVM 3.5svn)) from XCode 6.1.1. A quick look at /usr/include/sys/semaphore.h shows that the function does indeed have a __deprecated tag after its declaration, as do sem_getvalue() and sem_destroy().

Questions:

  1. Given that there is no hint of deprecation in the POSIX specification, why are these three functions singled out as deprecated on Mac OS X?

  2. Given that they are deprecated, what is the replacement, and why is the replacement preferred?

(I did check Ask Different first; there are no questions tagged and no questions that ask about deprecated system calls — only programs.)

Answer

dho picture dho · Jan 8, 2015

I ran into this problem myself when trying to port a library I was working on to OS X. I searched for a while without finding a great answer. When I did find the answer, I was a bit perturbed: the answer is effectively "if Apple implemented POSIX unnamed semaphores, how many X Serves would you buy?".

To summarize the points of why they are deprecated and why some of the functionality remains unimplemented:

  • Appendix 9 of the Single UNIX Specification states they are not mandatory interfaces
  • "Most portable code" uses SYSV semaphores
  • Backwards compatibility with POSIX named semaphores, which share the sem_t type is difficult

As for what to do instead, I went with GCD semaphores. As to why the replacement is preferred: it's the only native unnamed semaphore interface available on vanilla OS X. Apparently GCD helped them sell more X Serves. I fear there's not a better answer.

However, hopefully some code will be helpful. The upshot of all of this is that you effectively have to implement your own portable semaphore interface:

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

struct rk_sema {
#ifdef __APPLE__
    dispatch_semaphore_t    sem;
#else
    sem_t                   sem;
#endif
};


static inline void
rk_sema_init(struct rk_sema *s, uint32_t value)
{
#ifdef __APPLE__
    dispatch_semaphore_t *sem = &s->sem;

    *sem = dispatch_semaphore_create(value);
#else
    sem_init(&s->sem, 0, value);
#endif
}

static inline void
rk_sema_wait(struct rk_sema *s)
{

#ifdef __APPLE__
    dispatch_semaphore_wait(s->sem, DISPATCH_TIME_FOREVER);
#else
    int r;

    do {
            r = sem_wait(&s->sem);
    } while (r == -1 && errno == EINTR);
#endif
}

static inline void
rk_sema_post(struct rk_sema *s)
{

#ifdef __APPLE__
    dispatch_semaphore_signal(s->sem);
#else
    sem_post(&s->sem);
#endif
}

This was the minimal set of functionality I cared about; your needs may vary. Hopefully this is helpful.