Home > Blockchain >  sending signals to child processes , SIGCONT ,SIGSTOP
sending signals to child processes , SIGCONT ,SIGSTOP

Time:06-15

I have a problem with my code,

I want all the children stop when the program start. and after that I want just the child with the index of i to continue executing and others to be stopped .

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

#define N 5

void handler(int i)
{
    if (i == SIGCONT)
    {
        printf("signal cont\n");
    }
}
int main()
{
    int pid[N];
    for (int i = 0; i < N; i  )
    {
        if ((pid[i] = fork()) == 0)
        {
            /* code */
            pause();
            while (1)
            {
                printf("ici fils %d\n", i);
                usleep(50000);
            }
        }
        else
        {
            signal(SIGCONT, &handler);
            signal(SIGSTOP, &handler);
            // kill(pid[i], SIGSTOP);
            if (i == N - 1)
            {
                kill(pid[N - 1], SIGCONT);
                sleep(2);
                kill(pid[N - 1], SIGSTOP);
                kill(pid[0], SIGCONT);
            }
            else
            {

                kill(pid[i], SIGCONT);
                sleep(2);
                kill(pid[i], SIGSTOP);
                kill(pid[i   1], SIGCONT);
            }
            // kill(pid[i], SIGKILL);
            waitpid(pid[i], NULL, 0);
        }
    }
}

CodePudding user response:

There are several issues with your code, among them:

  1. Any processes to be stopped via SIGSTOP must not have a handler registered for that signal. Registering a handler causes the handler's behavior to replace the default behavior of stopping the process.

  2. It's usually a bad idea to register a handler for SIGCONT. Doing so will not prevent a SIGCONT from continuing the process, which is a special characteristic of SIGCONT that can be surprising, but also the handler will fire whenever a SIGCONT is delivered, even if the process was not stopped, which is often a different kind of surprise.

  3. You register your signal handlers only in the parent, after the first fork. The subsequently forked children will inherit those, but the first one will not. Among other things, this will prevent the first child's pause() from being unblocked by the signals the parent sends to it. You can make each child register any needed handlers for itself, or you can register them in the parent, before the first fork.

  4. There is a race between each child's pause() and the parent's first kill() targeting that child. It is possible for the child to receive the SIGCONT before it calls pause(), in which case it will wait for the next signal. You can prevent that by blocking SIGCONT in the parent before forking, and using sigsuspend() in the child, with an appropriate mask, instead of the initial pause(). In that case, you probably want to unblock SIGCONT after returning from that initial sigsuspend().

  5. The parent attempts to send signals to processes that it has not forked yet (kill(pid[i 1], SIGCONT);).

It's not clear what the full behavior you are trying to achieve is, but you may want to fork all the children first, and only then start sending signals.

CodePudding user response:

In the child processes, instead of using pause(2), use raise(3) to signal the calling process to stop with SIGSTOP. There is no real need to register signal handlers.

In the parent process, after creating a child, wait for it to stop by using waitpid(2) with the WUNTRACED flag set. The WIFSTOPPED(...) macro can be used to specifically determine the status of the child.

Here is a cursory example, with no meaningful error handling. Note that concurrent sleeps, while simple, are not technically a consistent way to schedule things. The output of this program may differ slightly between executions.

#define _POSIX_C_SOURCE 200809L
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

#define CHILDCOUNT 5

pid_t create_child(void) {
    pid_t pid = fork();

    if (!pid) {
        /* child */
        raise(SIGSTOP);

        pid_t self = getpid();
        printf("SIGCONT in %d\n", self);

        while (1) {
            printf("RUNNING in %d\n", self);
            sleep(1);
        }

        /* bug net */
        exit(EXIT_SUCCESS);
    }

    return pid;
}

int main(void) {
    pid_t pids[CHILDCOUNT];

    for (size_t i = 0; i < CHILDCOUNT; i  ) {
        pid_t current = pids[i] = create_child();

        printf("Parent now has child (%d).\n", current);

        int status;
        waitpid(current, &status, WUNTRACED);

        if (WIFSTOPPED(status))
            printf("P: C(%d) STOPPED!\n", current);
    }

    for (size_t i = 0; i < CHILDCOUNT; i  ) {
        pid_t current = pids[i];

        printf("P: C(%d) STARTING.\n", current);
        kill(current, SIGCONT);
        sleep(3);
        kill(current, SIGKILL);
    }

    for (size_t i = 0; i < CHILDCOUNT; i  ) {
        int status;
        waitpid(pids[i], &status, WUNTRACED);

        if (WIFSIGNALED(status) && SIGKILL == WTERMSIG(status))
            printf("P: C(%d) SUCCESSFULLY KILLED!\n", pids[i]);
    }
}
  • Related