no error thrown with exit(0) in the child process of vfork()
Hi all, I have been trying to create a process using vfork(). And both of the child and the parent process execute it in the same address space. So, if I execute exit(0) in the child process, it should throw some error right. Since the execution is happening in child process first and if I release all the resources by using exit(0) in the child process then parent should be deprived of the resources and should throw some errors right ?? In the following code, however the process ran fine even though I have exit(0) in the child process ........ #include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> int main() { int val,i=0; val=vfork(); if(val==0) { printf("\nI am a child process.\n"); printf(" %d ",i++); exit(0); } else { printf("\nI am a parent process.\n"); printf(" %d ",i); } return 0; } // The program is running fine ..... But as I have read it should throw some error right ?? I don't know what I am missing . Please point out the point I'm missing. Thanking you in advance.
On Fri, 18 Jan 2013 19:59:38 +0530, Niroj Pokhrel said:
I have been trying to create a process using vfork(). And both of the child and the parent process execute it in the same address space. So, if I execute exit(0) in the child process, it should throw some error right.
Why do you think it should throw an error?
Since the execution is happening in child process first and if I release all the resources by using exit(0) in the child process then parent should be deprived of the resources and should throw some errors right ??
No, because those resources that were shared across a fork() or vfork() were in general *multiple references* to the same resource. As an example - imagine a flagpole. You grab it with your hand, you're now holding it. You invite your friend to come over and grab it with his hand - now he's holding it too. But either one of you can let go of the flagpole - and the other one is still holding the flagpole until *they* let go. And the order you let go doesn't matter in this case - which is important because your example code has a race condition.... Note that there are other cases where the order people let go *does* matter. This is when you start having to worry about "locking order" and things like that.
In the following code, however the process ran fine even though I have exit(0) in the child process ........
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> int main() { int val,i=0; val=vfork(); if(val==0) { printf("\nI am a child process.\n");
Note that printf() gets interesting due to stdio buffering. You probably want to call setbuf() and guarantee line-buffering of the output if you're playing these sorts of games - the buffering can totally mask a real race condition or other bug.
printf(" %d ",i++); exit(0); } else {
/* race condition here - may want wait() or waitpid() to synchronize? */
printf("\nI am a parent process.\n"); printf(" %d ",i); } return 0; } // The program is running fine ..... But as I have read it should throw some error right ?? I don't know what I am missing . Please point out the point I'm missing. Thanking you in advance.
You're also missing the fact that after the vfork(), there's no real guarantee of which will run first - which means that the parent can race and output the 'printf("%d",i)" *before* the child process gets a chance to do the i++. (Aside - for a while, there was a patch in place that ensured that the child would run first, on the theory that the child would often do something short that the parent was waiting on, so scheduling parent-first would just result in the parent running, blocking to wait, and we end up running the child anyhow before the parent could continue. It broke an *amazing* amount of stuff in userspace because often the child would exit() before the parent was ready to deal with the child process's termination. Usual failure mode was the parent would set a SIGCHLD handler, and wait for the signal which never happened because the SIGCHLD actually fired *before* the handler was set up). (And on non-cache-coherent systems, it's even possible that the i++ happens on a different CPU first, and the CPU running the parent process never becomes aware of it. See 'Documentation/memory-barriers.txt' in the Linux source for more info on how this works for data inside the kernel. This example is out in userspace, so other techniques are required instead to do cross-CPU synchronization.
Completely agree with the flagpole analogy. In case of multiple references to a shared resource, the system does not consider the resource free as long as even one reference to it exists. About the race-condition though i am not so sure. The parent process is supposed to block on vfork() until the child process returns. This is a crucial difference between vfork() and the more common fork(). http://linux.die.net/man/2/vfork http://linux.die.net/man/2/fork So in the above case i imagine the flow would be as follows: 1. Parent process starts execution. 2. vfork() called spawns child process. 3. Child process executes(parent blocked at vfork). 4. Child process completes and exits. 5. Parent process continues. 6. Parent process completes and exits. The additonal references to resources(memory for example) are created in step2 while spawning the child process. These references are deleted when step4 completes. But the original references created by the parent process in step1 still exist till end of step6 and hence resources will NOT be freed in the middle. I believe the race condition is entirely plausible if fork() is used instead of vfork(). What interests me is the following line in the vfork manual page: "...the behavior is undefined if the process created by vfork() either modifies any data other than a variable of type *pid_t* used to store the return value from vfork()..." So the behaviour is undefined for modifying the variable "i"? Does this mean that "i++" in the child process is NOT guaranteed to always reflect in the parent process? (Though in either case there still wont be any error/crash, just that the one outcome is not guaranteed across all platforms/archs/implementations). Is it so? Any real-world experiences of using vfork anyone?... regards CVS On Sat, Jan 19, 2013 at 3:19 AM, <Valdis.Kletnieks@vt.edu> wrote:
On Fri, 18 Jan 2013 19:59:38 +0530, Niroj Pokhrel said:
I have been trying to create a process using vfork(). And both of the
child
and the parent process execute it in the same address space. So, if I execute exit(0) in the child process, it should throw some error right.
Why do you think it should throw an error?
Since the execution is happening in child process first and if I release all the resources by using exit(0) in the child process then parent should be deprived of the resources and should throw some errors right ??
No, because those resources that were shared across a fork() or vfork() were in general *multiple references* to the same resource.
As an example - imagine a flagpole. You grab it with your hand, you're now holding it. You invite your friend to come over and grab it with his hand - now he's holding it too.
But either one of you can let go of the flagpole - and the other one is still holding the flagpole until *they* let go. And the order you let go doesn't matter in this case - which is important because your example code has a race condition....
Note that there are other cases where the order people let go *does* matter. This is when you start having to worry about "locking order" and things like that.
In the following code, however the process ran fine even though I have exit(0) in the child process ........
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> int main() { int val,i=0; val=vfork(); if(val==0) { printf("\nI am a child process.\n");
Note that printf() gets interesting due to stdio buffering. You probably want to call setbuf() and guarantee line-buffering of the output if you're playing these sorts of games - the buffering can totally mask a real race condition or other bug.
printf(" %d ",i++); exit(0); } else {
/* race condition here - may want wait() or waitpid() to synchronize? */
printf("\nI am a parent process.\n"); printf(" %d ",i); } return 0; } // The program is running fine ..... But as I have read it should throw some error right ?? I don't know
what I
am missing . Please point out the point I'm missing. Thanking you in advance.
You're also missing the fact that after the vfork(), there's no real guarantee of which will run first - which means that the parent can race and output the 'printf("%d",i)" *before* the child process gets a chance to do the i++.
(Aside - for a while, there was a patch in place that ensured that the child would run first, on the theory that the child would often do something short that the parent was waiting on, so scheduling parent-first would just result in the parent running, blocking to wait, and we end up running the child anyhow before the parent could continue. It broke an *amazing* amount of stuff in userspace because often the child would exit() before the parent was ready to deal with the child process's termination. Usual failure mode was the parent would set a SIGCHLD handler, and wait for the signal which never happened because the SIGCHLD actually fired *before* the handler was set up).
(And on non-cache-coherent systems, it's even possible that the i++ happens on a different CPU first, and the CPU running the parent process never becomes aware of it. See 'Documentation/memory-barriers.txt' in the Linux source for more info on how this works for data inside the kernel. This example is out in userspace, so other techniques are required instead to do cross-CPU synchronization.
_______________________________________________ Kernelnewbies mailing list Kernelnewbies@kernelnewbies.org http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
On Sat, Jan 19, 2013 at 5:49 AM, <Valdis.Kletnieks@vt.edu> wrote:
On Fri, 18 Jan 2013 19:59:38 +0530, Niroj Pokhrel said:
I have been trying to create a process using vfork(). And both of the child and the parent process execute it in the same address space. So, if I execute exit(0) in the child process, it should throw some error right.
Why do you think it should throw an error?
Since the execution is happening in child process first and if I release all the resources by using exit(0) in the child process then parent should be deprived of the resources and should throw some errors right ??
No, because those resources that were shared across a fork() or vfork() were in general *multiple references* to the same resource.
Yes, correct, Valdis is right. Normally, when u free resources (which is what "exit()" will do), u must also remember to check something call "reference count". Basic malloc() and free() memory management internal data structure also comes with other info like size (which is 4 bytes BEHIND the first byte where the pointer points to, and other info). More info: http://stackoverflow.com/questions/1957099/how-do-free-and-malloc-work-in-c but what is lacking is reference counting. But this feature is available in Java and C++ libraries for memory allocation. Concept discussed here: http://stoneship.org/essays/c-reference-counting-and-you/ Interesting....
As an example - imagine a flagpole. You grab it with your hand, you're now holding it. You invite your friend to come over and grab it with his hand - now he's holding it too.
But either one of you can let go of the flagpole - and the other one is still holding the flagpole until *they* let go. And the order you let go doesn't matter in this case - which is important because your example code has a race condition....
Note that there are other cases where the order people let go *does* matter. This is when you start having to worry about "locking order" and things like that.
In the following code, however the process ran fine even though I have exit(0) in the child process ........
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> int main() { int val,i=0; val=vfork(); if(val==0) { printf("\nI am a child process.\n");
Note that printf() gets interesting due to stdio buffering. You probably want to call setbuf() and guarantee line-buffering of the output if you're playing these sorts of games - the buffering can totally mask a real race condition or other bug.
printf(" %d ",i++); exit(0); } else {
/* race condition here - may want wait() or waitpid() to synchronize? */
printf("\nI am a parent process.\n"); printf(" %d ",i); } return 0; } // The program is running fine ..... But as I have read it should throw some error right ?? I don't know what
I
am missing . Please point out the point I'm missing. Thanking you in advance.
You're also missing the fact that after the vfork(), there's no real guarantee of which will run first - which means that the parent can race and output the 'printf("%d",i)" *before* the child process gets a chance to do the i++.
I don't think there is any issue here (racing, or child calling exit before parent called exit()). Read the man-page: vfork() differs from fork(2) in that the parent is suspended until the child terminates (either normally, by calling _exit(2), or abnormally, after delivery of a fatal signal), or it makes a call to execve(2). Until that point, the child shares all memory with its parent, includ‐ ing the stack. The child must not return from the current function or call exit(3), but may call _exit(2). So: 1. if parent is suspended, it also means no contention issue, child can use the "i++", which is single-copy in memory, and parent is not even touching it. 2. It is clearly documented above - the vfork()'s child CAN exit() before the parent calling exit(). 3. More important is to understand the the use of vfork() - u don't to create a duplicate memory page table because u want to call execve() immediately, which will overwrite everything in memory with the new binary inside execve() command. Hope I got it right?
(Aside - for a while, there was a patch in place that ensured that the child would run first, on the theory that the child would often do something short that the parent was waiting on, so scheduling parent-first would just result in the parent running, blocking to wait, and we end up running the child anyhow before the parent could continue. It broke an *amazing* amount of stuff in userspace because often the child would exit() before the parent was ready to deal with the child process's termination. Usual failure mode was the parent would set a SIGCHLD handler, and wait for the signal which never happened because the SIGCHLD actually fired *before* the handler was set up).
(And on non-cache-coherent systems, it's even possible that the i++ happens on a different CPU first, and the CPU running the parent process never becomes aware of it. See 'Documentation/memory-barriers.txt' in the Linux source for more info on how this works for data inside the kernel. This example is out in userspace, so other techniques are required instead to do cross-CPU synchronization.
_______________________________________________ Kernelnewbies mailing list Kernelnewbies@kernelnewbies.org http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
-- Regards, Peter Teoh
On Sat, Jan 19, 2013 at 10:43 AM, Peter Teoh <htmldeveloper@gmail.com>wrote:
On Sat, Jan 19, 2013 at 5:49 AM, <Valdis.Kletnieks@vt.edu> wrote:
On Fri, 18 Jan 2013 19:59:38 +0530, Niroj Pokhrel said:
I have been trying to create a process using vfork(). And both of the child and the parent process execute it in the same address space. So, if I execute exit(0) in the child process, it should throw some error right.
Why do you think it should throw an error?
Since the execution is happening in child process first and if I release all the resources by using exit(0) in the child process then parent should be deprived of the resources and should throw some errors right ??
No, because those resources that were shared across a fork() or vfork() were in general *multiple references* to the same resource.
Yes, correct, Valdis is right. Normally, when u free resources (which is what "exit()" will do), u must also remember to check something call "reference count".
Basic malloc() and free() memory management internal data structure also comes with other info like size (which is 4 bytes BEHIND the first byte where the pointer points to, and other info). More info:
http://stackoverflow.com/questions/1957099/how-do-free-and-malloc-work-in-c
but what is lacking is reference counting. But this feature is available in Java and C++ libraries for memory allocation.
Concept discussed here:
http://stoneship.org/essays/c-reference-counting-and-you/
Interesting....
As an example - imagine a flagpole. You grab it with your hand, you're now holding it. You invite your friend to come over and grab it with his hand - now he's holding it too.
But either one of you can let go of the flagpole - and the other one is still holding the flagpole until *they* let go. And the order you let go doesn't matter in this case - which is important because your example code has a race condition....
Note that there are other cases where the order people let go *does* matter. This is when you start having to worry about "locking order" and things like that.
In the following code, however the process ran fine even though I have exit(0) in the child process ........
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> int main() { int val,i=0; val=vfork(); if(val==0) { printf("\nI am a child process.\n");
Note that printf() gets interesting due to stdio buffering. You probably want to call setbuf() and guarantee line-buffering of the output if you're playing these sorts of games - the buffering can totally mask a real race condition or other bug.
printf(" %d ",i++); exit(0); } else {
/* race condition here - may want wait() or waitpid() to synchronize? */
printf("\nI am a parent process.\n"); printf(" %d ",i); } return 0; } // The program is running fine ..... But as I have read it should throw some error right ?? I don't know
what I
am missing . Please point out the point I'm missing. Thanking you in advance.
You're also missing the fact that after the vfork(), there's no real guarantee of which will run first - which means that the parent can race and output the 'printf("%d",i)" *before* the child process gets a chance to do the i++.
I don't think there is any issue here (racing, or child calling exit before parent called exit()). Read the man-page:
vfork() differs from fork(2) in that the parent is suspended until the child terminates (either normally, by calling _exit(2), or abnormally, after delivery of a fatal signal), or it makes a call to execve(2). Until that point, the child shares all memory with its parent, includ‐ ing the stack. The child must not return from the current function or call exit(3), but may call _exit(2).
So:
1. if parent is suspended, it also means no contention issue, child can use the "i++", which is single-copy in memory, and parent is not even touching it.
2. It is clearly documented above - the vfork()'s child CAN exit() before the parent calling exit().
Sorry my mistake, documentation say may call "_exit(2)", and vfork() cannot return, but not exit(), which is reserved only for the parent process to call. But since it cannot return (as the only way to exit is to call _exit()), it is as good as not having any parent, or parent resources should be consumed or processed in the parent before it called vfork. Well, it is just a design issue.
3. More important is to understand the the use of vfork() - u don't to create a duplicate memory page table because u want to call execve() immediately, which will overwrite everything in memory with the new binary inside execve() command.
Hope I got it right?
(Aside - for a while, there was a patch in place that ensured that the child would run first, on the theory that the child would often do something short that the parent was waiting on, so scheduling parent-first would just result in the parent running, blocking to wait, and we end up running the child anyhow before the parent could continue. It broke an *amazing* amount of stuff in userspace because often the child would exit() before the parent was ready to deal with the child process's termination. Usual failure mode was the parent would set a SIGCHLD handler, and wait for the signal which never happened because the SIGCHLD actually fired *before* the handler was set up).
(And on non-cache-coherent systems, it's even possible that the i++ happens on a different CPU first, and the CPU running the parent process never becomes aware of it. See 'Documentation/memory-barriers.txt' in the Linux source for more info on how this works for data inside the kernel. This example is out in userspace, so other techniques are required instead to do cross-CPU synchronization.
_______________________________________________ Kernelnewbies mailing list Kernelnewbies@kernelnewbies.org http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
-- Regards, Peter Teoh
-- Regards, Peter Teoh
On Sat, Jan 19, 2013 at 8:13 AM, Peter Teoh <htmldeveloper@gmail.com> wrote:
On Sat, Jan 19, 2013 at 5:49 AM, <Valdis.Kletnieks@vt.edu> wrote:
On Fri, 18 Jan 2013 19:59:38 +0530, Niroj Pokhrel said:
I have been trying to create a process using vfork(). And both of the child and the parent process execute it in the same address space. So, if I execute exit(0) in the child process, it should throw some error right.
Why do you think it should throw an error?
Since the execution is happening in child process first and if I release all the resources by using exit(0) in the child process then parent should be deprived of the resources and should throw some errors right ??
No, because those resources that were shared across a fork() or vfork() were in general *multiple references* to the same resource.
Yes, correct, Valdis is right. Normally, when u free resources (which is what "exit()" will do), u must also remember to check something call "reference count".
Basic malloc() and free() memory management internal data structure also comes with other info like size (which is 4 bytes BEHIND the first byte where the pointer points to, and other info). More info:
http://stackoverflow.com/questions/1957099/how-do-free-and-malloc-work-in-c
but what is lacking is reference counting. But this feature is available in Java and C++ libraries for memory allocation.
Concept discussed here:
http://stoneship.org/essays/c-reference-counting-and-you/
Interesting....
As an example - imagine a flagpole. You grab it with your hand, you're now holding it. You invite your friend to come over and grab it with his hand - now he's holding it too.
But either one of you can let go of the flagpole - and the other one is still holding the flagpole until *they* let go. And the order you let go doesn't matter in this case - which is important because your example code has a race condition....
Note that there are other cases where the order people let go *does* matter. This is when you start having to worry about "locking order" and things like that.
In the following code, however the process ran fine even though I have exit(0) in the child process ........
#include<stdio.h> #include<stdlib.h> #include<sys/types.h> #include<unistd.h> int main() { int val,i=0; val=vfork(); if(val==0) { printf("\nI am a child process.\n");
Note that printf() gets interesting due to stdio buffering. You probably want to call setbuf() and guarantee line-buffering of the output if you're playing these sorts of games - the buffering can totally mask a real race condition or other bug.
printf(" %d ",i++); exit(0); } else {
/* race condition here - may want wait() or waitpid() to synchronize? */
printf("\nI am a parent process.\n"); printf(" %d ",i); } return 0; } // The program is running fine ..... But as I have read it should throw some error right ?? I don't know
what I
am missing . Please point out the point I'm missing. Thanking you in advance.
You're also missing the fact that after the vfork(), there's no real guarantee of which will run first - which means that the parent can race and output the 'printf("%d",i)" *before* the child process gets a chance to do the i++.
I don't think there is any issue here (racing, or child calling exit before parent called exit()). Read the man-page:
vfork() differs from fork(2) in that the parent is suspended until the child terminates (either normally, by calling _exit(2), or abnormally, after delivery of a fatal signal), or it makes a call to execve(2). Until that point, the child shares all memory with its parent, includ‐ ing the stack. The child must not return from the current function or call exit(3), but may call _exit(2).
So:
1. if parent is suspended, it also means no contention issue, child can use the "i++", which is single-copy in memory, and parent is not even touching it.
2. It is clearly documented above - the vfork()'s child CAN exit() before the parent calling exit().
3. More important is to understand the the use of vfork() - u don't to create a duplicate memory page table because u want to call execve() immediately, which will overwrite everything in memory with the new binary inside execve() command.
Hope I got it right?
(Aside - for a while, there was a patch in place that ensured that the child would run first, on the theory that the child would often do something short that the parent was waiting on, so scheduling parent-first would just result in the parent running, blocking to wait, and we end up running the child anyhow before the parent could continue. It broke an *amazing* amount of stuff in userspace because often the child would exit() before the parent was ready to deal with the child process's termination. Usual failure mode was the parent would set a SIGCHLD handler, and wait for the signal which never happened because the SIGCHLD actually fired *before* the handler was set up).
(And on non-cache-coherent systems, it's even possible that the i++ happens on a different CPU first, and the CPU running the parent process never becomes aware of it. See 'Documentation/memory-barriers.txt' in the Linux source for more info on how this works for data inside the kernel. This example is out in userspace, so other techniques are required instead to do cross-CPU synchronization.
_______________________________________________ Kernelnewbies mailing list Kernelnewbies@kernelnewbies.org http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies
-- Regards, Peter Teoh
Hi all, Thank you very much. I have much idea now. However, I am still wondering about these lines " those resources that were shared across a fork() or vfork() were in general *multiple references* to the same resource. " . Is it that all the resources are shared as multiple references or if it is otherwise. Will you please give me some example of the case which I should not share the resources ? Thanking you all in advance.
On Sat, 19 Jan 2013 08:40:04 +0530, you said:
Is it that all the resources are shared as multiple references or if it is otherwise. Will you please give me some example of the case which I should not share the resources ? Thanking you all in advance.
It's not a question of "I should not share the resources" - fork() and friends don't let you choose what to share or not share. It's a matter of being *aware* of what is or is not shared. 'man 2 fork' gives an extensive list of what the child does and does not inherit. Note that in some places it says "inherits" - this usually refers to settings, and means "you get a copy of the same value". In places where it says "inherits copies", that means you got another reference to the same object (mostly in regards to file system objects). The clone() syscall is useful if you wish to control what you do or don't inherit from your parent. It's also a very good way to shoot yourself in the foot, as the semantics are subtly different from fork().
participants (4)
-
Chinmay V S -
Niroj Pokhrel -
Peter Teoh -
Valdis.Kletnieks@vt.edu