cheshire
cheshire

Reputation: 1159

Handling SIGINT with shared memory and semaphores

I tried to write a shared memory and semaphores program that runs until Ctrl+C is pressed i.e. SIGINT is received:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <signal.h>
#include <semaphore.h>

#define SHM_NAME "/shm"
#define SEM_1 "/sem_1"
#define SEM_2 "/sem_2"
#define SEM_3 "/sem_3"

static volatile sig_atomic_t run;

struct sharedMemory{
    int done;
};
static struct sharedMemory *shared;

static void handleSIGINT(int sig){
    if(sig == SIGINT){
       printf(" SIGINT caught: sig = %d\n", sig);
       shared->done = 1;
       run = 1;
    }
}

int main(int argc, char *argv[])
{
    // setup shared memory and semaphores
    int shmfd = shm_open(SHM_NAME, O_RDWR | O_CREAT, 0600);
    if (shmfd == -1){
        // handle error 
    }

    if (ftruncate(shmfd, sizeof(struct sharedMemory)) == -1){
        // handle error 
    }

    shared = mmap(NULL, sizeof(*shared), PROT_READ | PROT_WRITE, MAP_SHARED, shmfd, 0);
    if (shared == MAP_FAILED){
       // close resources
    }

    sem_t *sem_read = sem_open(SEM_1, O_CREAT | O_EXCL, 0600, 0);
    sem_t *sem_write = sem_open(SEM_2, O_CREAT | O_EXCL, 0600, BUFFER_SIZE);
    // sem open error handling
    if (sem_read == SEM_FAILED)
       // close resources 

    if (sem_write == SEM_FAILED)
       // close resources 

    // settup signal handler
    signal(SIGINT, handleSIGINT);

    while (!run)
    {
        sem_wait(sem_read);

        // read from shared memory and store data or set shared->done to 1 to stop generator process

        sem_post(sem_write);
    }

    // close resources
    printf("exiting\n");
    exit(EXIT_SUCCESS);
}

When Ctrl+C is pressed volatile run is set to 1 and it breaks out of loop and exits. This works fine without shared memory and semaphores, but here I never get exiting string on stdout only SIGINT caught: sig = 2 and it continues to run.

Why?

Upvotes: 1

Views: 760

Answers (1)

kaylum
kaylum

Reputation: 14046

The reason for the behaviour you are seeing is the way the signal handler is being installed:

signal(SIGINT, handleSIGINT);

By default, signal enables the SA_RESTART flag. Which means that the sem_wait will be restarted after the signal handler has been called.

This is one of the main reasons for using sigaction instead of signal. Change the above line to the below code and it should work as you require.

struct sigaction saction;
saction.sa_handler = handleSIGINT;
sigemptyset(&saction.sa_mask);
saction.sa_flags = 0;
sigaction (SIGINT, &saction, NULL);

Not directly part of your question but it is advisable to call sem_unlink on SEM_1 and SEM_2 as well as check the return values of the sem_open calls. Since O_EXCL is set in the sem_open it will fail if you run the program again after force terminating a previous invocation with kill.

Upvotes: 4

Related Questions