Programming Forums
User Name Password Register
 

RSS Feed
FORUM INDEX | TODAY'S POSTS | UNANSWERED THREADS | ADVANCED SEARCH

Reply
 
Thread Tools Display Modes
Old Dec 14th, 2006, 1:09 AM   #1
Ghosty
Newbie
 
Join Date: May 2005
Location: NJ
Posts: 18
Rep Power: 0 Ghosty is on a distinguished road
Send a message via AIM to Ghosty
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.
Ghosty is offline   Reply With Quote
Old Dec 14th, 2006, 1:43 AM   #2
Game_Ender
Professional Programmer
 
Game_Ender's Avatar
 
Join Date: May 2006
Location: Maryland, USA
Posts: 306
Rep Power: 3 Game_Ender is on a distinguished road
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.
Game_Ender is offline   Reply With Quote
Old Dec 14th, 2006, 1:57 AM   #3
Ghosty
Newbie
 
Join Date: May 2005
Location: NJ
Posts: 18
Rep Power: 0 Ghosty is on a distinguished road
Send a message via AIM to Ghosty
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.
Ghosty is offline   Reply With Quote
Old Dec 14th, 2006, 11:09 AM   #4
Game_Ender
Professional Programmer
 
Game_Ender's Avatar
 
Join Date: May 2006
Location: Maryland, USA
Posts: 306
Rep Power: 3 Game_Ender is on a distinguished road
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.
Game_Ender is offline   Reply With Quote
Old Dec 14th, 2006, 1:01 PM   #5
Ghosty
Newbie
 
Join Date: May 2005
Location: NJ
Posts: 18
Rep Power: 0 Ghosty is on a distinguished road
Send a message via AIM to Ghosty
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?

Last edited by Ghosty; Dec 14th, 2006 at 1:15 PM.
Ghosty is offline   Reply With Quote
Reply

Bookmarks

« Previous Thread in Forum | Next Thread in Forum »

Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Unix commands compatible with Windows? titaniumdecoy Bash / Shell Scripting 7 Oct 5th, 2006 7:25 AM
Lions' Commentary on UNIX 6th Edition, with source code Mad_guy Book Reviews 0 Sep 24th, 2006 7:06 PM
Best Linux or Unix Desktop? Prm753 Coder's Corner Lounge 23 Apr 8th, 2006 10:17 AM
Need help coming up with mnemonic for command processing aznluvsmc Bash / Shell Scripting 6 Feb 21st, 2006 5:56 PM
Importing from DLL's on Unix Kaja Fumei Existing Project Development 5 Jan 9th, 2006 6:35 PM




DaniWeb IT Discussion Community
All times are GMT -5. The time now is 2:49 PM.

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