#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char **argv) {
for(int i = 0; i < 10; i++) {
pid_t pid = fork();
if(pid == 0) {
while(1) {
pid_t pid2 = fork();
wait(NULL);
}
}
}
wait(NULL);
return(0);
}
Basically the program runs several hello world processes and closes with ctrl+C. How would I do the wait error? Like perror(wait). I think I have to use int status instead of NULL but unsure how to go about it when theres orphan processes involved.
The given code is
$ gcc -Wall above.c
$ ./a.out
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
^C (until ctrl C is hit)
$
The function perror is only useful when you know that a function failed and
errno is set, so you want to print an error message. You usually write
perror("something failed") right after the function that could fail and
sets errno (the documentation of the function will tell you whether the
function set errno on failure).
man perror
SYNOPSIS
#include <stdio.h>
void perror(const char *s);
#include <errno.h>
DESCRIPTION
The perror() function produces a message on standard error describing the last error encountered during a call to a system or library
function....
This has nothing to do with wait and it's parameter, it's only useful if
wait fails and you want to print an error message about wait failing.
man wait
SYNOPSIS
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *wstatus);
pid_t waitpid(pid_t pid, int *wstatus, int options);
DESCRIPTION
All of these system calls are used to wait for state changes in a child of the calling process...
...
wait() and waitpid()
The wait() system call suspends execution of the calling process until one of its children terminates. The call wait(&wstatus) is
equivalent to:
waitpid(-1, &wstatus, 0);
...
RETURN VALUE
wait(): on success, returns the process ID of the terminated child; on error, -1 is returned.
...
Each of these calls sets errno to an appropriate value in the case of an error.
If you just want to wait for a child to exit, you can do just wait(NULL).
However if you want to know the status of the child that exited, then you have
to pass a pointer to int.
int wstatus;
pid_t wp = wait(&wstatus);
if(wp == -1)
{
// here I use perror because if wait returns -1 then there
// was an error and errno is set
perror("could not wait for child\n");
exit(1);
}
if(WIFEXITED(wstatus))
printf("Child with pid %d exited normally with status %d\n", wp, WEXITSTATUS(wstatus));
else
printf("Child with pid %d exited abnormally\n", wp);
I personally prefer waitpid over wait, it gives you more control over the
child you are waiting.
See man wait
Related
I have been reading "The Linux Programming Interface". Chapter 27, Program execution.
I understand that the author demonstrates how we could implement the system call using exec and fork. However, the challenging part is handling signals. In particular I am confused with the following text
The first signal to consider is SIGCHLD. Suppose that the program
calling system() is also directly creating children, and has
established a handler for SIGCHLD that performs its own wait(). In
this situation, when a SIGCHLD signal is generated by the termination
of the child created by system(), it is possible that the signal
handler of the main program will be invoked and collect the child’s
status before system() has a chance to call waitpid(). (This is an
example of a race condition.)
The following is the code example without signal handling
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
int system(char *command)
{
int status;
pid_t childPid;
switch(childPid = fork())
{
case -1: /* Error */
return -1;
case 0: /* Child */
execl("/bin/sh", "sh", "-c", command, (char*) NULL);
_exit(127); /* If reached this line than execl failed*/
default: /* Parent */
if (waitpid(childPid), &status, 0) == -1)
return -1;
else
return status;
}
}
I know what the race condition ism but don't understand the whole scenario the author describes. In particular, I don't understand what "the program calling system" might be. What is the "main program"? Which process creates child procs?
Could someone, please, explain by giving examples how a race condition can arise? In C or in pseudocode.
You could have a SIGCHLD handler installed that does int ws; wait(&ws);.
If such a SIGCHLD handler is allowed to run in response to a SIGCHLD, it will race with the waitpid done in system, preventing system from successfully retrieving the exit status of the child if the handler wins the race.
For this reason, POSIX prescribes that SIGCHLD be blocked in system.
You could still have races with wait calls done in other signal handlers or other threads, but that would be a design error that POSIX system won't help you with.
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
int system(char *command)
{
int status;
pid_t childPid;
switch(childPid = fork())
{
case -1: /* Error */
return -1;
case 0: /* Child */
execl("/bin/sh", "sh", "-c", command, (char*) NULL);
_exit(127); /* If reached this line than execl failed*/
default: /* Parent */
/*usleep(1);*/
if (waitpid(childPid, &status, 0) == -1)
return -1;
else
return status;
}
}
void sigchld(int Sig){ int er=errno; wait(0); errno=er; }
int main()
{
/*main program*/
//main program has a sigchld handler
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = sigchld;
sigaction(SIGCHLD, &sa,0);
for(;;){
//the handler may occasionally steal the child status
if(0>system("true") && errno==ECHILD)
puts("Child status stolen!");
}
}
I'm trying to figure out how to use pipes. I've managed to set up pipes to send information from C1 (child 1) to C2 (child 2) however, when I try to do the opposite e.g. sending an integer "10" from C2 to C1 it gets stuck after my first system("ps -o pid,ppid,pgid,sess,comm") call. In general I don't seem to have problem sending stuff forward however problem seems to arise when I try to do stuff backwards. Am I missing some logical steps here?
./in reads an integer and prints it and ./out takes an integer and writes it. They seems to be working perfectly okay.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <assert.h>
#define READ 0
#define WRITE 1
int main()
{
int fds[2];
pid_t pid;
int test;
if(pipe(fds)<0)
{
exit(0);
}
pid = fork();
if(pid==0)
{//C1
test = close(READ); assert(test==0);
test = dup(fds[READ]); assert(test==READ);
test = close(fds[READ]); assert(test==0);
test = close(fds[WRITE]); assert(test==0);
sleep(1);
execlp("./in", "./in", NULL);
exit(1);
}
system("ps -o pid,ppid,pgid,sess,comm");
wait(0);
system("ps -o pid,ppid,pgid,sess,comm");
sleep(2);
pid = fork();
if(pid==0)
{//C2
test = close(WRITE); assert(test==0);
test = dup(fds[WRITE]); assert(test==WRITE);
test = close(READ); assert(test==0);
test = close(fds[READ]); assert(test==0);
test = close(fds[WRITE]); assert(test==0);
sleep(2);
execlp("./out", "./out", "10", NULL);
exit(0);
}
sleep(1);
test = close(fds[READ]); assert(test==0);
test = close(fds[WRITE]); assert(test==0);
system("ps -o pid,ppid,pgid,sess,comm");
wait(0);
system("ps -o pid,ppid,pgid,sess,comm");
return 0;
}
The reason your process is getting stuck is the wait() system call after calling system(). system() actually calls wait() itself so your wait() is waiting for child 1 to finish but child 1 is itself probably blocked on IO.
For bidirectional communication, you really need two pipes, one for communication in each direction. With the second pipe you do pretty much exactly what you do at the moment except for child 1 you replace stdout and for child 2 you replace stdin.
the dup() function returns a file descriptor.
The child code is overlaying that file descriptor with the returned value from a call to close() Usually the returned value from close() is 0, which is NOT a file descriptor.
There is no communication possible via a pipe in the posted code as both end of the pipe are closed before calling execlp() for both child 1 and child 2.
I'm using fork to create a process on a Mac platform, and wait for the child process to finish in the parent process. But the waitpid return -1 and errno is 4 (EINTR).
The example code, which can reproduce this problem, is as follows:
#include <iostream>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
int main(int argc, const char *argv[])
{
pid_t pid = ::fork();
if (pid == 0)
{
return 0;
}
int s = 0;
if (::waitpid(pid, &s, 0) == -1)
{
printf("The errno is :%d\n", errno); // <<<The errno is 4(EINTR) in my machine.
assert(false); // <<<<This will be hit if run in debugger.
}
return 0;
}
When I run this code in GDB or LLDB the assert will always be hit. If not run in debugger it will not return -1.
I think there is something I don't understand about how debugger or fork/waitpid works. So can anyone explain why this happen?
The debugger is sending a signal to the process. As WhozCraig said, these should be handled by detecting EINTR and calling waitpid again in a loop. Be aware that when running the child process in the debugger, the debugger likely changes the parent process to the debugger's PID, so waitpid on the child PID will fail thinking the child process has exited, even though it has not. When the debugger exits, it restores the PPID of the child to the original parent's PID.
My question sounds the same as this but it isn't:
Start a process in the background in Linux with C
I know how to do fork() but not how to send a process to the background. My program should work like a simple command unix shell that supports pipes and background processes. I could do pipe and fork but I don't know how to send a process to the background with & like the last line of the program:
~>./a.out uname
SunOS
^C
my:~>./a.out uname &
How to achieve the background process?
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#define TIMEOUT (20)
int main(int argc, char *argv[])
{
pid_t pid;
if(argc > 1 && strncmp(argv[1], "-help", strlen(argv[1])) == 0)
{
fprintf(stderr, "Usage: Prog [CommandLineArgs]\n\nRunSafe takes as arguments:\nthe program to be run (Prog) and its command line arguments (CommandLineArgs) (if any)\n\nRunSafe will execute Prog with its command line arguments and\nterminate it and any remaining childprocesses after %d seconds\n", TIMEOUT);
exit(0);
}
if((pid = fork()) == 0) /* Fork off child */
{
execvp(argv[1], argv+1);
fprintf(stderr,"Failed to execute: %s\n",argv[1]);
perror("Reason");
kill(getppid(),SIGKILL); /* kill waiting parent */
exit(errno); /* execvp failed, no child - exit immediately */
}
else if(pid != -1)
{
sleep(TIMEOUT);
if(kill(0,0) == 0) /* are there processes left? */
{
fprintf(stderr,"\Attempting to kill remaining (child) processes\n");
kill(0, SIGKILL); /* send SIGKILL to all child processes */
}
}
else
{
fprintf(stderr,"Failed to fork off child process\n");
perror("Reason");
}
}
The solution in plain English appears to be here:
How do I exec() a process in the background in C?
Catch SIGCHLD and in the the handler, call wait().
Am I on the right track?
Q: How do I send a process to the background?
A: In general, exactly what you're already doing: fork()/exec().
Q: What's not working as you expect?
I suspect maybe you also want a "nohup" (to completely disassociate the child from the parent).
The key to doing this is to run "setsid()" in the child process:
How to use fork() to daemonize a child process independant of it's parent?
http://www.enderunix.org/docs/eng/daemon.php
I was trying some process operations like fork()ing and exec()ing I tried this Example which in it the parent wait()s his child to return and test if his child ended normally (by exit()ing or return to his caller) or abnormally (receiving Signal like SIGABRT)
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<unistd.h>
#include <sys/wait.h>
int spawn (char* program, char** arg_list)
{
pid_t child_pid;
child_pid = fork ();
if (child_pid != 0)
return child_pid;
else {
execvp (program, arg_list);
abort();
}
}
int main ()
{
int child_status;
char* arg_list[] = {"ls","/",NULL};
spawn ("ls", arg_list);
wait (&child_status);
if (WIFEXITED (child_status))
printf ("the child process exited normally, with exit code %d\n",
WEXITSTATUS (child_status));
else
printf ("the child process exited abnormally\n");
return 0;
}
I expect to see the sentence"the child process exited abnormally" but I saw "the child process exited normally, with exit code 0"!!! even if the child ended by calling abort() which send a SIGABRT
any help?
thanks in advance
When you call any functions in the exec() family the currently executing program is replaced with the one specified in the call to exec(). That means that there is never a call to abort(). So the ls program runs to completeion then exits normally.