1
votes

I am trying to test how quick can the process catch a signal, so I write a simple C code.

In my code, I fork N processes, each child process register a handler, which is triggered by SIGUSR1 and wait for signal SIGUSR2. The waiting time between catching SIGUSR1 and SIGUSR2 is what I want. I am trying to record the moment catching SIGUSR2 to a shared memory or a global random variable first.

The problem I met is I cannot modify the value of global variable or shared memory. Another thing also confuse me, I also set a timer in main process, which also use SIGVTALRM to trigger handler and modify a global variable. But it works.

Here is my code, and thanks for your help!

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <time.h>
#include <signal.h>
#include <sys/time.h>
#include <string.h>
#include <sys/shm.h>

#define N 3
#define SHMSIZE 20 

int count = 0;
int record[N];
char* shm;
int test = 0;

void timer_handler(int signum)
{
    ++count;
}

void handler2 (int signum)
{
    printf("%d ends, use %d usecs.\n", getpid(), count);
    *shm = count;
    test+=1;
}

void handler (int signum)
{
    signal(SIGUSR2, handler2); 
    printf("%d begin \n", getpid());
    kill(getpid(),SIGUSR2);
}

void child(int process_index)
{
    struct sigaction sa;

    /* Register */
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = handler;
    sigaction(SIGUSR1, &sa, NULL);

    printf("I am %d.\n", getpid());
    sleep(3);

    exit(0);
}

int main()
{
    int i, k, status, shmid;
    pid_t pid[N];
    pid_t pid_wait;
    struct sigaction sa_main;
    struct itimerval timer;
    key_t key = 123;
    char* shm;

    /* Create shared memory */
    if ((shmid = shmget(key, SHMSIZE, IPC_CREAT|666)) <0)
            {perror("shmget"); exit(1);}

    /* attach shm */
    if ((shm = shmat(shmid, NULL, 0)) == (char*)-1)
    {
        perror("shmat");
        exit(1);
    }

    /* Init Shm Value */
    *shm = '0';

    /* Register */
    memset(&sa_main, 0, sizeof(sa_main));
    sa_main.sa_handler = timer_handler;
    sigaction(SIGVTALRM, &sa_main, NULL);
    signal(SIGUSR1, SIG_IGN);

    /* Config timer */
    timer.it_value.tv_sec = 0;
    timer.it_value.tv_usec = 1;
    timer.it_interval.tv_sec = 0;
    timer.it_interval.tv_usec = 1;

    /* Start a virtual timer */
    setitimer( ITIMER_VIRTUAL, &timer, NULL);

    printf(" Main pid is:%d\n", getpid());
    /* Do k times */
    for (k=0;k<3;k++) 
    {

        for (i=0;i<N;i++)
        {
            pid[i] = fork();
            if (pid[i]==0)
            {
                child(i);
            }
        }

        sleep(2);
         kill(0, SIGUSR1);

        for (i=0;i<N;i++)
        {
            do
            {
                pid_wait = waitpid(pid[i], &status, WNOHANG);
                printf("I am waiting..\n");
                sleep(1);
            }while(pid_wait != pid[i]);
        }

        printf("the record is: %d\n", *shm);
        printf("test is:%d\n", test);
    }
    printf("all done\n");

    /* Detach shared memory */
    shmdt(shm);

    /* destroy shared memory */
    printf("shared memory destroyed!\n");
    int retval = shmctl(shmid, IPC_RMID, NULL);
    if (retval <0)
    {
        fprintf(stderr, "remove shared memory fail..\n");
        exit(1);
    }

    return 0;
}
1
Writing to the shared-memory-segment should be possible, I also do not see an error (except that *shm only has the size of a char). On the contrary, communicating through global variables is not possible, since every instance of the process has private memory (cow) there. You would have to use threads to do that. - Ctx
I think the value of global variable should not be zero, it might be one of value of one of process assign..? - KennyYang
As I said, modifications of the global variable in one process will not be reflected in the others, since each process has its own instance of test. You would have to use threads to change this behaviour and only have one instance of test shared by all processes - Ctx
printf() is not async-signal-safe. Using it in a signal handler invokes undefined behavior. See man7.org/linux/man-pages/man7/signal.7.html - Andrew Henle
@KennyYang well, printf() doesn't trouble me. Yet. - Andrew Henle

1 Answers

0
votes

I've noticed that I cannot modify value without passing shared memory as an argument. So, my solution is passing the modified global value from handler to child process, and modify shared memory.

Thanks for all your help!