Search code examples
clinuxsegmentation-faultipc

Why am i getting segmentation fault when trying IPC using shared memory in c linux


problem: implement IPC between 3 processes in a way that the first process create the shared memory and then sends a signal to the second and third processes so they can get attached to that shared memory, now make the second process write something to the shared memory and then make it send a signal to the third process so that the third process reads what the second process had written.

my code:

#include <signal.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/ipc.h> 
#include <sys/shm.h> 
#include <sys/types.h> 
#include <unistd.h> 

static int pid0, pid1, pid2, shmid, status;

struct memory { 
    char msg[100];
}; 

struct memory* shmptr; 
struct sigaction act0, act1, act2;

// Handler For P0
void handler0(int signum) 
{ 
    if (signum == SIGUSR1) { 
        printf("Allowing P1 And P2 To Get Attached\n\n");
        kill(pid1, SIGUSR1); // Allow P1 To Get Attached
        kill(pid2, SIGUSR1); // Allow P2 To Get Attached
    } 

    if (signum == SIGUSR2) { 
        kill(pid1, SIGINT); // Kill P1 
        kill(pid2, SIGINT); // Kill P2 
    } 
} 

// Handler For P1
void handler1(int signum) 
{ 
    if (signum == SIGUSR1) { 
        
        // Attaching To The Shared Memory 
        shmptr = (struct memory*) shmat(shmid, 0, 0); 

        printf("P1 - Attached to: %d\n\n", shmid); 
    } 
} 

// Handler For P2
void handler2(int signum) 
{ 
    if (signum == SIGUSR1) { 
        
        // Attaching To The Shared Memory 
        shmptr = (struct memory*) shmat(shmid, 0, 0); 

        printf("P2 - Attached to: %d\n\n", shmid); 
    } 

    if (signum == SIGUSR2) { 

        printf("Message Read From Shared Memory Is: "); 
        puts(shmptr->msg); 

        status = 1;

        // Detaching P2 From The Shared Memory
        shmdt((void*)shmptr);
        
        kill(pid0, SIGUSR2);
    }
} 

int main() 
{
    status = 0;

    printf("P0\n\n");

    pid0 = getpid();

    // Key Of Shared Memory 
    key_t key = 123456;

    // Shared Memory Creation
    printf("Creating Shared Memory\n\n"); 
    shmid = shmget(key, sizeof(struct memory), IPC_CREAT | 0666); 

    // Attaching P0 To The Shared Memory 
    shmptr = (struct memory*)shmat(shmid, 0, 0); 
    printf("P0 - Attached to: %d\n\n", shmid);

    // Attaching Handler Function To Signal SIGUSR1 For Process 0
    act0.sa_handler = handler0;
    sigaction(SIGUSR1, &act0, NULL);
    printf("Forking...\n\n");
    
    pid1 = vfork();

    if(pid1 == 0){ // Inside P1

        printf("P1\n\n");
        
        // Attaching Handler Function To Signal SIGUSR1 For Process 1
        act1.sa_handler = handler1;
        sigaction(SIGUSR1, &act1, NULL);

        pid2 = vfork();

        if(pid2 == 0){ // Inside P2

            printf("P2\n\n");

            // Attaching Handler Functions To Signals SIGUSR1 And SIGUSR2 For Process 2
            act2.sa_handler = handler2;
            sigaction(SIGUSR1, &act2, NULL);
            sigaction(SIGUSR2, &act2, NULL);
            kill(pid0, SIGUSR1); // Tell P0 That P1 And P2 Are Ready To Get Attached To The Shared Memory
            
        } else { // Inside P1

            printf("P1 Again\n\n");

            // Writing A Message To The Shared Memory
            printf("Enter A Message: \n");
            fgets(shmptr->msg, 100, stdin); 

            // Sending The Message To Process 2
            kill(pid2, SIGUSR2); 
            printf("Sent Message To P2\n\n"); // this gets printed and then a segmentation fault error occurs
        }

    } else { // Inside P0
    
        printf("P0 - Waiting..\n\n");
        while(1){
            if(status == 1)
                break;
        }
        // Detaching P0 From The Shared Memory
        shmdt((void*)shmptr);

        shmctl(shmid, IPC_RMID, (struct shmid_ds *) NULL);
    }
}

after executing the printf("Sent Message To P2\n\n"); i get a segmentation fault error

please tell me why, i couldn't figure it out

thanks


Solution

  • You can't do this with vfork().

    Read the man page, especially the part near the top where it says

    the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type pid_t used to store the return value from vfork(), or returns from the function in which vfork() was called, or calls any other function before successfully calling _exit(2) or one of the exec(3) family of functions.