demonzzz
asked on
Returning signals from parent to child
Say I have;
int routine1 (void)
{
some command; //ppp connection which stays alive
return;
}
int routine2 (void)
{
some command;
return;
}
int main (void)
{
int child1;
child1 = fork();
if (child1)
{
routine2();
}
else
routine1();
return 0;
}
I've read the section on signals and returns in my book a million times over, i cant make sense of it!
How would I get routine1 to terminate when all children finish?
To explain a little better: my program connects to gprs via ppp then run the children. routine1 is the gprs connection which i would like terminated once the children processes have completed.
As I said, i can't get my head around it and would like a little enlightenment please.
This solution is pretty urgent!
Thnx
int routine1 (void)
{
some command; //ppp connection which stays alive
return;
}
int routine2 (void)
{
some command;
return;
}
int main (void)
{
int child1;
child1 = fork();
if (child1)
{
routine2();
}
else
routine1();
return 0;
}
I've read the section on signals and returns in my book a million times over, i cant make sense of it!
How would I get routine1 to terminate when all children finish?
To explain a little better: my program connects to gprs via ppp then run the children. routine1 is the gprs connection which i would like terminated once the children processes have completed.
As I said, i can't get my head around it and would like a little enlightenment please.
This solution is pretty urgent!
Thnx
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int childcounter;
void Childroutine(void) {
//do some child work...
printf("\nCHILD %d: exiting\n",getpid());
exit(0);
}
void Mainroutine(void) {
int childstatus;
int deadchild;
while (1) {
//do some main work...
sleep(1);
if((deadchild=waitpid(0,&c hildstatus ,WNOHANG)) !=0) {
childcounter--;
printf("\nMAIN: child %d died\n",deadchild);
}
printf("\nMAIN: I have %d children\n",childcounter);
if(childcounter==0) exit(0);
}
}
int main(){
int pid;
int i;
childcounter=0;
for (i=0;i<10;i++) {
childcounter++;
printf("\nMAIN: giving birth to a child\n");
pid = fork();
if (pid == 0)
Childroutine();
}
if(pid!=0) Mainroutine();
}
You may want to think about not using signals at all and use waitpid with the WNOHANG argument as above, this seems to elinimate the problem of missing signals.
Daniel
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
int childcounter;
void Childroutine(void) {
//do some child work...
printf("\nCHILD %d: exiting\n",getpid());
exit(0);
}
void Mainroutine(void) {
int childstatus;
int deadchild;
while (1) {
//do some main work...
sleep(1);
if((deadchild=waitpid(0,&c
childcounter--;
printf("\nMAIN: child %d died\n",deadchild);
}
printf("\nMAIN: I have %d children\n",childcounter);
if(childcounter==0) exit(0);
}
}
int main(){
int pid;
int i;
childcounter=0;
for (i=0;i<10;i++) {
childcounter++;
printf("\nMAIN: giving birth to a child\n");
pid = fork();
if (pid == 0)
Childroutine();
}
if(pid!=0) Mainroutine();
}
You may want to think about not using signals at all and use waitpid with the WNOHANG argument as above, this seems to elinimate the problem of missing signals.
Daniel
Hi demonzzz,
The basic thing you need to realize about signals is that signal handling is totally asynchronous. A signal may be received at anytime and control will be transferred to the signal handler irrespective of where the control previously was.
Now I am not very clear about what you are trying to ask? Do you wish to know how to incorporate signal handling in the above code skeleton so that parent exits when all children have completed? If yes, then SIGCHLD signal is sent to the parent when a child exits. You can simply write a signal handler for SIGCHLD. This will be called whenever a child exits. You can then do the cleanup in the signal handler.
A word of caution, signal() interface has been replaced by sigaction() interface. New interface is safer and better. I would recommend that you use sigaction in place of signal
man sigaction
A link which I found very educative when I learnt sigaction interface
http://www.linux-mag.com/2000-01/compile_01.html
The basic thing you need to realize about signals is that signal handling is totally asynchronous. A signal may be received at anytime and control will be transferred to the signal handler irrespective of where the control previously was.
Now I am not very clear about what you are trying to ask? Do you wish to know how to incorporate signal handling in the above code skeleton so that parent exits when all children have completed? If yes, then SIGCHLD signal is sent to the parent when a child exits. You can simply write a signal handler for SIGCHLD. This will be called whenever a child exits. You can then do the cleanup in the signal handler.
A word of caution, signal() interface has been replaced by sigaction() interface. New interface is safer and better. I would recommend that you use sigaction in place of signal
man sigaction
A link which I found very educative when I learnt sigaction interface
http://www.linux-mag.com/2000-01/compile_01.html
idt has given a program for you to look into.
I haven't tried it to see if it works.
But, I will try to explain the logic behind his code.
When a child exits, parent gets a signal SIGCHLD.
If you use waitpid() function inside the parent, then you will also know the pid and status of the exiting child.
When waitpid() returns from wait, that means all the child processes have exited and you can exit the routine1() by calling exit(0).
So, only thing you have to learn is waitpid.
Here is the manual page for waitpid():
WAIT(2) Linux Programmer's Manual WAIT(2)
NAME
wait, waitpid - wait for process termination
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
DESCRIPTION
The wait function suspends execution of the current process until a
child has exited, or until a signal is delivered whose action is to
terminate the current process or to call a signal handling function.
If a child has already exited by the time of the call (a so-called
"zombie" process), the function returns immediately. Any system
resources used by the child are freed.
The waitpid function suspends execution of the current process until a
child as specified by the pid argument has exited, or until a signal is
delivered whose action is to terminate the current process or to call a
signal handling function. If a child as requested by pid has already
exited by the time of the call (a so-called "zombie" process), the
function returns immediately. Any system resources used by the child
are freed.
The value of pid can be one of:
< -1 which means to wait for any child process whose process group ID
is equal to the absolute value of pid.
-1 which means to wait for any child process; this is the same
behaviour which wait exhibits.
0 which means to wait for any child process whose process group ID
is equal to that of the calling process.
> 0 which means to wait for the child whose process ID is equal to
the value of pid.
The value of options is an OR of zero or more of the following con-
stants:
WNOHANG
which means to return immediately if no child has exited.
WUNTRACED
which means to also return for children which are stopped, and
whose status has not been reported.
(For Linux-only options, see below.)
If status is not NULL, wait or waitpid store status information in the
location pointed to by status.
This status can be evaluated with the following macros (these macros
take the stat buffer (an int) as an argument â not a pointer to the
buffer!):
WIFEXITED(status)
is non-zero if the child exited normally.
WEXITSTATUS(status)
evaluates to the least significant eight bits of the return code
of the child which terminated, which may have been set as the
argument to a call to exit() or as the argument for a return
statement in the main program. This macro can only be evaluated
if WIFEXITED returned non-zero.
WIFSIGNALED(status)
returns true if the child process exited because of a signal
which was not caught.
WTERMSIG(status)
returns the number of the signal that caused the child process
to terminate. This macro can only be evaluated if WIFSIGNALED
returned non-zero.
WIFSTOPPED(status)
returns true if the child process which caused the return is
currently stopped; this is only possible if the call was done
using WUNTRACED.
WSTOPSIG(status)
returns the number of the signal which caused the child to stop.
This macro can only be evaluated if WIFSTOPPED returned
non-zero.
Some versions of Unix (e.g. Linux, Solaris, but not AIX, SunOS) also
define a macro WCOREDUMP(status) to test whether the child process
dumped core. Only use this enclosed in #ifdef WCOREDUMP ... #endif.
RETURN VALUE
The process ID of the child which exited, or zero if WNOHANG was used
and no child was available, or -1 on error (in which case errno is set
to an appropriate value).
ERRORS
ECHILD if the process specified in pid does not exist or is not a child
of the calling process. (This can happen for oneâs own child if
the action for SIGCHLD is set to SIG_IGN. See also the LINUX
NOTES section about threads.)
EINVAL if the options argument was invalid.
EINTR if WNOHANG was not set and an unblocked signal or a SIGCHLD was
caught.
Hope this helps........
-ssnkumar
I haven't tried it to see if it works.
But, I will try to explain the logic behind his code.
When a child exits, parent gets a signal SIGCHLD.
If you use waitpid() function inside the parent, then you will also know the pid and status of the exiting child.
When waitpid() returns from wait, that means all the child processes have exited and you can exit the routine1() by calling exit(0).
So, only thing you have to learn is waitpid.
Here is the manual page for waitpid():
WAIT(2) Linux Programmer's Manual WAIT(2)
NAME
wait, waitpid - wait for process termination
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
DESCRIPTION
The wait function suspends execution of the current process until a
child has exited, or until a signal is delivered whose action is to
terminate the current process or to call a signal handling function.
If a child has already exited by the time of the call (a so-called
"zombie" process), the function returns immediately. Any system
resources used by the child are freed.
The waitpid function suspends execution of the current process until a
child as specified by the pid argument has exited, or until a signal is
delivered whose action is to terminate the current process or to call a
signal handling function. If a child as requested by pid has already
exited by the time of the call (a so-called "zombie" process), the
function returns immediately. Any system resources used by the child
are freed.
The value of pid can be one of:
< -1 which means to wait for any child process whose process group ID
is equal to the absolute value of pid.
-1 which means to wait for any child process; this is the same
behaviour which wait exhibits.
0 which means to wait for any child process whose process group ID
is equal to that of the calling process.
> 0 which means to wait for the child whose process ID is equal to
the value of pid.
The value of options is an OR of zero or more of the following con-
stants:
WNOHANG
which means to return immediately if no child has exited.
WUNTRACED
which means to also return for children which are stopped, and
whose status has not been reported.
(For Linux-only options, see below.)
If status is not NULL, wait or waitpid store status information in the
location pointed to by status.
This status can be evaluated with the following macros (these macros
take the stat buffer (an int) as an argument â not a pointer to the
buffer!):
WIFEXITED(status)
is non-zero if the child exited normally.
WEXITSTATUS(status)
evaluates to the least significant eight bits of the return code
of the child which terminated, which may have been set as the
argument to a call to exit() or as the argument for a return
statement in the main program. This macro can only be evaluated
if WIFEXITED returned non-zero.
WIFSIGNALED(status)
returns true if the child process exited because of a signal
which was not caught.
WTERMSIG(status)
returns the number of the signal that caused the child process
to terminate. This macro can only be evaluated if WIFSIGNALED
returned non-zero.
WIFSTOPPED(status)
returns true if the child process which caused the return is
currently stopped; this is only possible if the call was done
using WUNTRACED.
WSTOPSIG(status)
returns the number of the signal which caused the child to stop.
This macro can only be evaluated if WIFSTOPPED returned
non-zero.
Some versions of Unix (e.g. Linux, Solaris, but not AIX, SunOS) also
define a macro WCOREDUMP(status) to test whether the child process
dumped core. Only use this enclosed in #ifdef WCOREDUMP ... #endif.
RETURN VALUE
The process ID of the child which exited, or zero if WNOHANG was used
and no child was available, or -1 on error (in which case errno is set
to an appropriate value).
ERRORS
ECHILD if the process specified in pid does not exist or is not a child
of the calling process. (This can happen for oneâs own child if
the action for SIGCHLD is set to SIG_IGN. See also the LINUX
NOTES section about threads.)
EINVAL if the options argument was invalid.
EINTR if WNOHANG was not set and an unblocked signal or a SIGCHLD was
caught.
Hope this helps........
-ssnkumar
Hi idt,
> kill(getppid(),SIGCHLD);
> exit(0);
This will happen automatically, there is no need for an explicit SIGCHLD in this case.
It's more appropriate to wait for a child to finish in the parent:
waitpid(-1,NULL,0);
(-1 waits for any child to finish. Use WNOHANG as third argument for non-blocking calls. AFAIK, errno should be EAGAIN when no child was finished with WNOHANG.)
Cheers,
Stefan
> kill(getppid(),SIGCHLD);
> exit(0);
This will happen automatically, there is no need for an explicit SIGCHLD in this case.
It's more appropriate to wait for a child to finish in the parent:
waitpid(-1,NULL,0);
(-1 waits for any child to finish. Use WNOHANG as third argument for non-blocking calls. AFAIK, errno should be EAGAIN when no child was finished with WNOHANG.)
Cheers,
Stefan
ASKER
idt's post was extremely helpful, however, I still have a problem.
In the example i've posted here, 'mainroutine' runs, then spwns processes for 'startacap' and 'startpcap'. I want the mainroutine (which is the pppd gprs connection) to terminate once the children have finished, otherwise the program execution never gets to run 'poweroff' therefore the program and system continues to run.
It should also be noted here that i'm coding for Linux (k2.6.1).
I hope i've explained the problem well enough.
Thnx idt for getting me this close!
Nick
int childcounter;
void sigchld();
void mainroutine(void)
{
char command[MAXSTRING];
sprintf(command, "pppd /dev/ttyS0 115200 file /etc/ppp/options.gprs");
system(command);
}
void startacap(void)
{
char command[MAXSTRING];
sprintf(command, "arecord -t wav -c 1 -d 1 -r 5500 /root/peye/caps/stream-%g. wav", g);
system(command);
sleep(1);
printf("\nCHILD %d (acap): sending SIGCHLD\n",getpid());
kill(getpid(),SIGCHLD);
exit(0);
}
void startpcap(void)
{
char command[MAXSTRING];
sprintf(command, "./pcap-dev6 | cjpeg > /root/peye/caps/capture-%s .jpg", s, i);
system(command);
printf("\nCHILD %d (pcap): sending SIGCHLD\n",getpid());
kill(getpid(),SIGCHLD);
exit(0);
}
void sigcounter(void)
{
signal(SIGCHLD,sigchld);
while (1)
{
sleep(20);
printf("\nSIGCOUNTER: I have %d children\n", childcounter);
if (childcounter == 1)
{
sleep(10);
return;
}
}
}
int main ()
{
int i;
childcounter=0;
int child1;
int child2;
for (i=0;i<4;i++)
{
sleep(1);
childcounter++;
printf("\nMAIN: giving birth to a child\n");
child1 = fork();
if (child1)
{
sleep(1);
childcounter++;
printf("\nMAIN: giving birth to a child 2\n");
child2 = fork();
if (child2)
{
startpcap();
}
else
{
sleep(18);
startacap();
}
}
else
startsmsgprs();
sleep(30);
powerdown(); //shutdown -h now
return 0;
}
}
void sigchld()
{
childcounter--;
return;
}
In the example i've posted here, 'mainroutine' runs, then spwns processes for 'startacap' and 'startpcap'. I want the mainroutine (which is the pppd gprs connection) to terminate once the children have finished, otherwise the program execution never gets to run 'poweroff' therefore the program and system continues to run.
It should also be noted here that i'm coding for Linux (k2.6.1).
I hope i've explained the problem well enough.
Thnx idt for getting me this close!
Nick
int childcounter;
void sigchld();
void mainroutine(void)
{
char command[MAXSTRING];
sprintf(command, "pppd /dev/ttyS0 115200 file /etc/ppp/options.gprs");
system(command);
}
void startacap(void)
{
char command[MAXSTRING];
sprintf(command, "arecord -t wav -c 1 -d 1 -r 5500 /root/peye/caps/stream-%g.
system(command);
sleep(1);
printf("\nCHILD %d (acap): sending SIGCHLD\n",getpid());
kill(getpid(),SIGCHLD);
exit(0);
}
void startpcap(void)
{
char command[MAXSTRING];
sprintf(command, "./pcap-dev6 | cjpeg > /root/peye/caps/capture-%s
system(command);
printf("\nCHILD %d (pcap): sending SIGCHLD\n",getpid());
kill(getpid(),SIGCHLD);
exit(0);
}
void sigcounter(void)
{
signal(SIGCHLD,sigchld);
while (1)
{
sleep(20);
printf("\nSIGCOUNTER: I have %d children\n", childcounter);
if (childcounter == 1)
{
sleep(10);
return;
}
}
}
int main ()
{
int i;
childcounter=0;
int child1;
int child2;
for (i=0;i<4;i++)
{
sleep(1);
childcounter++;
printf("\nMAIN: giving birth to a child\n");
child1 = fork();
if (child1)
{
sleep(1);
childcounter++;
printf("\nMAIN: giving birth to a child 2\n");
child2 = fork();
if (child2)
{
startpcap();
}
else
{
sleep(18);
startacap();
}
}
else
startsmsgprs();
sleep(30);
powerdown(); //shutdown -h now
return 0;
}
}
void sigchld()
{
childcounter--;
return;
}
Hi Nick,
Your children need to kill with getppid() not getpid() since you want the processid of the parent, not the child.
I don't see where you are calling mainroutine(void) or sigcounter(void)
Nor see the prototype for startsmsgprs()
Does the system() in mainroutine finish, or is that the routine that you want to stop once all children proceses are complete?
Daniel
Your children need to kill with getppid() not getpid() since you want the processid of the parent, not the child.
I don't see where you are calling mainroutine(void) or sigcounter(void)
Nor see the prototype for startsmsgprs()
Does the system() in mainroutine finish, or is that the routine that you want to stop once all children proceses are complete?
Daniel
ASKER
Daniel,
Sorry, my bad, mainroutine is "startsmsgprs", i had renamed to make it easier reading but forgot that one!
When using kill(getppid(),SIGCHLD); on BOTH childprocesses, does this mean that the parent is killed when BOTH children are finished, or just the one?
I will attach the code again with all my typo's fixed, sorry 'bout this.
The system(command) in the mainroutine does not finish, this is what i would like killed after ALL child processes have finished.
After looking over this again, i'm not sure where to call sigcounter, would it be called at the start of main()?
Thnx
int childcounter;
void sigchld();
void mainroutine(void)
{
char command[MAXSTRING];
sprintf(command, "pppd /dev/ttyS0 115200 file /etc/ppp/options.gprs");
system(command);
}
void startacap(void)
{
char command[MAXSTRING];
sprintf(command, "arecord -t wav -c 1 -d 1 -r 5500 /root/peye/caps/stream-%g. wav", g);
system(command);
sleep(1);
printf("\nCHILD %d (acap): sending SIGCHLD\n",getpid());
kill(getppid(),SIGCHLD);
exit(0);
}
void startpcap(void)
{
char command[MAXSTRING];
sprintf(command, "./pcap-dev6 | cjpeg > /root/peye/caps/capture-%s .jpg", s, i);
system(command);
printf("\nCHILD %d (pcap): sending SIGCHLD\n",getpid());
kill(getppid(),SIGCHLD);
exit(0);
}
void sigcounter(void)
{
signal(SIGCHLD,sigchld);
while (1)
{
sleep(20);
printf("\nSIGCOUNTER: I have %d children\n", childcounter);
if (childcounter == 1)
{
sleep(10);
return;
}
}
}
int main ()
{
int i;
childcounter=0;
int child1;
int child2;
for (i=0;i<4;i++)
{
sleep(1);
childcounter++;
printf("\nMAIN: giving birth to a child\n");
child1 = fork();
if (child1)
{
sleep(1);
childcounter++;
printf("\nMAIN: giving birth to a child 2\n");
child2 = fork();
if (child2)
{
startpcap();
}
else
{
sleep(18);
startacap();
}
}
else
mainroutine();
sleep(30);
powerdown(); //shutdown -h now
return 0;
}
}
void sigchld()
{
childcounter--;
return;
}
Sorry, my bad, mainroutine is "startsmsgprs", i had renamed to make it easier reading but forgot that one!
When using kill(getppid(),SIGCHLD); on BOTH childprocesses, does this mean that the parent is killed when BOTH children are finished, or just the one?
I will attach the code again with all my typo's fixed, sorry 'bout this.
The system(command) in the mainroutine does not finish, this is what i would like killed after ALL child processes have finished.
After looking over this again, i'm not sure where to call sigcounter, would it be called at the start of main()?
Thnx
int childcounter;
void sigchld();
void mainroutine(void)
{
char command[MAXSTRING];
sprintf(command, "pppd /dev/ttyS0 115200 file /etc/ppp/options.gprs");
system(command);
}
void startacap(void)
{
char command[MAXSTRING];
sprintf(command, "arecord -t wav -c 1 -d 1 -r 5500 /root/peye/caps/stream-%g.
system(command);
sleep(1);
printf("\nCHILD %d (acap): sending SIGCHLD\n",getpid());
kill(getppid(),SIGCHLD);
exit(0);
}
void startpcap(void)
{
char command[MAXSTRING];
sprintf(command, "./pcap-dev6 | cjpeg > /root/peye/caps/capture-%s
system(command);
printf("\nCHILD %d (pcap): sending SIGCHLD\n",getpid());
kill(getppid(),SIGCHLD);
exit(0);
}
void sigcounter(void)
{
signal(SIGCHLD,sigchld);
while (1)
{
sleep(20);
printf("\nSIGCOUNTER: I have %d children\n", childcounter);
if (childcounter == 1)
{
sleep(10);
return;
}
}
}
int main ()
{
int i;
childcounter=0;
int child1;
int child2;
for (i=0;i<4;i++)
{
sleep(1);
childcounter++;
printf("\nMAIN: giving birth to a child\n");
child1 = fork();
if (child1)
{
sleep(1);
childcounter++;
printf("\nMAIN: giving birth to a child 2\n");
child2 = fork();
if (child2)
{
startpcap();
}
else
{
sleep(18);
startacap();
}
}
else
mainroutine();
sleep(30);
powerdown(); //shutdown -h now
return 0;
}
}
void sigchld()
{
childcounter--;
return;
}
Nick,
Ahh, makes things a bit clearer
When using kill(getppid(),SIGCHLD); on BOTH childprocesses, does this mean that the parent is killed when BOTH children are finished, or just the one?
kill is how to send a signal, it does not actually mean kill, well it could if the recieving process doesn't handle it, but in this case the parent has a handler.
Okay, since the main thread is off doing a system instruction, you will have a lot of problems in this model.
Instead, create a new thread to do the system(), and you can kill it by sending it a signal that it does not have a handler for, like SIGHUP after all the other children die.
That thread would then exit, and your main thread would do any cleanup.
If you want to wait a few hours, I can get a chance to revamp the code to this new paradigm.
It's pretty easy now.
Daniel
Ahh, makes things a bit clearer
When using kill(getppid(),SIGCHLD); on BOTH childprocesses, does this mean that the parent is killed when BOTH children are finished, or just the one?
kill is how to send a signal, it does not actually mean kill, well it could if the recieving process doesn't handle it, but in this case the parent has a handler.
Okay, since the main thread is off doing a system instruction, you will have a lot of problems in this model.
Instead, create a new thread to do the system(), and you can kill it by sending it a signal that it does not have a handler for, like SIGHUP after all the other children die.
That thread would then exit, and your main thread would do any cleanup.
If you want to wait a few hours, I can get a chance to revamp the code to this new paradigm.
It's pretty easy now.
Daniel
ASKER
That makes sense. So the mainroutine will be a child aswell, and when the child count =1 a SIGHUP is sent to the mainroutine child?
Ive had a go at changing it, but my heads gone a bit fuzzy. If you wouldnt mind could you revamp it for me?
It's 1am here, so I don't think i'll be able to give it a go before i go to bed, so there is no rush.
Nick
Ive had a go at changing it, but my heads gone a bit fuzzy. If you wouldnt mind could you revamp it for me?
It's 1am here, so I don't think i'll be able to give it a go before i go to bed, so there is no rush.
Nick
Nick,
I changed the code to only use a signal to kill the GRPS process once the the A and PCAP process complete. main just creates the processes, and waits on the kiddies to terminate. I hope I understood your requirements.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
void waitInfo(int pid, int status);
void gprs_routine(void);
void startacap(void);
void startpcap(void);
void ErrorStopProcesses(void);
void waitInfo(int pid, int status) {
if(WIFEXITED(status))
printf("\tProcess %d exited normally with exit code %d.\n",pid,WEXITSTATUS(sta tus));
else {
if(WIFSIGNALED(status))
printf("\tProcess %d exited because of signal %d was not caught.\n",pid,WTERMSIG(st atus));
if(WIFSTOPPED(status))
printf("\tProcess %d is stopped because signal %d.\n",pid,WSTOPSIG(status ));
}
return;
}
void gprs_routine(void) {
sleep(1); //simulate startup code
printf("\tGPRS Process started.\n");
while (1) {sleep(10);} //simulate long running process
printf("\tGRPS Process ending (should be unreachable, unless gprs completes).\n");
exit(0);
}
void startacap(void) {
sleep(1); //simulate startup code
printf("\tACAP Process started.\n");
sleep(8); //simulate short running process
printf("\tACAP Process ending.\n");
exit(0);
}
void startpcap(void) {
sleep(1); //simulate startup code
printf("\tPCAP Process started.\n");
sleep(10); //simulate short running process
printf("\tPCAP Process ending.\n");
exit(0);
}
void ErrorStopProcesses(void) {
printf("\nMAIN: Error %d occurred, kill all processes with process group:%d.\n",errno, (getpid()*-1));
kill((getpid()*-1),SIGTERM );
return;
}
int main () {
int childcounter=0;
int status;
int pid;
int threadgprs;
threadgprs=fork();
if(!threadgprs) {
gprs_routine();
exit(0);
}
printf("MAIN: started GPRS process thread with pid:%d.\n",threadgprs);
pid=fork();
if(!pid) {
startpcap();
exit(0);
}
if(pid==-1) ErrorStopProcesses();
childcounter++;
printf("MAIN: started PCAP process thread with pid:%d.\n",pid);
pid=fork();
if(!pid) {
startacap();
exit(0);
}
if(pid==-1) ErrorStopProcesses();
childcounter++;
printf("MAIN: started ACAP process thread with pid:%d.\n",pid);
printf("\nMAIN: entering main wait loop.\n");
while (childcounter) {
pid=waitpid(0,&status,0);
if(pid!=threadgprs)
childcounter--;
else {
threadgprs=0;
// if gprs process terminates early, you could
// kill all others by calling ErrorStopProcesses();
// here, or just wait for them to complete.
}
printf("\tMAIN: %s process terminated, %d child processes still exist.\n",(threadgprs==0? "GRPS" : "child"), childcounter);
waitInfo(pid, status);
}
printf("MAIN: exited main wait loop.\n\n");
if(threadgprs) {
printf("MAIN: signalling GPRS process to terminate (it will not catch the signal).\n");
kill(threadgprs,SIGHUP);
pid=waitpid(0,&status,0);
waitInfo(pid,status);
}
else {
printf("MAIN: GPRS already terminated.\n");
}
printf("\nGround control, shut down main engines.\n");
sleep(1); //simulate shutdown code
return 0;
}
Should complile clean, t'is rather ammusing to watch run.
Daniel
I changed the code to only use a signal to kill the GRPS process once the the A and PCAP process complete. main just creates the processes, and waits on the kiddies to terminate. I hope I understood your requirements.
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
void waitInfo(int pid, int status);
void gprs_routine(void);
void startacap(void);
void startpcap(void);
void ErrorStopProcesses(void);
void waitInfo(int pid, int status) {
if(WIFEXITED(status))
printf("\tProcess %d exited normally with exit code %d.\n",pid,WEXITSTATUS(sta
else {
if(WIFSIGNALED(status))
printf("\tProcess %d exited because of signal %d was not caught.\n",pid,WTERMSIG(st
if(WIFSTOPPED(status))
printf("\tProcess %d is stopped because signal %d.\n",pid,WSTOPSIG(status
}
return;
}
void gprs_routine(void) {
sleep(1); //simulate startup code
printf("\tGPRS Process started.\n");
while (1) {sleep(10);} //simulate long running process
printf("\tGRPS Process ending (should be unreachable, unless gprs completes).\n");
exit(0);
}
void startacap(void) {
sleep(1); //simulate startup code
printf("\tACAP Process started.\n");
sleep(8); //simulate short running process
printf("\tACAP Process ending.\n");
exit(0);
}
void startpcap(void) {
sleep(1); //simulate startup code
printf("\tPCAP Process started.\n");
sleep(10); //simulate short running process
printf("\tPCAP Process ending.\n");
exit(0);
}
void ErrorStopProcesses(void) {
printf("\nMAIN: Error %d occurred, kill all processes with process group:%d.\n",errno, (getpid()*-1));
kill((getpid()*-1),SIGTERM
return;
}
int main () {
int childcounter=0;
int status;
int pid;
int threadgprs;
threadgprs=fork();
if(!threadgprs) {
gprs_routine();
exit(0);
}
printf("MAIN: started GPRS process thread with pid:%d.\n",threadgprs);
pid=fork();
if(!pid) {
startpcap();
exit(0);
}
if(pid==-1) ErrorStopProcesses();
childcounter++;
printf("MAIN: started PCAP process thread with pid:%d.\n",pid);
pid=fork();
if(!pid) {
startacap();
exit(0);
}
if(pid==-1) ErrorStopProcesses();
childcounter++;
printf("MAIN: started ACAP process thread with pid:%d.\n",pid);
printf("\nMAIN: entering main wait loop.\n");
while (childcounter) {
pid=waitpid(0,&status,0);
if(pid!=threadgprs)
childcounter--;
else {
threadgprs=0;
// if gprs process terminates early, you could
// kill all others by calling ErrorStopProcesses();
// here, or just wait for them to complete.
}
printf("\tMAIN: %s process terminated, %d child processes still exist.\n",(threadgprs==0? "GRPS" : "child"), childcounter);
waitInfo(pid, status);
}
printf("MAIN: exited main wait loop.\n\n");
if(threadgprs) {
printf("MAIN: signalling GPRS process to terminate (it will not catch the signal).\n");
kill(threadgprs,SIGHUP);
pid=waitpid(0,&status,0);
waitInfo(pid,status);
}
else {
printf("MAIN: GPRS already terminated.\n");
}
printf("\nGround control, shut down main engines.\n");
sleep(1); //simulate shutdown code
return 0;
}
Should complile clean, t'is rather ammusing to watch run.
Daniel
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Whoops.. bad prototype
change
...
void mainSigHandler();
...
to
...
void SigHandler();
...
change
...
void mainSigHandler();
...
to
...
void SigHandler();
...
ASKER
Yeah, i did think about that, pppd continues to execute. However, the first revamp did work as you expected, and as my system poweroff's (init0) after the gprs_routine is killed, it kills the pppd anyway!
I know that its quite a sloppy way about it, but it works! Also, my dissertation is due in a few weeks and i still have lots of ends to tie up and make a project box.
If I have problems with the current setup then ill go over it again with what you've just given me.
Youve given me what i needed, and more, to tie up the loose ends of my uni dissertation project, thanks Daniel!!!!
Thanks also to those who contributed earlier.
I know that its quite a sloppy way about it, but it works! Also, my dissertation is due in a few weeks and i still have lots of ends to tie up and make a project box.
If I have problems with the current setup then ill go over it again with what you've just given me.
Youve given me what i needed, and more, to tie up the loose ends of my uni dissertation project, thanks Daniel!!!!
Thanks also to those who contributed earlier.
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
int childcounter;
void sigchld();
void Childroutine(void) {
sleep(6);
printf("\nCHILD %d: sending SIGCHLD\n",getpid());
kill(getppid(),SIGCHLD);
exit(0);
}
void Mainroutine(void) {
signal(SIGCHLD,sigchld);
while (1) {
sleep(1);
printf("\nMAIN: I have %d children\n",childcounter);
if(childcounter==0) exit(0);
}
}
int main(){
int pid;
int i;
childcounter=0;
for (i=0;i<4;i++) {
sleep(1);
childcounter++;
printf("\nMAIN: giving birth to a child\n");
pid = fork();
if (pid == 0)
Childroutine();
}
if(pid!=0) Mainroutine();
}
void sigchld() {
childcounter--;
return;
}
Note that if 2 signals are sent at the same time, the main can miss 1.
Daniel