Search code examples
cposixsemaphoreshared-memory

POSIX unnamed semaphore in shared memory is not responding to post or wait


I have unnamed semaphores that I am placing in shared memory in one process following the method that I found here on SO

In P0:

/* addr is a pointer to the base of the shared memory area */
sem_t *sem = (sem_t*) addr;
void *usableSharedMemory = (char*) addr + sizeof(sem_t)
sem_init(sem, 1, 0);

In P1:

if ((addr = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
  exit(EXIT_FAILURE);
}

sem_t *my_sem = (sem_t*) addr;
...
sem_post(my_sem);
...
sem_wait(my_sem);

If I call sem_getvalue(my_sem) before and after a post or wait, the value of the semaphore does not change. I have prints like this to debug:

int v = 0;
v = sem_getvalue(rsem, &v);
printf("BEFORE-POST:%d\n", v);
sem_post(rsem);
v = sem_getvalue(rsem, &v);
printf("AFTER-POST:%d\n", v);

Before and after the call to sem_post, the semaphore value is zero (0).


Solution

  • I haven't used this kind of semaphore before, but I see a number of things one could trip over.

    I'm not excited about the funky pointer math that the other SO post was suggesting, and I can't tell from here whether both processes are actually talking to the same chunk of shared memory.

    A good idea in this case is to avoid the pointer math and use a struct to overlay the shared memory segment so you have a clear organization, and add a magic number so everybody can tell if they're getting a valid segment or some random bogus memory:

    #define MYSHM_MAGIC 12345987  // can be anything random-ish
    
    struct mysharedmem {
        int     magicvalue;
        sem_t   MySemaphore;
        void    *UsableMemory;
    };
    

    This structure overlays whatever your shared memory segment is and allows you to use consistent and more readable access methods, especially if you add additional variables that all sides agree on. The code that creates the segment should initialize it:

    // in P1 ?
    struct mysharedmem *myshm = mmap(NULL, SIZE, ...);
    
    myshm->magic = MYSHM_MAGIC;
    sem_init(&myshm->MySemaphore, 1, 0);
    ...
    

    and then in the other process, once you obtain the shared address, actually ask the segment "did you come from the place I think?" by checking the magic number. The value of the number doesn't matter, only that both sides agree.

    // In P0 ?
    struct mysharedmem *myshm = addr; // obtained somehow
    
    if (myshm->magic != MYSHM_MAGIC)
    {
        error - we don't see the special magic number
    }
    .. do stuff
    

    How does P0 obtain a handle to the shared memory segment created by the P1?