0

I wrote a code that creates a child with a fork(). The parent of this child should sent a SIGUSR1/2 to its CHILD and the child should answer with a SIGUSR2/1.

This is the code:

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

void HDL_PSIGUSR(int sig) {
    printf("Signal 0x%x received.\n\n", sig);
    fflush(stdout);
}

void HDL_SSIGUSR(int sig) {
    if (sig == SIGUSR1) {
        printf("PID %d -> PID %d: 0x%x\n", getpid(), getppid(), SIGUSR2);
        kill(getppid(), SIGUSR2);
    } else if (sig == SIGUSR2) {
        printf("PID %d -> PID %d: 0x%x\n", getpid(), getppid(), SIGUSR1);
        kill(getppid(), SIGUSR1);
    }

    fflush(stdout);
}

void HDL_SSIGINT(int sig) {
    kill(getppid(), SIGINT);
}

void son() {

    signal(SIGUSR1, HDL_SSIGUSR);
    signal(SIGUSR2, HDL_SSIGUSR);
    signal(SIGINT, HDL_SSIGINT);
    signal(SIGALRM, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);

    while (true) {
        pause();
    }

}

int main() {
    int* _buf, n, i, t, timer = 0;
    pid_t pid;
    char buff[1000];

    printf("Number of signals to send: ");
    scanf("%d", &n);

    printf("Interval time: ");
    scanf("%d", &t);

    printf("Signals to send: ");

    _buf = malloc(n * sizeof *_buf);
    for (i = 0; i < n; i++) {
        scanf("%d", &_buf[i]);
    }

    fflush(stdout);

    if (pid = fork()) {

        signal(SIGUSR1, HDL_PSIGUSR);
        signal(SIGUSR2, HDL_PSIGUSR);

        i = 0;
        while (true) {
            i %= n;
            //sprintf(buff, "kill -USR1 %d", pid);
            //system(buff);
            kill(pid, SIGUSR1);
            sleep(t);
        }

    } else {
        son();
        exit(0);
    }

    waitpid(pid, (int*)0, 0);
    return 0;
}

The problem is that if I use the kill() system call, the child process become a zombie process. Instead, if I use the system() system call and calling from there the command kill on CHILD PID, it works! Why?

  • 1
    [Signal handlers can only safely call async-signal-safe functions](https://stackoverflow.com/questions/46354925/why-only-async-safe-functions-should-be-called-from-a-signal-handler). `printf()` and `fflush()` are not asynic-signal-safe. – Andrew Henle Nov 27 '18 at 17:42
  • You also have a race condition where the child process can receive a signal from the parent before it installs a handler for that signal, which would explain why it's terminating. – Shawn Nov 27 '18 at 18:09
  • Most likely, your problem is one of timing. The parent process probably sends the signal before the child sets its signal handlers, and therefore dies because that's the default behaviour. Try adding `sleep(1);` in the parent code before you send the signal to the child. – Jonathan Leffler Nov 27 '18 at 18:10
  • 1
    Processes are gender neutral. `son` should be named `child` – William Pursell Nov 27 '18 at 19:02
  • @WilliamPursell Yeah I know, but I was too ungry in that moment to use a right name – Salvatore Gabriele La Greca Nov 27 '18 at 19:14

1 Answers1

0

Thank you guys! The problem was as said by @Jonathan Leffler and @Shawn. It can be solved with a sleep(1); in the parent process before starting to send signals. I modified my code as shown here:

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

bool startProg = false;

void HDL_PSIGUSR(int sig) {

    if (!startProg) {
        startProg = true;
        return;
    }

    printf("Received signal 0x%x\n", sig);
    fflush(stdout);
}

void HDL_SSIGUSR(int sig) {
    kill(getppid(), (sig == SIGUSR1) ? SIGUSR2 : SIGUSR1);
}

void HDL_SSIGINT(int sig) {
    kill(getppid(), SIGINT);
}

void son() {

    signal(SIGUSR1, HDL_SSIGUSR);
    signal(SIGUSR2, HDL_SSIGUSR);
    signal(SIGINT, HDL_SSIGINT);
    signal(SIGALRM, SIG_IGN);
    signal(SIGCHLD, SIG_IGN);

    kill(getppid(), SIGUSR1);

    while (true) {
        pause();
    }

}

int main() {
    int* _buf, n, i, t;
    pid_t pid;

    printf("Number of signals to send: ");
    scanf("%d", &n);

    printf("Interval time: ");
    scanf("%d", &t);

    printf("Signals to send: ");

    _buf = malloc(n * sizeof *_buf);
    for (i = 0; i < n; i++) {
        scanf("%d", &_buf[i]);
    }

    fflush(stdout);

    if (pid = fork()) {

        signal(SIGUSR1, HDL_PSIGUSR);
        signal(SIGUSR2, HDL_PSIGUSR);

        while (!startProg) {
            pause();
        }

        i = 0;
        while (true) {
            i %= n;

            kill(pid, _buf[i++]);
            pause();
            sleep(t);
        }

    } else {
        son();
        exit(0);
    }

    waitpid(pid, (int*)0, 0);
    return 0;
}