Search code examples
clinuxsignals

Sending signal SIGUSR1 and SIGUSR2 from parent to 4 children process?


I have a fork business and I have 4 child processes. I want to send a signal from parent process to each of 4 active child processes before they terminated. If child process id is odd, I send SIGUSR1, otherwise, I send SIGUSR2. I also want to print the receive time of each SIGUSR1 and SIGUSR2 signals in children processes.

Here is my source code:

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

void sigusr1();
void sigusr2();

void main()
{
int status;
pid_t pid[4];
int process_id;

for (int i = 0; i < 4; i++)
{
    pid[i] = fork();

    if (pid[i] == 0)
    {
        process_id = getpid();
        if (process_id % 2 == 1)
        {
            signal(SIGUSR1, sigusr1);
            sleep(1);
        }
        else
        {
            signal(SIGUSR2, sigusr2);
            sleep(1);
        }
        exit(&status);
    }
    else
    {
        printf("\nPARENT: sending SIGUSR1\n\n");
        kill(pid, SIGUSR1);

        printf("\nPARENT: sending SIGUSR2\n\n");
        kill(pid, SIGUSR2);
    }
  }
}

void sigusr1()

{
    signal(SIGUSR1, sigusr1);
    printf("CHILD:  SIGUSR1\n");
    time_t current_time;
    char *c_time_string;
    c_time_string = ctime(&current_time);

    printf("SIGUSR1 received time is %s", c_time_string);
}

void sigusr2()

{
    signal(SIGUSR2, sigusr2);
    printf("CHILD: SIGUSR2\n");

    time_t current_time;
    char *c_time_string;
    c_time_string = ctime(&current_time);
    printf("SIGUSR2 received time is %s", c_time_string);
}

I got following output 4 times:

PARENT: sending SIGUSR1
PARENT: sending SIGUSR2

I cannot get signals in child processes. Can you help me to solve this issue?


Solution

  • When I compile your code, I get a lot of errors – some of them would be warnings except that I use -Werror:

    $ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -fno-common sig31.c -o sig31
    sig31.c:8:1: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
        8 | void sigusr1();
          | ^~~~
    sig31.c:9:1: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
        9 | void sigusr2();
          | ^~~~
    sig31.c:11:6: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
       11 | void main()
          |      ^~~~
    sig31.c:11:6: error: return type of ‘main’ is not ‘int’ [-Werror=main]
    sig31.c: In function ‘main’:
    sig31.c:34:14: error: passing argument 1 of ‘exit’ makes integer from pointer without a cast [-Werror=int-conversion]
       34 |         exit(&status);
          |              ^~~~~~~
          |              |
          |              int *
    In file included from sig31.c:4:
    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdlib.h:145:15: note: expected ‘int’ but argument is of type ‘int *’
      145 | void     exit(int) __dead2;
          |               ^~~
    sig31.c:39:14: error: passing argument 1 of ‘kill’ makes integer from pointer without a cast [-Werror=int-conversion]
       39 |         kill(pid, SIGUSR1);
          |              ^~~
          |              |
          |              pid_t * {aka int *}
    In file included from sig31.c:2:
    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/signal.h:80:14: note: expected ‘pid_t’ {aka ‘int’} but argument is of type ‘pid_t *’ {aka ‘int *’}
       80 | int     kill(pid_t, int) __DARWIN_ALIAS(kill);
          |              ^~~~~
    sig31.c:42:14: error: passing argument 1 of ‘kill’ makes integer from pointer without a cast [-Werror=int-conversion]
       42 |         kill(pid, SIGUSR2);
          |              ^~~
          |              |
          |              pid_t * {aka int *}
    In file included from sig31.c:2:
    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/signal.h:80:14: note: expected ‘pid_t’ {aka ‘int’} but argument is of type ‘pid_t *’ {aka ‘int *’}
       80 | int     kill(pid_t, int) __DARWIN_ALIAS(kill);
          |              ^~~~~
    sig31.c: At top level:
    sig31.c:47:6: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
       47 | void sigusr1()
          |      ^~~~~~~
    sig31.c: In function ‘sigusr1’:
    sig31.c:54:21: error: implicit declaration of function ‘ctime’ [-Werror=implicit-function-declaration]
       54 |     c_time_string = ctime(&current_time);
          |                     ^~~~~
    sig31.c:54:19: error: assignment to ‘char *’ from ‘int’ makes pointer from integer without a cast [-Werror=int-conversion]
       54 |     c_time_string = ctime(&current_time);
          |                   ^
    sig31.c: At top level:
    sig31.c:59:6: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
       59 | void sigusr2()
          |      ^~~~~~~
    sig31.c: In function ‘sigusr2’:
    sig31.c:67:19: error: assignment to ‘char *’ from ‘int’ makes pointer from integer without a cast [-Werror=int-conversion]
       67 |     c_time_string = ctime(&current_time);
          |                   ^
    cc1: all warnings being treated as errors
    

    Most of those are issues I mentioned in comments — the complaint about assignment to ‘char *’ from ‘int’ makes pointer from integer without a cast [-Werror=int-conversion] is because you didn't include <time.h>.

    Here is reworked code. It still ignores the issue of How to avoid using printf() in a signal handler?.

    /* SO 7601-6541 */
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <time.h>
    #include <sys/wait.h>
    
    static void sigusr1(int signum);
    static void sigusr2(int signum);
    
    int main(void)
    {
        pid_t pid[4];
        struct sigaction sa = { 0 };
    
        sa.sa_handler = sigusr1;
        sigaction(SIGUSR1, &sa, 0);
        sa.sa_handler = sigusr2;
        sigaction(SIGUSR2, &sa, 0);
    
        for (int i = 0; i < 4; i++)
        {
            pid[i] = fork();
    
            if (pid[i] == 0)
            {
                sleep(1);
                exit(0);
            }
            else
            {
                /* Snooze for 10 ms */
                nanosleep(&(struct timespec){ .tv_sec = 0, .tv_nsec = 10000000 }, 0);
                if (pid[i] % 2 == 1)
                {
                    printf("PARENT: sending SIGUSR1 to %d\n", pid[i]);
                    kill(pid[i], SIGUSR1);
                }
                else
                {
                    printf("PARENT: sending SIGUSR2 to %d\n", pid[i]);
                    kill(pid[i], SIGUSR2);
                }
            }
        }
    
        int corpse;
        int status;
        while ((corpse = wait(&status)) > 0)
            printf("%d: child %d exited with status 0x%.4X\n", getpid(), corpse, status);
    
        return 0;
    }
    
    static void sigusr1(int signum)
    {
        printf("CHILD %d: %d SIGUSR1\n", getpid(), signum);
        time_t current_time = time(0);
        printf("CHILD %d: SIGUSR1 received - time is %s", getpid(), ctime(&current_time));
    }
    
    static void sigusr2(int signum)
    {
        printf("CHILD %d: %d SIGUSR2\n", getpid(), signum);
        time_t current_time = time(0);
        printf("CHILD %d: SIGUSR2 received - time is %s", getpid(), ctime(&current_time));
    }
    

    When I run that, I get output such as:

    PARENT: sending SIGUSR2 to 56842
    CHILD 56842: 31 SIGUSR2
    CHILD 56842: SIGUSR2 received - time is Fri Apr 14 14:14:24 2023
    PARENT: sending SIGUSR1 to 56843
    CHILD 56843: 30 SIGUSR1
    CHILD 56843: SIGUSR1 received - time is Fri Apr 14 14:14:24 2023
    PARENT: sending SIGUSR2 to 56844
    CHILD 56844: 31 SIGUSR2
    CHILD 56844: SIGUSR2 received - time is Fri Apr 14 14:14:24 2023
    PARENT: sending SIGUSR1 to 56845
    56841: child 56844 exited with status 0x0000
    56841: child 56843 exited with status 0x0000
    56841: child 56842 exited with status 0x0000
    CHILD 56845: 30 SIGUSR1
    CHILD 56845: SIGUSR1 received - time is Fri Apr 14 14:14:24 2023
    56841: child 56845 exited with status 0x0000
    

    Without the 10 ms nanosleep, the child processes were sometimes exiting with status 0x0004 — which indicates they died from signal SIGILL. I didn't experiment with smaller naps than 10 ms.