Controlling multiple children, handling sigchld - c

Let's say i have a main C program that has to wait for sigchld of two children, and that these two sons have to do two separate task, for example one should write "1", and the other
one should write "2" ,wait 2 seconds and then terminate, now how should I write the code so that the father write his children's pid only after the two sons ends with sigchld? It's obvious that i'm missing some theory, if you look at my code you will understand what my issue is.
After that i'll have to force the execution of the second son before the first son, suggestion?
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char **argv)
{
int pids[2], cpid, i, status;
char buff[200];
for(i=0; i < 2; i++)
{
if ((pids[i] = fork()) < 0)
perror("errno");
else
{
//child
if (pids[i] == 0)
{
if(i == 0)
write(1,"1\n", 2);
else
{
sleep(2);
write(1,"2\n", 2);
}
return 0;
}
}
}
for(i = 0; i < 2; i++)
{
cpid = waitpid(pids[i], &status, 0);
if (WTERMSIG(status))
printf("status:%d , pid terminated:\n", status,cpid);
else
printf("error: not exited with a signal\n");
}
return 0;
}

If the last for loop is changed as:
for(i = 0; i < 2; i++)
{
cpid = waitpid(pids[i], &status, 0);
if (WIFEXITED(status))
printf("status:%d , pid %d terminated normally :\n", status,cpid);
else if (WTERMSIG(status))
printf("status:%d , pid %d terminated by signal:\n", status,cpid);
else
printf("error: not exited with a signal\n");
}
Then the thing works better, as there is no signal to terminate the childs.

Related

Linux shuts down after compiling basic children process

In this simple C code, I am trying to create 10 children. Then do some work (such as printing the time) in them individually. Then I try to kill all of them in parent process. You will easily understand the code below. The problem is that, whenever I run this, first it gives the various outputs from children then Linux shuts down. Then I start from passing user password and everything is closed. Why this happens?
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdlib.h>
#include <time.h>
int main() {
pid_t pids[10];
int i;
int n= 10;
for (i= 0; i<n; ++i) {
if ((pids[i] = fork()) <0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {
struct timeval tv;
time_t t;
struct tm*info;
char buffer[64];
gettimeofday(&tv,NULL);
t = tv.tv_sec;
info = localtime(&t);
sleep(1);
printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
}
}
int status;
pid_t pid;
sleep(5);
while (n >0) {
pid = wait(&status);
kill((long)pid, SIGTERM);
printf("CHILD %d killed.",pid);
--n;
}
}
In process created by fork() all variables have the same value as before fork. After fork in this your code
for (i= 0; i<n; ++i) {
if ((pids[i] = fork()) <0) {
perror("fork");
abort();
}
else if (pids[i] == 0) {
...
}
}
i in child process is the same as it was in parent before fork, so for loop continue to execute and spawn a lot of grand children processes.
After loop is executed all spawned processes call wait(). Processes which are spawned on last iteration (with i==9) have no children, so wait() indicates error by returning -1 (and errno==ECHILD). Then you call kill() with pid==-1, which is:
If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init)
If you want child processes to terminate by themself then you should exit explicitly, e.g. with _exit() function. In this case you don't need to send TERM signal:
int main(void)
{
pid_t pids[10];
int i;
int n = 10;
for (i = 0; i<n; ++i)
{
if ((pids[i] = fork()) < 0)
{
perror("fork");
abort();
// abort() never return, "else" is not needed
}
if (pids[i] == 0)
{
struct timeval tv;
time_t t;
struct tm*info;
gettimeofday(&tv,NULL);
t = tv.tv_sec;
info = localtime(&t);
sleep(1);
printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
_exit(0); // terminate process explicitly
}
}
int status;
pid_t pid;
sleep(5);
while (n > 0)
{
pid = wait(&status);
// No kill needed for already exited process
// kill((long)pid, SIGTERM);
if (pid == -1)
{
perror("wait");
abort();
} else {
printf("CHILD %d killed.\n", pid);
}
--n;
}
}
If you want to terminate child processes from parent process then children should wait until terminated, but you should send signal before waiting for child process termination:
int main(void)
{
pid_t pids[10];
int i;
int n = 10;
for (i = 0; i<n; ++i)
{
if ((pids[i] = fork()) < 0)
{
perror("fork");
abort();
// abort() never return, "else" is not needed
}
if (pids[i] == 0)
{
struct timeval tv;
time_t t;
struct tm*info;
gettimeofday(&tv,NULL);
t = tv.tv_sec;
info = localtime(&t);
sleep(1);
printf("CHILD PID: %d and the time is %s\n",getpid(),asctime(info));
// wait until terminated
for (;;)
pause();
}
}
int status;
pid_t pid;
sleep(5);
for (i = 0; i<n; ++i) {
if (kill(pids[i], SIGTERM) == -1) {
perror("kill");
}
}
while (n--)
{
pid = wait(&status);
if (pid == -1)
{
perror("wait");
abort();
} else {
printf("CHILD %d killed.\n", pid);
}
}
}

fork() 4 children in a loop

The goal is to try and fork 4 children in a loop, but I'm not sure how to properly do that. This is what I have so far. I tried to draw it out and I think I'm not waiting to reap the child properly. And I create like 2 children every iteration. So, 8 children in total.
void main() {
int i = 0;
pid_t pid;
int status;
for(i = 0; i < 4; i++) {
pid = fork();
if(pid == 0) {
/* Child Process */
fork();
exit(0);
} else {
/* Parent Process */
wait(&status);
printf("At i = %d, process %d is terminated.\n", i, pid);
}
}
}
Creating four children processes from the same parent process can be achieved by forking once on each iteration of the for loop:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
for (int i = 0; i < 4; i++) {
pid_t pid = fork();
if (pid == 0)
exit(0); // child process
// parent process
wait(NULL);
printf("At i = %d, process %d is terminated.\n", i, pid);
}
}
However, you probably want the parent process to wait for the children after it has created all of the four children, because you usually want the children to do something before exiting and concurrently with the other children:
int main() {
// create the four children processes
for (int i = 0; i < 4; i++) {
pid_t pid = fork();
if (pid == 0) {
// child process
// ... do some stuff ...
exit(0);
}
}
// wait for the four children processes to finish
for (int i = 0; i < 4; i++) {
pid_t pid = wait(NULL);
printf("Process %d is terminated.\n", pid);
}
}

fork() in C. I need explanation on this code

So, i have this piece of C code
I can't grasp what the second 'for' segment is about. When does it get terminated abnormally?
Can someone enlighten me on that?
#include<unistd.h>
#include<stdio.h>
#include <sys/wait.h>
#define N 30
int main() {
pid_t pid[N];
int i;
int child_status;
for (i = 0; i < N; i++) {
pid[i] = fork();
if (pid[i] == 0) {
sleep(60 - 2 * i);
exit(100 + i);
}
}
for (i = 0; i < N; i++) {
pid_t wpid = waitpid(pid[i], & child_status, 0);
if (WIFEXITED(child_status)) {
printf("Child%d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
} else {
printf("Child%d terminated abnormally\n", wpid);
}
}
return (0);
}
When child is terminate ,to be able to find with which value the child was terminated (either with exit or with return) i have to pash the second parametre in waitpid() with pointer to an integer.So in that integer on return from the call it will include 2 types of information
a) if child was terminated well with return or exit or stoped unexpectedly
b)the second type will be having the termination value.
If i want to know the information from (a) i need to use the macro WIFEXITED(), if this give me true the (b) emerged from macro WEXITSTATUS().This is a simple example
#include <stdio.h>
#include <stdlib.h> /* For exit() */
#include <unistd.h> /* For fork(), getpid() */
#include <sys/wait.h> /* For waitpid() */
void delay() { /* Just delay */
int i, sum=0;
for (i = 0; i < 10000000; i++)
sum += i;
printf("child (%d) exits...\n", getpid());
exit(5); /* Child exits with 5 */
}
int main() {
int pid, status;
pid = fork();
if (pid == 0) /* child */
delay();
printf("parent (%d) waits for child (%d)...\n", getpid(), pid);
waitpid(pid, &status, 0);
if (WIFEXITED(status)) /* Terminated OK? */
printf("child exited normally with value %d\n", WEXITSTATUS(status));
else
printf("child was terminated abnormaly.\n");
return 0;
}
SOS The macro WEXITSTATUS() return only the 8 least important bits of the value when the child is terminate.So if the child wants to "say" something to his parent through exit/waitpid it must be a number up to 255.

Capturing exit code of n child processes

I am trying to fork() 10 child processes in one loop and then in another loop wait() for them to terminate and print their PID along with their exit status code. It cannot be done any other way or using any other function. Two loops/waves and the function wait();
This is what I have tried:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
pid_t wait_p, p[10], p_child;
int status;
for (int i = 0; i < 10; i++)
{
p[i] = fork();
}
for (int i = 0; i < 10; i++)
{
switch (p[i])
{
case 0:
p_child = getpid();
exit(p_child % 10);
break;
case -1:
puts("ERROR");
break;
default:
wait_p = wait(&status);
printf("Child with PID: %d", wait_p);
if (WIFEXITED(status))
printf(" terminated with STATUS: %d\n", WEXITSTATUS(status));
break;
}
}
return (EXIT_FAILURE);
}
This code will execute an endless count of child processes. It must print only the first original(issued by THE one parent) 10. What am I doing wrong?
You have to handle the child processes directly in your first loop:
for (int i = 0; i < 10; i++)
{
p[i] = fork();
if (p[i] == 0) {
p_child = getpid();
exit(p_child % 10);
} else if (p[i] == -1) {
perror("fork");
}
}
and then wait for them in the second loop
for (int i = 0; i < 10; i++)
{
wait_p = wait(&status);
printf("Child with PID: %d", wait_p);
if (WIFEXITED(status))
printf(" terminated with STATUS: %d\n", WEXITSTATUS(status));
}
You cannot handle the case, that fork() returns in the child process (yielding 0 as return value), in your second loop, otherwise each child process in the first loop keeps forking more child processes.

How to run child processes simultaneously? in c

So here is my code that will take an int as an command line argument then fork N child processes (That run simultaneously). And then when each child ends, the parent will echo the child that child exit status.
But right now I can only do child by child but not simultaneously. How can I do it?
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
int main ( int argc, char *argv[] )
{
int i, pid, ran;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
srand(time(NULL));
ran = (rand() % 10) + 1 ;
if (pid < 0) {
printf("Error");
exit(1);
} else if (pid == 0) {
printf("Child (%d): %d\n", i + 1, getpid());
printf("Sleep for = %d\n", ran);
sleep(ran);
exit(ran);
} else {
int status = 0;
pid_t childpid = wait(&status);
printf("Parent knows child %d is finished. \n", (int)childpid);
}
}
}
You're calling wait() inside of the loop where you're spawning the children, so it won't continue the loop to start the next child until the current one is done.
You need to call wait() outside of the loop in a separate loop:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <time.h>
int main ( int argc, char *argv[] )
{
int i, pid, ran;
for(i = 0; i < atoi(argv[1]); i++) {
pid = fork();
srand(time(NULL));
ran = (rand() % 10) + 1 ;
if (pid < 0) {
printf("Error");
exit(1);
} else if (pid == 0) {
printf("Child (%d): %d\n", i + 1, getpid());
printf("Sleep for = %d\n", ran);
sleep(ran);
exit(ran);
}
}
for(i = 0; i < atoi(argv[1]); i++) {
int status = 0;
pid_t childpid = wait(&status);
printf("Parent knows child %d is finished. \n", (int)childpid);
}
}

Resources