Let suppose that process-A calls fork
pid = fork();
...
waitpid( pid, ...);
Is it possible, that between these calls (fork and waitpid) proccess-B, which is created by fork(), may to finish? Then some new process-C starts and gets a pid is equal to an old pid of process-B. And after that waitpid will waits the end of process-C, not B.
The exec-family calls don't return a value and a control if they are successful. The exec starts new process instead current process but keeps a process pid. Is it an any guaranteed way to do fork/vfork + exec + waitpid as a truly "atomic" operation and to get result of a process which is created by exec?
Does bash/shell run, wait commands and return their results in an "atomic" way?
Related
I am reading http://www.tutorialspoint.com/unix_system_calls/waitpid.htm regarding the waitpid function. It says this about the first parameter, pid,
-1 meaning wait for any child process.
0 meaning wait for any child process whose process group ID is equal to that of the calling process.
May I know what does "any child process" mean, any child process of whom? What sort of situation would one need to use a value of -1?
Ignoring the case where your process has pid 1 (in some process namespace - in which case orphaned processes will be reparented), there is only one difference between 0 and -1.
With -1, any child will be waited for. With 0, children that have called setpgid will not be waited for.
"child" is defined as the process created by fork from your process (but not from any child - you cannot wait for grandchildren, though on Linux I think you can do something similar by polling /proc/<pid>). Note that execve does not affect anything.
By “any child process”, it means any process that is a child of the process that called waitpid.
You would use a pid argument of -1 if you want to wait for any of your children. The most common use is probably when you have multiple children and you know at least one has exited because you received SIGCHLD. You want to call waitpid for each child that has exited, but you don't know exactly which ones have exited. So you loop like this:
while (1) {
int status;
pid_t childPid = waitpid(-1, &status, WNOHANG);
if (childPid <= 0) {
break;
}
// Do whatever you want knowing that the child with pid childPid
// exited. Use status to figure out why it exited.
}
Here below i have a simple code snippet of application which takes request from several clients and invokes mathematical operations through exec and waits for result from invoked processes to return those results to the respective clients through pipes
case '+':
fret=fork();
if(fret==-1)
perror(" error in forking at add\n");
else if(fret==0)
{//child
sprintf(s_rp,"%d",p_op[0]);
sprintf(s_wp,"%d",p_op[1]);
argm[0]="add";
if((ret= execve(argm[0],argm,argp))== -1)
{
printf("exeve of add failed \n");
exit(1);
}
}
else
{//parent
write(p_op[1],&request,sizeof(request));
if((ret=waitpid(fret,&x,0))==-1)
perror("Error with wait at +\n");
read(p_op[0],&result,sizeof(result));
write(fd_res,&result,sizeof(result));
}
break;
Here i am facing a simple issue of parent being executing first fastly,which makes the waitpid() to fail,generally waitpid() waits for the child to exit but in my case the child is not even created when parent encounters waitpid() fails
My question is instead of using a sleep() (which has solved my problem but making the program run slow !! ) or any IPC How can i make sure the fork to execute my child first than my parent
when i thought of this, some approaches reeled in my mind, like making use of signals to block parent or semaphores to achieve atomicity is there any simple approach that makes sure my child will execute first and then my parent start execution
The waitpid function will BLOCK until the specified process ends. Although some other reasons such as EINTR can cause waitpid to return -1, it is very easy to solve that by placing the waitpid call into a loop. For example, if waitpid call returned -1 and errno == EINTR, then just continue the loop. See http://linux.die.net/man/3/waitpid about the return value.
Your waitpid call will NEVER be executed before the child process is created! Obviously, the waitpid function is called after the fork syscall, and the return value of the fork syscall is not -1. So, at that time, the fork call has already returned which means that the child process would already exist.
I am not handling SIGCHLD in my code. Still my process is removed immediately after termination. I want it to become zombie process.
If I set SIGCHLD to SIG_DFL then, will it work? How do I set SIGCHLD to SIG_DFL?
I want process to become zombie, so I can read the child status in parent after waitpid.
From your question history you seem to be tying yourself in knots over this. Here is the outline on how this works:
The default disposition of SIGCHLD is ignore. In other words, if you do nothing, the signal is ignored but the zombie exists in the process table. This why you can wait on it at any time after the child dies.
If you set up a signal handler then the signal is delivered and you can reap it as appropriate but the (former) child is still a zombie between the time it dies and the time you reap it.
If you manually set SIGCHLD's disposition to SIG_IGN via signal then the semantics are a little different than they are in item 1. When you manually set this disposition the OS immediately removes the child from the process table when it dies and does not create a zombie. Consequently there is no longer any status information to reap and wait will fail with ECHILD. (Linux kernels after 2.6.9 adhere to this behavior.)
So your final target is to read return code in parent process after your child process exit? I don't see this has any matter with signal. Some example code is:
short pid;
if((pid == fork()) == 0) {
// Child process do some thing here.
exit(n);
} else {
int returnCode;
while(pid != wait(&returnCode));
// the child has terminated with returnCode
// wait is blocking system call so u don't need to worry about busy waiting.
}
I have a task/process currently running. I would like to schedule another task to start when the first one finished.
How can I do that in linux ?
(I can't stop the first one, and create a script to start one task after the other)
Somewhat meager spec, but something along the line of
watch -n 1 'pgrep task1 || task2'
might do the job.
You want wait.
Either the system call in section 2 of the manual, one of it's varients like waitpid or the shell builtin which is designed explicitly for this purpose.
The shell builtin is a little more natural because both processes are childred of the sell, so you write a script like:
#!/bin/sh
command1 arguments &
wait
command2 args
To use the system calls you will have to write a program that forks, launches the first command in the child then waits before execing the second program.
The manpage for wait (2) says:
wait() and waitpid()
The wait() system call suspends execution of the current process until one of its children terminates. The call wait(&status) is equivalent to:
waitpid(-1, &status, 0);
The waitpid() system call suspends execution of the current process until a child
specified by pid argument has changed state.
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
int main(){
pid_t pid = fork();
if(pid==0){
system("watch ls");
}
else{
sleep(5);
killpg(getpid(),SIGTERM); //to kill the complete process tree.
}
return 0;
}
Terminal:
anirudh#anirudh-Aspire-5920:~/Desktop/testing$ gcc test.c
anirudh#anirudh-Aspire-5920:~/Desktop/testing$ ./a.out
Terminated
for the first 5 secs the output of the "watch ls" is shown and then it terminates because I send a SIGTERM.
Question: How can a process kills itself ? I have done kill(getpid(),SIGTERM);
My hypothesis:
so during the kill() call the process switches to kernel mode. The kill call sends the SIGTERM to the process and copies it in the process's process table. when the process comes back to user mode it sees the signal in its table and it terminates itself (HOW ? I REALLY DO NOT KNOW )
(I think I am going wrong (may be a blunder) somewhere in my hypothesis ... so Please enlighten me)
This code is actually a stub which I am using to test my other modules of the Project.
Its doing the job for me and I am happy with it but there lies a question in my mind how actually a process kills itself. I want to know the step by step hypothesis.
Thanks in advance
Anirudh Tomer
Your process dies because you are using killpg(), that sends a signal to a process group, not to a process.
When you fork(), the children inherits from the father, among the other things, the process group. From man fork:
* The child's parent process ID is the same as the parent's process ID.
So you kill the parent along with the child.
If you do a simple kill(getpid(), SIGTERM) then the father will kill the child (that is watching ls) and then will peacefully exit.
so during the kill() call the process switches to kernel mode. The kill call sends the SIGTERM to the process and copies it in the process's process table. when the process comes back to user mode it sees the signal in its table and it terminates itself (HOW ? I REALLY DO NOT KNOW )
In Linux, when returning from the kernel mode to the user-space mode the kernel checks if there are any pending signals that can be delivered. If there are some it delivers the signals just before returning to the user-space mode. It can also deliver signals at other times, for example, if a process was blocked on select() and then killed, or when a thread accesses an unmapped memory location.
I think it when it sees the SIGTERM signal in its process tables it first kills its child processes( complete tree since I have called killpg() ) and then it calls exit().
I am still looking for a better answer to this question.
kill(getpid(), SIGKILL); // itself I think
I tested it after a fork with case 0: and it quit regular from separate parent process.
I don't know if this is a standard certification method ....
(I can see from my psensor tool that CPU usage return in 34% like a normal program code with
a counter stopped ) .
This is super-easy in Perl:
{
local $SIG{TERM} = "IGNORE";
kill TERM => -$$;
}
Conversion into C is left as an exercise for the reader.