4

I have a problem with some simple code I'm writing to teach myself about semaphores and POSIX shared memory.

The idea is that one program, the server, opens the shared memory and writes a structure (containing a semaphore and an array) to it. Then it waits for input and after input increments the semaphore.

Meanwhile the client opens the shared memory, waits on the semaphore, and after it is incremented by the server, reads the structure.

The server seems to work okay, however I am encountering a segfault in the client at the sem_wait function, immediately (even before the server increments it). I can't figure out what is wrong.

Server code:

#define _XOPEN_SOURCE 500

#include <stdio.h>

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <unistd.h>
#include <sys/types.h>

#include <semaphore.h>

#include <stdbool.h>

#define ARRAY_MAX 1024

typedef struct {
    sem_t inDataReady;
    float array[ARRAY_MAX];
    unsigned arrayLen;
} OsInputData;

int main() {

    int shm_fd;
    OsInputData *shm_ptr;

    if((shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0666)) == -1) {
        printf("shm_open failure\n");
        return 1;
    }

    if(ftruncate(shm_fd, sizeof(OsInputData)) == -1) {
        printf("ftruncate failure\n");
        return 1;
    }

    if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
        printf("mmap failure\n");
        return 1;
    }

    sem_init(&(shm_ptr->inDataReady), true, 0);

    shm_ptr->array[0] = 3.0;
    shm_ptr->array[1] = 1.0;
    shm_ptr->array[2] = 2.0;
    shm_ptr->array[3] = 5.0;
    shm_ptr->array[4] = 4.0;

    shm_ptr->arrayLen = 5;

    getchar();
    sem_post(&(shm_ptr->inDataReady));

    sem_destroy(&(shm_ptr->inDataReady));

    munmap(shm_ptr, sizeof(OsInputData));
    close(shm_fd);

    return 0;
}

Client code:

#define _XOPEN_SOURCE 500

#include <stdio.h>

#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <unistd.h>
#include <sys/types.h>

#include <semaphore.h>

#include <stdbool.h>

#define ARRAY_MAX 1024

typedef struct {
    sem_t inDataReady;
    float array[ARRAY_MAX];
    unsigned arrayLen;
} OsInputData;

int main() {

    int shm_fd;
    OsInputData *shm_ptr;

    if((shm_fd = shm_open("/my_shm", O_RDONLY, 0666)) == -1) {
        printf("shm_open failure\n");
        return 1;
    }

    if((shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ, MAP_SHARED, shm_fd, 0)) == MAP_FAILED) {
        printf("mmap failure\n");
        return 1;
    }

    sem_wait(&(shm_ptr->inDataReady));

    printf("%u\n", shm_ptr->arrayLen);

    munmap(shm_ptr, sizeof(OsInputData));
    close(shm_fd);

    return 0;
}

2 Answers 2

4

The actual outcome depends upon your system, but in general your program contains an error. You can’t destroy a semaphore that is reachable by another process/thread. Just because you have executed a sem_post doesn’t mean that your system has switched to the process waiting for it. When you destroy it, the other guy might still be using it.

SIGSEGV, in this case, is a kindness. Few programmers check the return values of sem_wait, which can lead to programs thinking they are synchronized when they are not.

Sign up to request clarification or add additional context in comments.

2 Comments

If that's the case, how would I go about fixing it? Though I'm not sure it is the case, since 1) getchar should block the server from continuing (and destroying the semaphore), and the client segfault happens before this; and 2) commenting out the sem_destroy line does nothing to help. I also wrapped sem_init, sem_post and sem_wait functions in error checks, but they don't return an error.
Synchronization objects should follow a similar pattern to RAII (resource acquisition is initialization) which tracks the number of outstanding references to an object. To destroy it, it must first become undiscoverable, then when its reference count hits zero, it is safe to destroy things like sync variables. The future will thank you.
1

Turns out I had to open the shared memory in the client with both read and write permissions, as well as update the protections accordingly in mmap.

Quite a stupid mistake, as it's obvious the client needs write permissions as well to actually modify the semaphore.

So in the client code the following changes solved it

...
shm_fd = shm_open("/my_shm", O_CREAT | O_RDWR, 0755)
...
shm_ptr = (OsInputData*)mmap(0, sizeof(OsInputData), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0)
...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.