Monday, 2 September 2013

Unnamed semaphores and POSOSX

During the development of my bitcoin mining software, cgminer, I've used just about every synchronisation primitive due to it being heavily multithreaded. A few months back I used some semaphores and the first thing I reached for was the much more useful unnamed semaphores commonly in use today. Classic SYSV IPC semaphores are limited in number, require allocating of shared memory, stay in use till destroyed or the system rebooted etc. etc. that make them real awkward to use and far less flexible so I never even considered using them. For some reason, though, I had a vague memory of trying to use them on lrzip years ago and deciding not too. Well that memory came back to bite me.

Cgminer is cross platform, working reasonably well on various architectures with Linux, windows (via mingw32) and OSX mainly, though other brave souls have used it on all sorts of things. I've often heard OSX described as the "Fischer Price" unix, AKA "My first unix" because of its restricted subset of unix capabilities that it has, although I'm led to believe it claimed to have POSIX compliance at some stage - though I never really investigated it nor does it really matter since Linux is only POSIXy at best.

So the interesting thing was that I had written some code for cgminer which used unnamed semaphores and it compiled fine across the 3 main platforms, but it failed miserably when it came to working on OSX. Of note, the unnamed semaphore functions conform to POSIX.1-2001. All of the functions compiled perfectly fine, but the application refused to run properly, and finally when I got some of the OSX users to investigate further, every single unnamed semaphore function, such as sem_init, sem_post, sem_wait etc, would return a unique OSX error which when deciphered it was actually "Unimplemented feature". Quite amusing that to get POSIX compliance it only had to implement the functions, but not the actual features of those functions... You may go wild with speculation as to why this may be. This is why I coined the term POSOSX.

After toying with the idea of using SYSV semaphores and being disgusted at the thought, I finally decided that I should just implement really basic fake unnamed semaphores using pipes on OSX to imitate their behaviour.

Simplified code from cgminer for OSX follows (real code checks return values etc.):

struct cgsem {
    int pipefd[2];

typedef struct cgsem cgsem_t;

void cgsem_init(cgsem_t *cgsem)
    int flags, fd, i;


    /* Make the pipes FD_CLOEXEC to allow them to close should we call
     * execv on restart. */
    for (i = 0; i < 2; i++) {
        fd = cgsem->pipefd[i];
        flags = fcntl(fd, F_GETFD, 0);
        flags |= FD_CLOEXEC;
        fcntl(fd, F_SETFD, flags);

void cgsem_post(cgsem_t *cgsem)
    const char buf = 1;

    write(cgsem->pipefd[1], &buf, 1);

void cgsem_wait(cgsem_t *cgsem)
    char buf;

    read(cgsem->pipefd[0], &buf, 1);

void cgsem_destroy(cgsem_t *cgsem)


  1. Those functions are optional, according to the standard.

    [SEM] Semaphores
    The functionality described is optional. The functionality described is also an extension to the ISO C standard.

    Where applicable, functions are marked with the SEM margin legend in the SYNOPSIS section. Where additional semantics apply to a function, the material is identified by use of the SEM margin legend.


    1. Thanks. The real question is why implement a function that always returns an error unsupported function?

    2. It's probably returning an ENOSYS error, which I believe would be considered best practice for unimplemented functions in a POSIX environment. That is, it's not odd that they do this, it would be odd if they didn't do this.

  2. Nobody except you has called it "Fisher Price Unix". I have been on an Apple for years and never heard that.

    1. I'm sorry if I've offended the Apple people then.


    That is why and it is a perfectly ok why.