Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sigwait() repeatedly unblocked by SIGUSR1

I am writing a program that takes a list of UNIX commands from a file and executes them sequentially. To keep everything in order, I must have each command initialized and kept waiting for SIGUSR1 via sigwait(). When every command is initialized, then every command can execute.

Usage: > program.c input.txt

However, it appears that SIGUSR1 is repeatedly called, completely surpassing sigwait(). What is going on here? I've tried so many different things, but it's recently modeled after this answer. To rephrase, I want the signal to be raised for commands immediately after initialization. I want the signal to be unblocked when all commands are completely initialized

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>


void on_sigusr1(int sig)
{
// Note: Normally, it's not safe to call almost all library functions in a
// signal handler, since the signal may have been received in a middle of a
// call to that function.
    printf("SIGUSR1 received!\n");
}

int main(int arc, char* argv[])
{


    FILE *file;
    file = fopen(argv[1] ,"r");

    int BUF_SIZE = 100; 

    char *token;
    char buffer[BUF_SIZE];
    char programs[BUF_SIZE];
    char *commands[BUF_SIZE];

    int i = 0;
    int counter = 1;

    while (fgets(buffer, sizeof buffer, file ) != NULL)
    {
        strcpy(programs, buffer);

        int length = strlen(buffer)-1;
        if (buffer[length] == '\n') 
        {
            buffer[length] = '\0';
        }

        i = 0;
        token = strtok(buffer," ");
        while(token != NULL)
        {
            commands[i++] = token;
            token = strtok(NULL, " ");
        }
        commands[i] = 0;

        pid_t pids[counter];


        // Set a signal handler for SIGUSR1
        signal(SIGUSR1, &on_sigusr1);

    // At program startup, SIGUSR1 is neither blocked nor pending, so raising it
    // will call the signal handler
        raise(SIGUSR1);

    // Now let's block SIGUSR1
        sigset_t sigset;
        sigemptyset(&sigset);
        sigaddset(&sigset, SIGUSR1);
        sigprocmask(SIG_BLOCK, &sigset, NULL);

    // SIGUSR1 is now blocked, raising it will not call the signal handler
        printf("About to raise SIGUSR1\n");
        raise(SIGUSR1);
        printf("After raising SIGUSR1\n");


        for(i = 0; i < counter; ++i)
        {
            pids[i] = fork();

            if(pids[i] > 0)
            {
                printf("Child process %d ready to execute command %s", getpid(), programs);
                // SIGUSR1 is now blocked and pending -- this call to sigwait will return
                // immediately
                int sig;
                int result = sigwait(&sigset, &sig);
                if(result == 0) {
                    printf("Child process %d executing command %s", getpid(), programs);
                    execvp(commands[0], commands);   
                }
            }
        }

        // All programs have been launched
        for(i = 0; i < counter; ++i)
        {
            wait(&pids[i]);
        }

        // All programs are waiting to execute
        for (i = 0; i < counter; ++i)
        {
        // SIGUSR1 is now no longer pending (but still blocked).  Raise it again and
        // unblock it
            raise(SIGUSR1);
            printf("About to unblock SIGUSR1\n");
            sigprocmask(SIG_UNBLOCK, &sigset, NULL);
            printf("Unblocked SIGUSR1\n");
        }
    }

exit(0);
fclose(file);   
return 0;
}

UPDATE: Tried changing signal() to sigaction(). No change.

like image 376
Miss Rainbowdash Avatar asked Nov 09 '22 23:11

Miss Rainbowdash


1 Answers

You should consider calling sigwait after checking to see if that pid is a child process.

So maybe put

int sig;

and

int result = sigwait(&sigset, &sig);

within an if statement that checks if the pid is == 0 which would indicate that it is a child. Otherwise you would be sigwaiting a parent process.

If the pid is greater than 0 it's a parent process id and if it's less than zero its an error.

Then for each process in your array of pids you would call kill(pid_array[i], SIGUSR1) to unblock it.

like image 156
chups Avatar answered Dec 07 '22 19:12

chups