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;
}
test. You would have to use threads to change this behaviour and only have one instance of test shared by all processes - Ctxprintf()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