Programming Forums

Programming Forums (http://www.programmingforums.org/forumindex.php)
-   C++ (http://www.programmingforums.org/forum15.html)
-   -   unix signal processing (http://www.programmingforums.org/showthread.php?t=12180)

Ghosty Dec 14th, 2006 2:09 AM

unix signal processing
 
The following is a program I'm trying to get working. My problem isn't the code itself. I can't seem to understand signal handling no matter what I read or try. Will someone please help me understand how to handle signals?

The following program spawns three processes which are passed as arguments. The program is suppose to initially spawn each process and then restart each of the processes (up to 4 times) when the SIGCHLD signal is received.

Please note that the p1xxx variables aren't being used at the moment and I'm aware of this fact. I originally had this program working using the waitpid() and the WNOHANG option (no signal handling) and I was using the p1xxx variables as counters.

:

#include <iostream>
#include <unistd.h>
#include <sys/wait.h>

using namespace std;

void sig_handler( int signo ); //signal handler
int spawnProcess(char *name); //spawns a particular process by name, returns PID
void syserr(const char *msg); //ignore this

int main(int argc, char * argv[]) {
        if(argc != 4){
                cerr << "Lab5: Program takes 3 processes as arguments" << endl;
                //syserr("Program takes 3 arguments");
                return 1;
        }

        //Initial spawn of our processes
        int pids[3];
        for(int i = 1; i < 4; i++){
                pids[i-1] = spawnProcess(argv[i]);
        }

        //Keep track of how many times each process has been restarted
        int p1Res=1, p2Res=1, p3Res=1;

  struct sigaction act;

        act.sa_handler = sig_handler;
        sigemptyset( &act.sa_mask );
        act.sa_flags = SA_NOCLDWAIT;

        if( sigaction( SIGCHLD , &act, NULL ) == -1 ) {

            perror( "sigaction" );
            exit( 1 );
        }

        cout << "Parent has exited" << endl;
return 0;
}


These are the functions
:

void sig_handler( int signo ) {
        }

//Spawn the process "name" and return its PID
int spawnProcess(char *name) {
        int pid;
        switch( (pid = vfork()) ){
                case -1:
                        //syserr("vfork");
                        cerr << "Error calling vfork()" << endl;
                        return 1;
                case 0:
                        if(execl(name, NULL) == -1){
                        //syserr("execl");
                        cerr << "Error calling execl" << endl;
                        return 1;
                        }
        };
return pid;
}


Thank you for your time.

Game_Ender Dec 14th, 2006 2:43 AM

Its late so you get no explanation but this. You set up the signal handler properly you just needed to actual check on the child processes in and start back up the right one. I use some global data so the signal handler would know what pids to check each time. You also need to sleep the parent so it can wait for the children. (sorry for mixed tabs and spaces, but I use spaces ;))

:

#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/wait.h>

using namespace std;

// These need to be global so the signal handler can access them as well
int run_count[3] = {0, 0, 0};
int child_pids[3];
string processes[3];


void sig_handler( int signo ); //signal handler
int spawnProcess(const char *name); //spawns a particular process by name, returns PID

int main(int argc, char * argv[]) {
        if(argc != 4){
                cerr << "Lab5: Program takes 3 processes as arguments" << endl;
                return 1;
        }

    // Setup the signal handler
    struct sigaction act;
    act.sa_handler = sig_handler;
        sigemptyset( &act.sa_mask );
        act.sa_flags = SA_NOCLDWAIT;

    if( sigaction( SIGCHLD , &act, NULL ) == -1 ) {
            perror( "sigaction" );
            exit( 1 );
        }

        // Initial spawn of our processes
        for(int i = 1; i < 4; i++){
            processes[i-1] = string(argv[i]);
                child_pids[i-1] = spawnProcess(argv[i]);
        }


    // Sleep for 20 seconds even if the timer is interupted by a signal
        int sleep_time = 20;
        while (0 != (sleep_time = sleep(sleep_time)))
        {}

        cout << "Parent has exited" << endl;

    return 0;
}

void sig_handler( int signo ) {
    int status;
    for (int i = 0; i < 4; ++i)
    {
        // If we get negative one the child is dead
        if ((-1 == waitpid(child_pids[i], &status, WNOHANG)) &&
            (run_count[i] < 4))
        {
            // Increment the run count
            run_count[i]++;

            cout << "Restarting child '" << processes[i] << "' for the "
                <<  run_count[i] << " time" << endl;
            // Run the process again and record its new pid, then
            child_pids[i] = spawnProcess(processes[i].c_str());
        }
    }
}

//Spawn the process "name" and return its PID
int spawnProcess(const char *name) {
        int pid;
        switch( (pid = vfork()) ){
                case -1:
                        cerr << "Error calling vfork()" << endl;
                        return 1;
                case 0:
                        if(execl(name, NULL) == -1){
                        cerr << "Error calling execl" << endl;
                        return 1;
                        }
        };
return pid;
}


Oh yes, and there might be way to do this without global data. See the "wait" function in this page of the gnu c manual.

Ghosty Dec 14th, 2006 2:57 AM

Thanks for your reply. That code you posted is making my head hurt so I'll have to stare at it for awhile. The actual code you have in the sig_handler() looks similar to the code I had before this program used signals. I'm going to play with this for awhile longer. I'll post back if I have any more questions.

Once I understand this I'll probably try to change it so it doesn't use globals. I have a feeling that my professor will reject it if I use globals.

Game_Ender Dec 14th, 2006 12:09 PM

Using the GCC code I linked to you should be able to removed the need to store the pids globally but you somehow have to know what command to run when a certain child quits. The signal handler can't be passed any other information so it will be quite a trick for it to figure out what command it should run to "restart" a process.

Ghosty Dec 14th, 2006 2:01 PM

It seems to be working just fine with the globals. There were some bugs but the logic of the code is sound. Why can't the signal handler be passed anything more than int signo? Is that just the way it's implemented?


All times are GMT -5. The time now is 1:36 AM.

Powered by vBulletin® Version 3.7.0, Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Copyright ©2007 DaniWeb® LLC