I'm having some troubles using sigchld...
what I want to do is to create a child process with fork and make the child print and sleep a second for a couple of times... during these process I want to send signal to child (SIGSTOP and SIGCONTINUED) and I want the parent to print what the signal was... here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
void handler (int i) {
int x;
waitpid(-1,&x, 0);
printf("WIFSTOPPED=%d, WIFCONTINUED=%d\n", WIFSTOPPED(x),WIFCONTINUED(x) );
}
int main(){
int x;
int q=fork();
if(q==0){
int i=0;
printf("%d\n",getpid());
while (i<20){
printf("%d\n", i++);
sleep(1);
}
_exit(0);
}
else {
signal(SIGCHLD, handler);
waitpid(-1,&x, 0);
while(WIFEXITED(x)!=1){
waitpid(-1,&x, 0);
sleep(1);
}
exit(0);
}
}
but it doesn't work beacause when I send a SIGSTOP or SIGCONTINUED to the child, the child stop and continue but the parent doesn't print anything
any suggestion?
Your handler shall not call waitpid again and you main while loop is also not correct : again you call waitpid twice the first time. And last, your waitpid call much declare to be interested in status changes (WUNTRACED option).
A much correct code could be :
void handler (int i) { // a handler just handle the fact some signal occured
printf("in handler\n");
}
int main(){
int x;
int q=fork();
if(q==0){
int i=0;
printf("%d\n",getpid());
while (i<20){
printf("%d\n", i++);
sleep(1);
}
_exit(0);
}
else {
signal(SIGCHLD, handler); // catch child status changes
do {
waitpid(-1,&x, WUNTRACED|WCONTINUED); // wait until child terminates or changes its status
if (WIFSTOPPED(x)|WIFCONTINUED(x)) // test what really happens
printf("STOPPED=%d, CONTINUED=%d\n", WIFSTOPPED(x),WIFCONTINUED(x) );
} while(!WIFEXITED(x));
exit(0);
}
}
Related
I have a parent process that is spawning X number of child processes (player) based off the first argument passed to the program. After each child is spawned it sends them a signal. For now all I want the children to do it print they received the signal and exit, but they don't seem to get the signal from the parent. Are the children not getting the signal or am I handling it wrong?
Parent:
#define _POSIX_SOURCE
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
void reciveCard() {
write(1, "signal recived\n", 15);
exit(0);
}
int main(int argc, char **argv) {
int numPlayers, i;
int *kpids;
numPlayers = atoi(argv[1]);
kpids = malloc(numPlayers * sizeof(int));
signal(SIGUSR1, SIG_IGN);
for(i = 0; i < numPlayers; i++) {
if((kpids[i] = fork()) == 0) {
if(execlp("./player\0", "./player\0", (char *) NULL) == -1) {
printf("error\n");
exit(1);
}
}
}
for(i = 0; i < numPlayers; i++) {
printf("%d\n", kpids[i]);
kill(kpids[i], SIGUSR1);
}
wait(NULL);
return 0;
}
Child:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void reciveCard() {
write(1, "signal recived\n", 15);
exit(0);
}
int main() {
signal(SIGUSR1, reciveCard);
while(1) {
sleep(1);
}
return 0;
}
You have a race condition.
The parent program does the fork calls so fast that it falls into the kill loop before any child has a chance to do the execlp.
Thus, the child can't set up the handler fast enough. That is, when the signal comes in, the child is still ignoring it because of the parent's SIG_IGN call that it has inherited.
Now, after the execlp, the child will set up the handler, but the signal has already occurred, so the the handler will never be called.
To see this, add a sleep(1) between the two parent loops and it should work.
I need to send a signal to a child process 3 times.
The problem is that the child only receives the signal once and then transforms into a zombie.
The expected output would be:
I'm the child 11385 and i received SIGUSR1
I'm the child 11385 and i received SIGUSR1
I'm the child 11385 and i received SIGUSR1
But the real output is:
I'm the child 11385 and i received SIGUSR1
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
void my_handler()
{
printf("\n I'm the child %i and i received SIGUSR1\n", getpid());
}
int main (int argc, char **argv) {
int *array;
int N = 10;
int i;
pid_t pid1;
array=(int*)malloc(sizeof(int)*N);
signal(SIGUSR1,my_handler);
for (i = 0; i< N; i++)
{
pid1 = fork();
if(pid1 < 0)
{
exit(EXIT_FAILURE);
}
else if (pid1 > 0)
{
array[i]= pid1;
}
else
{
sleep(100);
exit(EXIT_SUCCESS);
}
}
i=0;
while(i<3) // I need to call the son 3 times
{
kill(array[1], SIGUSR1);
i++;
}
}
When the child receives the signal, it is probably waiting for the sleep to terminate. The first signal will interrupt the sleep even if the time hasn't expired, causing it to return with errno set to EINTR. If you want it to keep sleeping, you need to call sleep again.
your parent process exited without wait()ing for the child
The signals could be sent to fast, I added a short delay
i added more delays
the correct signature for a signal handler is void handler(int signum) This is crucial, because the handler is called with an argument, and the stack layout is different for signal handlers.
you should not call printf() from a signal handler, it is not async safe.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
char pidstr[10];
char massage[]=" I'm the child and i received SIGUSR1\n";
#define CNT 1
void my_handler(int signum)
{
write(0, massage, strlen(massage));
}
int main (int argc, char **argv) {
int i , err, status;
pid_t pid1;
int array[CNT];
signal(SIGUSR1, my_handler);
for (i = 0; i< CNT; i++) {
pid1 = fork();
if(pid1 < 0) { exit(EXIT_FAILURE); }
else if (pid1 > 0) {
printf("ChildPid=%d\n", pid1 );
array[i]= pid1;
}
else
{ // child
// signal(SIGUSR1, my_handler);
sprintf(pidstr,"[%d]", getpid() );
memcpy (massage,pidstr, strlen(pidstr));
sleep(10);
printf("Unslept\n");
sleep(10);
printf("Unslept\n");
sleep(10);
printf("Unslept\n");
exit(EXIT_SUCCESS);
}
}
sleep(10);
for (i=0; i<3; i++) {
err = kill(array[0], SIGUSR1);
printf("Err=%d:%d\n", err, (err) ? errno: 0 );
sleep(1);
}
while ( (pid1=wait( &status)) != -1){
printf("[Parent] Reaped %d\n", pid1);
}
return 0;
}
I have a program that starts a child (r.out), and that child has a time limit.
I want to know how to stop running r.out after passing the time limit.
I am running the code on Linux.
This is what I have so far:
#include <unistd.h>
#include <signal.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#define TIME_LIMIT 1 //determine time limit
void my_function(); //supposed to include the submitted code
void alarm_handler(int);
int main()
{
if (sigaction(SIGALRM, NULL, NULL) == -1)
err(1, NULL);
signal(SIGALRM, alarm_handler); // assigning an alarm handler for SIGALRM
alarm(TIME_LIMIT); // install an alarm to be fired after TIME_LIMIT
system("./r.out"); //Running the file
alarm(0);
return 0;
}
void alarm_handler(int sig)
{
printf("%s" , "Time limit exceeded");
//Here i want a code to stop the r.out file
}
In order to kill the child, you need to know its pid. You can get it if you start the program with fork and exec instead of system.
In addition to a signal handler for SIGALRM, set up one for SIGCHLD (received when a child process finishes) as well. After calling alarm to set the timer, call pause. This function will return when you get either of the two signals.
In the signal handlers you should only set a global flag. Calling printf from within a signal handler can lead to undefined behavior.
After pause returns, check each of the two flags. If the timeout flag is set, you can terminate the child with kill.
In either case, call wait to reap the child process's pid.
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#define TIME_LIMIT 1 //determine time limit
void alarm_handler(int);
void child_handler(int);
int timeout = 0;
int child_done = 0;
int main()
{
pid_t pid = fork();
if (pid == -1) {
perror("fork failed");
exit(1);
} else if (pid == 0) {
// child process
execl("./r.out","r.out", NULL);
perror("exec failed");
_exit(1);
}
// set up the signal handlers after forking so the child doesn't inherit them
signal(SIGALRM, alarm_handler);
signal(SIGCHLD, child_handler);
alarm(TIME_LIMIT); // install an alarm to be fired after TIME_LIMIT
pause();
if (timeout) {
printf("alarm triggered\n");
int result = waitpid(pid, NULL, WNOHANG);
if (result == 0) {
// child still running, so kill it
printf("killing child\n");
kill(pid, 9);
wait(NULL);
} else {
printf("alarm triggered, but child finished normally\n");
}
} else if (child_done) {
printf("child finished normally\n");
wait(NULL);
}
return 0;
}
void child_handler(int sig)
{
child_done = 1;
}
void alarm_handler(int sig)
{
timeout = 1;
}
I have some troubles:
it is not clear for me how to synchronise parent and child processes using signals, and this code doesn't work.
I thought that it should work like that: parent sends signal to child, child's pause() is end, child sends signal to parent, parent's pause() is end .. etc
why it is not so?
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
void handler_cp() {
}
void handler_pc() {
}
void child_proc() {
int i = 0;
for (; i < 50; ++i) {
pause();
kill(getppid(), SIGUSR2);
}
void parent_proc(pid_t ch) {
int j = 0;
for (; j < 50; ++j) {
kill(ch, SIGUSR1);
pause();
}
}
int main(int argc, char* argv[]) {
signal(SIGUSR1, handler_cp);
signal(SIGUSR2, handler_pc);
pid_t ch = fork();
if (ch == 0)
child_proc();
else
parent_proc(ch);
return 0;
}
The signal may arrive before pause is called, in which case it will deadlock. Using signals for synchronization is, in general, a very bad idea.
In the child_proc method, reverse the lines as :
kill(getppid(),SIGUSR2);
pause();
This will wake the parent before the child goes to sleep.
I try to create 4 child processes who will work simultaneously, but the output of my program is quite random: sometimes one of the processes is not created (the printf statement is not executed). I can not understand the reason for this, because when I use the wait() function in my parent it should wait for it's children to finish? Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define NR_OF_PROCESSES 4
void readProcess(void);
void tokenProcess(void);
void calculatorProcess(void);
void errorProcess(void);
void (*functionTable[NR_OF_PROCESSES]) (void) = {readProcess, tokenProcess, calculatorProcess, errorProcess};
int main(void) {
int i;
int status;
for (i = 0; i < NR_OF_PROCESSES; i++) {
int pid = fork();
if (pid < 0) {
perror("could not fork");
return 0;
}
if (pid == 0) {
functionTable[i]();
exit(0);
}
}
printf("parent is waiting");
wait(status);
return (0);
}
void readProcess(void) {
printf("readprocess running, PID=%d, PPID=%d\n",getpid(),getppid());
}
void tokenProcess(void) {
printf("tokenprocess running, PID=%d, PPID=%d\n",getpid(),getppid());
}
void calculatorProcess(void) {
printf("calculatorprocess running, PID=%d, PPID=%d\n",getpid(),getppid());
}
void errorProcess(void) {
printf("errorprocess running, PID=%d, PPID=%d\n",getpid(),getppid());
}
Also, I want to add interprocess communication with pipes later on. Will this be possible if I implement the processes this way? Any better solution?
You only wait for one child, you probably want to call wait for each child.