cstructshared-memory

Error with operations on the elements in shared memory C


I made this code that inserts a structure into shared memory. I made debug prints to try to figure out where the processes were stopping and why there was an error. Apparently by doing operations on the elements in shared memory it goes into error but I don't understand why. How can I solve it?

static shared_pid_data *shared_pid_atom;

static int shmidA;
static int semidA;

void atomSharedPidInit(){
    key_t key = ftok("shmfileA",65);
    printf("atomSharedPidInit - key = ftok\n");
    shmidA = shmget(key, sizeof(shared_pid_data), 0666|IPC_CREAT);
    printf("atomSharedPidInit - shmget\n");
    shared_pid_atom = (shared_pid_data*) shmat(shmidA, (void*)0, 0);
    printf("atomSharedPidInit - shmat\n");
    key_t sem_key = ftok("semfileA", 75);
    printf("atomSharedPidInit - sem_key = ftok\n");
    semidA = semget(sem_key, 1, 0666 | IPC_CREAT);
    printf("atomSharedPidInit - semget\n");
    semctl(semidA, 0, SETVAL, 1);
    printf("atomSharedPidInit - semctl\n");
}

void lockA() {
    struct sembuf sba = {(unsigned short) 0, -1, 0};
    semop(semidA, &sba, 1);
}

void unlockA() {
    struct sembuf sba = {(unsigned short) 0, 1, 0};
    semop(semidA, &sba, 1);
}

void atomSharedPidWrite(pid_t pid) {
    lockA();
    printf("atomSharedPidWrite - lock\n");
    int dim = shared_pid_atom->dimensione;
    printf("atomSharedPidWrite - int dim\n");
    if (dim < 1000) {
        printf("atomSharedPidWrite - if\n");
        shared_pid_atom->atomi_pid[shared_pid_atom->dimensione] = pid;
        shared_pid_atom->dimensione++;
        printf("pid : %d  dimensione : %d ",shared_pid_atom->atomi_pid[shared_pid_atom->dimensione-1],shared_pid_atom->dimensione);
    } else {
        fprintf(stderr, "Shared memory is full\n");
    }
    unlockA();
}

int main (){
    atomSharedPidInit();
    printf("simulazione - atomSharedPidInit\n");
    alarm((unsigned int)sim_duration);
    printf("simulazione - alarm\n");
    print_statistics();

    for (int i = 0; i < n_atomi_init; i++) {
        atomoPID = fork();
        if (atomoPID == 0) {
            printf("Atomo - fork\n");
            srand((unsigned int)(time(NULL) + getpid()));
            printf("Atomo - srand\n");
            atomSharedPidWrite(getpid());
            printf("Atomo - atomSharedPidWrite(getpid())\n");
            
            int numero_atomico = rand() % max_num_atomico + min_num_atomico;
            printf("%d %d %d ", numero_atomico, max_num_atomico, min_num_atomico);
            char num_atomico_str[10];
            sprintf(num_atomico_str, "%d", numero_atomico);
            execl("./atomo", "./atomo", num_atomico_str, NULL);
            exit(0);
        } else if (atomoPID < -1) {
            kill(getpid(), SIGINT);
            exit(EXIT_FAILURE);
        }
    }
}

this is what I get by starting the process:

atomSharedPidInit - key = ftok
atomSharedPidInit - shmget
atomSharedPidInit - shmat
atomSharedPidInit - sem_key = ftok
atomSharedPidInit - semget
atomSharedPidInit - semctl
simulazione - atomSharedPidInit
simulazione - alarm
Current state:
Total energy: 0
Total energy consumed: 0
Total energy available: 0
Total atomi attivi: 0
Total scissions: 0
Total activations: 0
Total scorie: 0
+---------------------------------------------------+
Atomo - fork
Atomo - srand
atomSharedPidWrite - lock
Atomo - fork
Atomo - srand
Atomo - fork
Atomo - srand
Atomo - fork
Atomo - fork
Atomo - srand
Atomo - srand
atomSharedPidWrite - lock
atomSharedPidWrite - lock
atomSharedPidWrite - lock
atomSharedPidWrite - lock
make: *** [Makefile:38: run] Errore di segmentazione (creato dump del core)

even if I do a very banal operation like shared_pid_atom->dimensione = 0; on the shared memory, it doesn't get done. I don't understand why.


Solution

  • I suggest you to check if the returned values of shmidA, semidA and shared_pid_atom are valid: maybe you do not have the permissions to access the shared memory.

    It seems your children processes are dying before the

    int dim = shared_pid_atom->dimensione;
    

    is executed, so maybe the pointer shared_pid_atom isn't valid.

    Furthermore, your lock does not work:

    I checked your code, and once the lock errors are corrected, and the files used for shared resources are existent, the program works OK and I see no need to call the shmget repeatedly, you can use the shared_pid_atom pointer you already have.

    #include <stdio.h>
    #include <stdlib.h>
    #include <inttypes.h>
    #include <sys/shm.h>
    #include <sys/sem.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <time.h>
    #include <signal.h>
    #include <errno.h>
    #include <string.h>
    #include <sys/stat.h>
    
    typedef struct _shared_pid_data
    {
        uint32_t dimensione;
        uint32_t atomi_pid[1000];
    }shared_pid_data;
    
    static shared_pid_data *shared_pid_atom;
    
    static int shmidA;
    static int semidA;
    
    void print_errno_and_die(const char * s)
    {
        const int err = errno;
        printf("%s error: %i, %s\n", s, err, strerror(err));
        exit(0);
    }
    
    void atomSharedPidInit(){
        printf("+%s\n", __func__);
        struct stat statbuf;
        if (stat("./shmfileA", &statbuf) == -1)
        {
            print_errno_and_die("stat");
        }
        key_t key = ftok("./shmfileA",65);
        printf("\tkey: %i\n", key);
        if (-1 == key)
        {
            print_errno_and_die("key ftok");
        }
    
        shmidA = shmget(key, sizeof(shared_pid_data), 0666|IPC_CREAT);
        printf("\tshmidA: %i\n", shmidA);
        if (-1 == shmidA)
        {
            print_errno_and_die("shmget");
        }
    
        shared_pid_atom = (shared_pid_data*) shmat(shmidA, (void*)0, 0);
        printf("\tshared_pid_atom: %p\n", shared_pid_atom);
        if ((void *)-1 == shared_pid_atom)
        {
            print_errno_and_die("shared_pid_atom");
        }
    
        if (stat("./semfileA", &statbuf) == -1)
        {
            print_errno_and_die("stat semfileA");
        }
    
        key_t sem_key = ftok("./semfileA", 75);
        printf("\tsem_key: %i\n", sem_key);
        if (-1 == sem_key)
        {
            print_errno_and_die("sem key");
        }
    
        semidA = semget(sem_key, 1, 0666 | IPC_CREAT);
        printf("\tsemidA has value: %i\n", semidA);
        if (-1 == semidA)
        {
            print_errno_and_die("semidA");
        }
    
        const int ret_semctl =  semctl(semidA, 0, SETVAL, 0);
        printf("\tsemctl returns: %i\n", ret_semctl);
    
        if (ret_semctl < 0)
        {
            print_errno_and_die("semctl");
        }
    
        shared_pid_atom->dimensione = 0;
        printf("-%s\n", __func__);
    }
    
    void lockA() {
        struct sembuf sops[2];
    
        sops[0].sem_num = 0;     
        sops[0].sem_op = 0; // wait for 0
        sops[0].sem_flg = 0;
    
        sops[1].sem_num = 0;
        sops[1].sem_op = 1; // get the semaphore
        sops[1].sem_flg = 0;
    
        if (semop(semidA, sops, 2) == -1) {
            perror(__func__);
            exit(EXIT_FAILURE);
        }
    }
    
    void unlockA() {
    
        struct sembuf sops;
        sops.sem_num = 0;
        sops.sem_op = -1; // unlock the semaphore
        sops.sem_flg = 0;
    
        if (semop(semidA, &sops, 1) == -1) {
            perror(__func__);
            exit(EXIT_FAILURE);
        }
    }
    
    void atomSharedPidWrite(pid_t pid) {
        printf("\t+%s: pid %i\n", __func__, pid);
        printf("\t\tpid %i +lockA\n", pid);
        lockA();
        printf("\t\tpid %i -lockA\n", pid);
        int dim = shared_pid_atom->dimensione;
        if (dim < 1000) {
            shared_pid_atom->atomi_pid[shared_pid_atom->dimensione] = pid;
            shared_pid_atom->dimensione++;
            printf("\t\tpid: %u  dimensione: %" PRIu32 "\n",shared_pid_atom->atomi_pid[shared_pid_atom->dimensione-1],shared_pid_atom->dimensione);
        } else {
            fprintf(stderr, "\tShared memory is full\n");
        }
        printf("\t\tpid %i +unlockA\n", pid);
        unlockA();
        printf("\t\tpid %i -unlockA\n", pid);
        printf("\t-%s: pid %i\n", __func__, pid);
    }
    
    int main (){
        atomSharedPidInit();
    
        const int n_atomi_init = 5;
    
        int atomoPID[n_atomi_init];
        for (int i = 0; i < n_atomi_init; i++) {
            atomoPID[i] = fork();
            if (atomoPID[i] == 0) {
                printf("\tchild %i forked OK with PID %i\n", i, getpid());
                srand((unsigned int)(time(NULL) + getpid()));
                atomSharedPidWrite(getpid());
    
                const int max_num_atomico = 100;
                const int min_num_atomico = 10;
                int numero_atomico = rand() % max_num_atomico + min_num_atomico;
                printf("\tnumeri: %d %d %d\n", numero_atomico, max_num_atomico, min_num_atomico);
                const int wait_ms = rand() % 200;
                printf("\tchild %i is going to die in %i ms\n", i, wait_ms);
                usleep(wait_ms * 1000);
                //char num_atomico_str[10];
                //sprintf(num_atomico_str, "%d", numero_atomico);
                //execl("./atomo", "./atomo", num_atomico_str, NULL);
                exit(0);
            } else if (atomoPID[i] < -1) {
                printf("\tsomething really bad happened on child %i: atomoPID[i] = %i\n", i, atomoPID[i]);
                kill(getpid(), SIGINT);
                exit(EXIT_FAILURE);
            }
        }
    
        printf("MAIN: waiting for the children completed OK\n");
        for (int i = 0; i < n_atomi_init; i++)
        {
            int    wstatus;
            waitpid(atomoPID[i], &wstatus, 0);
            printf("MAIN: child %i completed OK\n", i);
        }
        printf("MAIN: all the children completed OK\n");
        printf("MAIN: dimension is %" PRIu32 "\n", shared_pid_atom->dimensione);
        printf("MAIN: bye\n");
    }
    

    Outoput:

    +atomSharedPidInit
            key: 1093279968
            shmidA: 98346
            shared_pid_atom: 0x7f80684f4000
            sem_key: 1261052132
            semidA has value: 1
            semctl returns: 0
    -atomSharedPidInit
            child 0 forked OK with PID 95059
            +atomSharedPidWrite: pid 95059
                    pid 95059 +lockA
                    pid 95059 -lockA
                    pid: 95059  dimensione: 1
                    pid 95059 +unlockA
                    pid 95059 -unlockA
            -atomSharedPidWrite: pid 95059
            child 1 forked OK with PID 95060
            numeri: 13 100 10
            child 0 is going to die in 136 ms
            +atomSharedPidWrite: pid 95060
                    pid 95060 +lockA
                    pid 95060 -lockA
                    pid: 95060  dimensione: 2
                    pid 95060 +unlockA
                    pid 95060 -unlockA
            -atomSharedPidWrite: pid 95060
            numeri: 76 100 10
            child 1 is going to die in 156 ms
            child 2 forked OK with PID 95061
            +atomSharedPidWrite: pid 95061
                    pid 95061 +lockA
                    pid 95061 -lockA
                    pid: 95061  dimensione: 3
                    pid 95061 +unlockA
                    pid 95061 -unlockA
            -atomSharedPidWrite: pid 95061
            numeri: 21 100 10
            child 2 is going to die in 102 ms
    MAIN: waiting for the children completed OK
            child 3 forked OK with PID 95062
            +atomSharedPidWrite: pid 95062
                    pid 95062 +lockA
                    pid 95062 -lockA
                    pid: 95062  dimensione: 4
                    pid 95062 +unlockA
                    pid 95062 -unlockA
            -atomSharedPidWrite: pid 95062
            numeri: 24 100 10
            child 4 forked OK with PID 95063
            child 3 is going to die in 137 ms
            +atomSharedPidWrite: pid 95063
                    pid 95063 +lockA
                    pid 95063 -lockA
                    pid: 95063  dimensione: 5
                    pid 95063 +unlockA
                    pid 95063 -unlockA
            -atomSharedPidWrite: pid 95063
            numeri: 55 100 10
            child 4 is going to die in 195 ms
    MAIN: child 0 completed OK
    MAIN: child 1 completed OK
    MAIN: child 2 completed OK
    MAIN: child 3 completed OK
    MAIN: child 4 completed OK
    MAIN: all the children completed OK
    MAIN: dimension is 5
    MAIN: bye