About wait() and waitpid() - c

So I wrote this code on C. I created a father, that has two child processes, and one becomes zombie. After one second it exits, and the father, that was waiting for him, finishes. The other child process remains orphan, and then finishes. My question is, what happens if I change the wait for waitpid.
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid;
int status, value;
pid = fork();
if (pid > 0) { // Father
pid = fork();
if (pid > 0) { // Father
wait(&status);
value = WEXITSTATUS(status);
if (value == 2)
printf("Child 2");
else if (value == 3)
printf("Child 1");
} else if (pid == 0) { //Child 2 - Orphan
sleep(4);
exit(2);
} else {
exit(1);
}
} else if (pid == 0) { // Child 1 - Zombie
sleep(1);
exit(3);
} else {
printf("Error al ejecutar el fork");
exit(1);
}
return 0;
}

Quoting wait/waitpid,
The waitpid() function is provided for three reasons:
To support job control
To permit a non-blocking version of the wait() function
To permit a library routine, such as system() or pclose(), to wait for its children without interfering with other terminated children for which the process has not waited
and
The waitpid() function shall be equivalent to wait() if the pid argument is (pid_t)-1 and the options argument is 0. Otherwise, its behavior shall be modified by the values of the pid and options arguments.
So the behavior of waitpid() depends on its arguments.

Related

Check whether Child Process has terminated in C on Unix without blocking

I would like to check whether / when a child process has terminated in C on Unix. It's not supposed to be blocking, rather a short check in a loop.
My code:
pid_t pid = fork();
if (pid > 0)
// Parent Process
while (1) {
// Do a short check whether Child has already terminated if yes break the loop.
// Ik that it's possible to use waitpid(pid, &status, 0) but that blocks the whole loop until the child has terminated
}
if (pid == 0)
printf("child process born");
exit(0);
Thx in advance
The third argument to waitpid is a set of flags. If you pass WNOHANG to this argument, the function will return immediately if no children have yet exited.
You can then check if waitpid returned 0. If so, no child exited and you wait and try again.
while (1) {
pid_t rval = waitpid(pid, &status, WNOHANG);
if (rval == -1) {
perror("waitpid failed");
exit(1);
} else if (rval == 0) {
sleep(1);
} else {
break;
}
}
Traditional way is:
#include <errno.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
int exist(pid_t pid) {
return kill(pid, 0) > 0 || errno != ESRCH;
}
int main(int ac, char **av) {
while (--ac > 0) {
pid_t p = strtol(*++av, 0, 0);
printf("%d %s\n", p, exist(p) ? "exists" : "doesn't exist");
}
return 0;
}
It doesn't care about parent : child relation (whereas wait derivatives do), and works even if you don't have permission to affect the process.

Why does WIFEXITED return false after child process exits?

I've got this simple program that creates a child process which immediately calls exit(). So in the parent process I'm expecting WIFEXITED(status) to evaluate as true, but it's not. Instead, WIFSTOPPED(status) evaluates as true and "stopped" is printed. Can anyone explain why I'm getting this behavior? I'm running on OS X and compiling with gcc. Thanks!
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/wait.h>
int main(void)
{
int pid;
int status;
pid = fork();
if (pid < 0)
printf("fork failed\n");
else if (pid == 0)
{
wait(&status);
if (WIFEXITED(status))
printf("exited\n");
else if (WIFSTOPPED(status))
printf("stopped\n");
}
else
exit(0);
return (0);
}
You have the logic for the child and parent backwards. The parent is exiting immediately and the child is calling wait. Since the child has no children, wait is returning an error (and not touching status) since the child has no children (ECHILD), then you're testing the (uninitialized) value of status and acting on it, resulting in undefined behavior.
Change:
else if (pid == 0)
to:
else if (pid > 0)
and it should work as expected.

Invalid commands for child process in background in C

I have the following code in C:
if ((childpid = fork()) == 0) {
if (execvp(argv[0], argv) < 0) {
//execute failed
exit(1);
}
} else if (childpid < 0) {
//fork failed
} else {
//if execvp failed don't do anything here
//else do something
}
What I want is:
I enter a command.
If it is not executable it should not do anything but wait for my next entered command.
If it is executable it should do some things in the parent process.
If I enter e.g. sleep 1m it should execute it in my child process, do things in the parent process and should be still able to execute more jobs (this works fine). But when I execute something like abcdef (invalid command) it does the stuff in my parent process anyway.
Can someone tell me how the code should look like?
I also tried the following:
void signalHandler(int signal)
{
if (signal==SIGCHLD) {
printf("Child ended\n");
wait(NULL);
}
}
//in main
signal(SIGCHLD,signalHandler);
//...
if ((childpid = fork()) == 0) {
if (execvp(t_argv[0], t_argv) < 0) {
kill(getppid(),SIGCHLD);
}
}
Is this correct?
This way I get an error afterwards (when it's finished).
waitpid(childpid, &status, WNOHANG)
tells me it finished with an error (-1).
One possible solution is to use a pair of anonymous pipes, where the child process writes in the write-end of the pipe any status it needs to pass on to the parent. Then in the parent you check the read-end of the pipe, if you don't receive anything before the child-process exits then everything was okay and the child process successfully executed the program.
If the parent does receive anything before the child process exits, then it means that the exec call failed.
One possible solution is to terminate abnormally with a signal (for example, SIGUSR1) and check for that in the parent. This assumes that whatever program you execute in the child never terminates with SIGUSR1 - a reasonable assumption in most cases, I'd say. The parent can then check the termination status of the child.
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
pid_t childpid;
if ((childpid = fork()) == 0) {
if (execvp(argv[1], &argv[1]) < 0) {
raise(SIGUSR1);
}
} else if (childpid < 0) {
perror("fork()");
exit(EXIT_FAILURE);
} else {
int term_status;
if (wait(&term_status) < 0) {
perror("wait()");
exit(EXIT_FAILURE);
}
if (WIFSIGNALED(term_status) && WTERMSIG(term_status) == SIGUSR1) {
printf("execvp failed\n");
} else {
printf("success\n");
}
}
return 0;
}
Side note: you probably want execvp(argv[1], &argv[1]), because execvp(argv[0], argv) will execute this same program over and over.
Again, this works as long as the process executed by execvp(2) never terminates with SIGUSR1. Notice that if the process executed by execvp(2) terminates with SIGSEGV or other abnormal termination condition, it is still seen as success by the parent.

Interprocess Communication fork() - Timing wait() and/or sleep()

I've been asked to develop the consumer (client) side to a producer (server), where the producer creates processes, waits until the consumer has read shared memory and deleted processes, then passes control back to the producer for the killing of processes and the shutting down of the shared memory block.
I've researched the difference between sleep and wait, and realise that as soon as fork() is called, the child process begins running.
The below code is after the creation of processes and checks if they're parent processes. If they are, they wait(0). *Now for my question, how do I know where the code in the consumer starts to be executed, and how do I pass it back? *
else if(pid > 0)
{
wait(0);
}
Below can be seen the main loop the producer uses.
int noToCreate = atoi(argv[2]); // (user inputs on cmd line "./prod 20 10 5" - 20 size of shared mem, 10 process to be created, 5 processes to be deleted)
while(*memSig != 2)
{
while(*memSig == 1) // set memsignature to sleep while..
{
sleep(1);
}
for(B = 0; B < noToCreate; B++)
{
pid = fork();
if(pid == -1)
{
perror("Error forking");
exit(1);
}
else if(pid > 0)
{
wait(0);
}
else
{
srand(getpid());
while(x == 0)
{
if(*randNum == 101)
{
*randNum = rand() % (100 -
1) + 1;
*pidNum = getpid();
printf("priority: %d
Process ID: %d \n", *randNum, *pidNum);
x = 1;
}
else
{
*randNum++;
*pidNum++;
}
}
exit(0);
}
} /* Closes main for loop */
if(*memSig == 0)
{
*memSig = 1;
}
} /* Closes main while loop */
Thanks a bunch guys :)
wait make parent blocked until any child end .You can use waitpid let parent wait specific child.
When a child process end, it will set a signal SIG_CHILD.
The pid is zero for the child process after the fork, so you are in the child process at your call to the srand function.
The other pid is that for the child process which allows he original thread to wait for the child to finish. If you wish to pass data between the processes consider using a pipe. A popen call returns two file descriptors, one to write end and the other to the read end. Set this up before the fork and the two processes can communicate.
wait makes the parent wait for any child to terminate before going on (preferably use waitpid to wait for a certain child), whereas sleep puts the process to sleep and resumes it, as soon as the time passed as argument is over.
Both calls will make the process block.
And it is NOT said that the child will run immediately, this is indeterminate behavior!
If you want to pass data between producer and consumer, use pipes or *NIX sockets, or use the return-value of exit from the child if a single integer is sufficient.
See man wait, you can get the return value of the child with the macro WEXITSTATUS.
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int
main(int argc, char *argv[])
{
pid_t cpid, w;
int status;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code executed by child */
printf("Child PID is %ld\n", (long) getpid());
if (argc == 1)
pause(); /* Wait for signals */
_exit(atoi(argv[1]));
} else { /* Code executed by parent */
do {
w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(status)) {
printf("exited, status=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("killed by signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("stopped by signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("continued\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
exit(EXIT_SUCCESS);
}
}

Father process was block while set SIGCHLD

This is my code, I had simplified it.
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
void signal_handle(int sig)
{
int status;
wait(&status);
}
int main()
{
pid_t pid = fork();
if (pid > 0)
signal(SIGCHLD, signal_handle);
if (pid == 0) {
if (execl("/bin/ls", "/", (char *)0) < 0)
{
perror("execl");
return -1;
}
}
return 0;
}
When I run it, I found that, son process print the run result, but father process
was blocked.
what should I do, if a father has much son process? set wait(&status) for every one?
I'm very sorry for my bad english!
I don't see why the parent process would hang, and it doesn't on my machine.
After the fork(), the parent process invokes signal() to set the signal handler and immediately exits. The child, meanwhile, executes ls to print the contents of the current directory (because the "/" argument becomes argv[0], the program name, and there are no additional arguments). It then exits too. Except under very unlikely circumstances, the parent has exited long before the child completes.
If you want the parent process to wait until it gets the 'death of a child' signal, add a call to pause() in the parent-only execution path:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
static void signal_handle(int sig)
{
int status;
pid_t pid = wait(&status);
printf("%d: signal %d child %d status 0x%.4X\n", (int)getpid(), sig, (int)pid, status);
}
int main(void)
{
pid_t pid = fork();
if (pid > 0)
{
signal(SIGCHLD, signal_handle);
pause();
}
else if (pid == 0)
{
execl("/bin/ls", "ls", "/", (char *)0);
perror("execl");
return -1;
}
else
perror("fork");
return 0;
}

Resources