2006-01-11 12:37:30

by Gábor Lénárt

[permalink] [raw]
Subject: OT: fork(): parent or child should run first?

Hello,

The following problem may be simple for you, so I hope someone can answer
here. We've got a complex software using child processes and a table
to keep data of them together, like this:

childs[n].pid=fork();

where "n" is an integer contains a free "slot" in the childs struct array.

I also handle SIGCHLD in the parent and signal handler searches the childs
array for the pid returned by waitpid(). However here is my problem. The
child process can be fast, ie exits before scheduler of the kernel give
chance the parent process to run, so storing pid into childs[n].pid in the
parent context is not done yet. Child may exit, than scheduler gives control
to the signal handler before doing the store of the pid (if child run for
more time, eg 10 seconds it works of course). So it's impossible to store
child pids and search by that information in eg the signal handler? It's
quite problematic, since the code uses blocking I/O a lot, so other
solutions (like searching in childs[] in the main program and not in signal
handler) would require to recode the whole project. The problem can be
avoided with having a fork() run the PARENT first, but I thing this is done
by the scheduler so it's a kernel issue. Also the problem that source should
be portable between Linux and Solaris ...

Sorry for disturbing the list with this kind of problem but I can't find
any solution elsewhere.

Thanks a lot,

--
- G?bor


2006-01-11 12:51:58

by Arjan van de Ven

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Wed, 2006-01-11 at 13:37 +0100, Gábor Lénárt wrote:
> Hello,
>
> The following problem may be simple for you, so I hope someone can answer
> here. We've got a complex software using child processes and a table
> to keep data of them together, like this:
>
> childs[n].pid=fork();
>
> where "n" is an integer contains a free "slot" in the childs struct array.
>
> I also handle SIGCHLD in the parent and signal handler searches the childs
> array for the pid returned by waitpid(). However here is my problem. The
> child process can be fast, ie exits before scheduler of the kernel give
> chance the parent process to run, so storing pid into childs[n].pid in the
> parent context is not done yet. Child may exit, than scheduler gives control
> to the signal handler before doing the store of the pid (if child run for
> more time, eg 10 seconds it works of course). So it's impossible to store
> child pids and search by that information in eg the signal handler? It's
> quite problematic, since the code uses blocking I/O a lot, so other
> solutions (like searching in childs[] in the main program and not in signal
> handler) would require to recode the whole project. The problem can be
> avoided with having a fork() run the PARENT first, but I thing this is done
> by the scheduler so it's a kernel issue. Also the problem that source should
> be portable between Linux and Solaris ...

you just cannot depend on which would run first, child or parent. Even
if linux would do it the other way around, you have no guarantee. Think
SMP or Dual Core processors and time slices and cache misses... your
code just HAS to be able to cope with it. Even on solaris ;)


2006-01-11 13:02:10

by Gábor Lénárt

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

Hello,

Ok, you're absolutly right here. My problem is to find some solution and not
to change the behaviour of fork() of course :) It's quite annoying to
introduce some kind of IPC between parent and childs just for transferring a
single pid_t ;-) Using exit status would be great (I would transfer "n")
because it can be got by eg waitpid() in signal handler, however exit status
is limited it status & 0377 which is too short range for us ;-( As a
solution I've created a pid_t array and a counter which is filled by signal
handler with pid_t got by waitpid() and then I use it in the main loop to do
the cleanup in parent. Well, this is quite good, the only problem of mine
that some kind of race condition may occur when altering/using these
structures between the main loop and signal handler ...

Again, thanks for the info.

- G?bor

On Wed, Jan 11, 2006 at 01:51:50PM +0100, Arjan van de Ven wrote:
> On Wed, 2006-01-11 at 13:37 +0100, G?bor L?n?rt wrote:
> > Hello,
> >
> > The following problem may be simple for you, so I hope someone can answer
> > here. We've got a complex software using child processes and a table
> > to keep data of them together, like this:
> >
> > childs[n].pid=fork();
> >
> > where "n" is an integer contains a free "slot" in the childs struct array.
> >
> > I also handle SIGCHLD in the parent and signal handler searches the childs
> > array for the pid returned by waitpid(). However here is my problem. The
> > child process can be fast, ie exits before scheduler of the kernel give
> > chance the parent process to run, so storing pid into childs[n].pid in the
> > parent context is not done yet. Child may exit, than scheduler gives control
> > to the signal handler before doing the store of the pid (if child run for
> > more time, eg 10 seconds it works of course). So it's impossible to store
> > child pids and search by that information in eg the signal handler? It's
> > quite problematic, since the code uses blocking I/O a lot, so other
> > solutions (like searching in childs[] in the main program and not in signal
> > handler) would require to recode the whole project. The problem can be
> > avoided with having a fork() run the PARENT first, but I thing this is done
> > by the scheduler so it's a kernel issue. Also the problem that source should
> > be portable between Linux and Solaris ...
>
> you just cannot depend on which would run first, child or parent. Even
> if linux would do it the other way around, you have no guarantee. Think
> SMP or Dual Core processors and time slices and cache misses... your
> code just HAS to be able to cope with it. Even on solaris ;)
>
>

--
- G?bor

2006-01-11 13:03:33

by Miquel van Smoorenburg

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

In article <[email protected]>,
G?bor L?n?rt <[email protected]> wrote:
>The following problem may be simple for you, so I hope someone can answer
>here. We've got a complex software using child processes and a table
>to keep data of them together, like this:
>
>childs[n].pid=fork();
>
>where "n" is an integer contains a free "slot" in the childs struct array.
>
>I also handle SIGCHLD in the parent and signal handler searches the childs
>array for the pid returned by waitpid(). However here is my problem. The
>child process can be fast, ie exits before scheduler of the kernel give
>chance the parent process to run, so storing pid into childs[n].pid in the
>parent context is not done yet. Child may exit, than scheduler gives control
>to the signal handler before doing the store of the pid (if child run for
>more time, eg 10 seconds it works of course). So it's impossible to store
>child pids and search by that information in eg the signal handler?

Simply block sigchld like this:

sigemptyset(&set);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, &oldset);
pid = fork();
if (pid == 0) {
sigprocmask(SIG_SETMASK, &oldset, NULL);
do_whatever();
exit(0);
}
childs[n].pid = pid;
sigprocmask(SIG_SETMASK, &oldset, NULL);

This is a common problem. When you have data structures that are
handled by both the main program and by a signal handler, *always* block
the signal when you're handling the data structures in the main program.

Mike.
--
Freedom is no longer a problem.

2006-01-11 13:08:03

by Jan-Benedict Glaw

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Wed, 2006-01-11 13:37:45 +0100, Gábor Lénárt <[email protected]> wrote:
> Hello,
>
> The following problem may be simple for you, so I hope someone can answer
> here. We've got a complex software using child processes and a table
> to keep data of them together, like this:
>
> childs[n].pid=fork();
>
> where "n" is an integer contains a free "slot" in the childs struct array.
>
> I also handle SIGCHLD in the parent and signal handler searches the childs
> array for the pid returned by waitpid(). However here is my problem. The
> child process can be fast, ie exits before scheduler of the kernel give
> chance the parent process to run, so storing pid into childs[n].pid in the
> parent context is not done yet. Child may exit, than scheduler gives control
> to the signal handler before doing the store of the pid (if child run for
> more time, eg 10 seconds it works of course). So it's impossible to store
> child pids and search by that information in eg the signal handler? It's
> quite problematic, since the code uses blocking I/O a lot, so other
> solutions (like searching in childs[] in the main program and not in signal
> handler) would require to recode the whole project. The problem can be
> avoided with having a fork() run the PARENT first, but I thing this is done
> by the scheduler so it's a kernel issue. Also the problem that source should
> be portable between Linux and Solaris ...

One way to sort this out would be to queue the dead childs to some
thread that clears the child's slot, possibly waiting on a condition
(queue to slot list ready).

Quite easy :-)

MfG, JBG

--
Jan-Benedict Glaw [email protected] . +49-172-7608481 _ O _
"Eine Freie Meinung in einem Freien Kopf | Gegen Zensur | Gegen Krieg _ _ O
für einen Freien Staat voll Freier Bürger" | im Internet! | im Irak! O O O
ret = do_actions((curr | FREE_SPEECH) & ~(NEW_COPYRIGHT_LAW | DRM | TCPA));


Attachments:
(No filename) (1.89 kB)
signature.asc (189.00 B)
Digital signature
Download all attachments

2006-01-11 13:28:53

by Bernd Petrovitsch

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Wed, 2006-01-11 at 14:02 +0100, Gábor Lénárt wrote:
> Hello,
>
> Ok, you're absolutly right here. My problem is to find some solution and not
> to change the behaviour of fork() of course :) It's quite annoying to
> introduce some kind of IPC between parent and childs just for transferring a
> single pid_t ;-) Using exit status would be great (I would transfer "n")
> because it can be got by eg waitpid() in signal handler, however exit status
> is limited it status & 0377 which is too short range for us ;-( As a
> solution I've created a pid_t array and a counter which is filled by signal
> handler with pid_t got by waitpid() and then I use it in the main loop to do
> the cleanup in parent. Well, this is quite good, the only problem of mine
> that some kind of race condition may occur when altering/using these
> structures between the main loop and signal handler ...

Disabling signals for most of the main loop and activating them just
around the select()/poll/... is one solution to the problem.

Then this leaves the race if an old pid is reused in a newly created
process before the last instances of that pid is cleaned up. But this is
probably only a theoretical problem (unless you fork() very very
often) ....

Bernd
--
Firmix Software GmbH http://www.firmix.at/
mobil: +43 664 4416156 fax: +43 1 7890849-55
Embedded Linux Development and Services

2006-01-11 13:34:29

by Roland Kuhn

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

Hi Arjan!

On 11 Jan 2006, at 13:51, Arjan van de Ven wrote:

> you just cannot depend on which would run first, child or parent. Even
> if linux would do it the other way around, you have no guarantee.
> Think
> SMP or Dual Core processors and time slices and cache misses... your
> code just HAS to be able to cope with it. Even on solaris ;)

That means that the starting of the child process needs to be
synchronized by the application itself. I tried it once but then I
discovered that my case was easily solved in a completely different
way (it was a very small project). However, which one is the easiest/
fastest way to do this synchronization? Using SysV-Semaphores? Pipes?
Would something like this work?

int fd[2], pid;

pipe(fd);
pid = fork();
if (pid < 0) {
error();
} else if (pid == 0) {
close(fd[1]);
read(fd[0]);
close(fd[0]);
child_code();
} else {
store_pid();
close(fd[0]);
close(fd[1]); // this should wake up the child, right?
}

This should ensure that store_pid() is executed before child_code()...

Ciao,
Roland

--
TU Muenchen, Physik-Department E18, James-Franck-Str., 85748 Garching
Telefon 089/289-12575; Telefax 089/289-12570
--
UNIX was not designed to stop you from doing stupid things, because that
would also stop you from doing clever things.
-Doug Gwyn
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GS/CS/M/MU d-(++) s:+ a-> C+++ UL++++ P+++ L+++ E(+) W+ !N K- w--- M
+ !V Y+
PGP++ t+(++) 5 R+ tv-- b+ DI++ e+++>++++ h---- y+++
------END GEEK CODE BLOCK------





Attachments:
PGP.sig (186.00 B)
This is a digitally signed message part

2006-01-11 13:48:58

by Ian Campbell

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Wed, 2006-01-11 at 14:25 +0100, Bernd Petrovitsch wrote:
> Then this leaves the race if an old pid is reused in a newly created
> process before the last instances of that pid is cleaned up.

The PID won't be available to be re-used until the signal handler has
called waitpid() on it?

Ian.

--
Ian Campbell
Current Noise: Sloth - Wishman

I understand why you're confused. You're thinking too much.
-- Carole Wallach.

2006-01-11 13:59:51

by Bernd Petrovitsch

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Wed, 2006-01-11 at 13:49 +0000, Ian Campbell wrote:
> On Wed, 2006-01-11 at 14:25 +0100, Bernd Petrovitsch wrote:
> > Then this leaves the race if an old pid is reused in a newly created
> > process before the last instances of that pid is cleaned up.
>
> The PID won't be available to be re-used until the signal handler has
> called waitpid() on it?

Yes.
But ATM the signal handler calls waitpid() and stores the pid in a
to-be-cleaned-pids array (at time X).
The main loop at some time in the future (say at time X+N) walks through
the to-be-cleaned-pids array and cleans them from the active-childs
array.
If a new process is started between X and X+N with a pid in the
to-be-cleaned-pids it may happen (depends on the implementation - if the
active-childs array is "sorted" as childs are created (i.e. just append
the new pid at the end), holes of terminated childs are closed with
moving the rest of array and *never* reordered, than it may even work
then) that the wrong one (or both) are cleaned up.
But IMHO a too fragile solution in the log run as this doesn't scale and
people are inclined to tune it with sorting, hashing, etc.

Bernd
--
Firmix Software GmbH http://www.firmix.at/
mobil: +43 664 4416156 fax: +43 1 7890849-55
Embedded Linux Development and Services

2006-01-11 14:04:52

by Ian Campbell

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Wed, 2006-01-11 at 14:55 +0100, Bernd Petrovitsch wrote:
> On Wed, 2006-01-11 at 13:49 +0000, Ian Campbell wrote:
> > On Wed, 2006-01-11 at 14:25 +0100, Bernd Petrovitsch wrote:
> > > Then this leaves the race if an old pid is reused in a newly created
> > > process before the last instances of that pid is cleaned up.
> >
> > The PID won't be available to be re-used until the signal handler has
> > called waitpid() on it?
>
> Yes.
> But ATM the signal handler calls waitpid() and stores the pid in a
> to-be-cleaned-pids array (at time X).
> The main loop at some time in the future (say at time X+N) walks through
> the to-be-cleaned-pids array and cleans them from the active-childs
> array.

yuk... I'd say the application is a bit dumb for calling waitpid before
it is actually prepared for the pid to be reclaimed.

A possible solution would be to also defer the waitpid until the main
loop cleanup function, perhaps flagging the entry in the child array as
not-active between the signal and that time or moving the pid from the
active to an inactive array in the signal handler.

Ian.
--
Ian Campbell
Current Noise: Sloth - Into The Sun

To err is human,
To purr feline.
-- Robert Byrne

2006-01-11 15:21:07

by linux-os (Dick Johnson)

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?


On Wed, 11 Jan 2006, Ian Campbell wrote:

> On Wed, 2006-01-11 at 14:55 +0100, Bernd Petrovitsch wrote:
>> On Wed, 2006-01-11 at 13:49 +0000, Ian Campbell wrote:
>>> On Wed, 2006-01-11 at 14:25 +0100, Bernd Petrovitsch wrote:
>>>> Then this leaves the race if an old pid is reused in a newly created
>>>> process before the last instances of that pid is cleaned up.
>>>
>>> The PID won't be available to be re-used until the signal handler has
>>> called waitpid() on it?
>>
>> Yes.
>> But ATM the signal handler calls waitpid() and stores the pid in a
>> to-be-cleaned-pids array (at time X).
>> The main loop at some time in the future (say at time X+N) walks through
>> the to-be-cleaned-pids array and cleans them from the active-childs
>> array.
>
> yuk... I'd say the application is a bit dumb for calling waitpid before
> it is actually prepared for the pid to be reclaimed.
>

The application has no clue (and must not know) the internal workings
of the kernel. In the following code, both forks must work, the case
in which the child executed immediately, and the case in which the
child did some work or slept before it exited.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
pid_t pid;
int status;

switch((pid = fork()))
{
case 0: // child
exit(EXIT_SUCCESS);
case -1: // Error
perror("fork");
exit(EXIT_FAILURE);
default: // Parent
waitpid(pid, &status, 0);
break;
}
switch((pid = fork()))
{
case 0: // child
sleep(10);
exit(EXIT_SUCCESS);
case -1: // Error
perror("fork");
exit(EXIT_FAILURE);
default: // Parent
waitpid(pid, &status, 0);
break;
}
return 0;
}

The code has no clue whether or not the child started before
waitpid was called. It knows it has a valid pid, which is only a
promise that such a child will start execution sometime or
that it once existed and has already expired. That pid must
remain valid until somebody reaps the status of the expired
child.

> A possible solution would be to also defer the waitpid until the main
> loop cleanup function, perhaps flagging the entry in the child array as
> not-active between the signal and that time or moving the pid from the
> active to an inactive array in the signal handler.
>

The pid will (must) always be valid until after the status is reaped.
There should not be any flags used to synchronize anything here. That
pid just cannot be reused until the child is out of the Z state and
its status has been obtained. Then the pid can be reused. It's the
Z state that has historically provided the needed synchronization.

> Ian.
> --
> Ian Campbell
> Current Noise: Sloth - Into The Sun
>
> To err is human,
> To purr feline.
> -- Robert Byrne
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

Cheers,
Dick Johnson
Penguin : Linux version 2.6.13.4 on an i686 machine (5589.71 BogoMips).
Warning : 98.36% of all statistics are fiction.
.

****************************************************************
The information transmitted in this message is confidential and may be privileged. Any review, retransmission, dissemination, or other use of this information by persons or entities other than the intended recipient is prohibited. If you are not the intended recipient, please notify Analogic Corporation immediately - by replying to this message or by sending an email to [email protected] - and destroy all copies of this information, including any attachments, without reading or disclosing them.

Thank you.

2006-01-11 17:11:56

by Lee Revell

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Wed, 2006-01-11 at 14:34 +0100, Roland Kuhn wrote:
> Hi Arjan!
>
> On 11 Jan 2006, at 13:51, Arjan van de Ven wrote:
>
> > you just cannot depend on which would run first, child or parent. Even
> > if linux would do it the other way around, you have no guarantee.
> > Think
> > SMP or Dual Core processors and time slices and cache misses... your
> > code just HAS to be able to cope with it. Even on solaris ;)
>
> That means that the starting of the child process needs to be
> synchronized by the application itself. I tried it once but then I
> discovered that my case was easily solved in a completely different
> way (it was a very small project). However, which one is the easiest/
> fastest way to do this synchronization? Using SysV-Semaphores? Pipes?
> Would something like this work?

How about POSIX process-shared mutexes? There's no documentation
avalable on using them with Linux (where are the NPTL man pages
already?) but they work.

Lee

2006-01-12 01:34:31

by David Schwartz

[permalink] [raw]
Subject: RE: OT: fork(): parent or child should run first?



> Yes.
> But ATM the signal handler calls waitpid() and stores the pid in a
> to-be-cleaned-pids array (at time X).
> The main loop at some time in the future (say at time X+N) walks through
> the to-be-cleaned-pids array and cleans them from the active-childs
> array.

Obviously that's broken. You would have precisely the same problem if you
did the same thing with file descriptors or sockets.

DS


2006-01-12 01:34:30

by David Schwartz

[permalink] [raw]
Subject: RE: fork(): parent or child should run first?


> The following problem may be simple for you, so I hope someone can answer
> here. We've got a complex software using child processes and a table
> to keep data of them together, like this:
>
> childs[n].pid=fork();
>
> where "n" is an integer contains a free "slot" in the childs struct array.
>
> I also handle SIGCHLD in the parent and signal handler searches
> the childs
> array for the pid returned by waitpid(). However here is my problem. The
> child process can be fast, ie exits before scheduler of the kernel give
> chance the parent process to run, so storing pid into childs[n].pid in the
> parent context is not done yet. Child may exit, than scheduler
> gives control
[snip]

There are a lot of things you should not do in a signal handler, this is
one of them. There are a lot of possible solutions. My recommendation would
be to handle the death of a child from a safe context, rather than from a
signal handler. For example, the SIGCHLD handler could just set a volatile
variable to 'true' and then the code could notice that from a safe context
and loop on 'waitpid', reaping all dead children.

DS


2006-01-12 01:39:06

by Kurt Wall

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Wed, Jan 11, 2006 at 02:02:55PM +0100, G?bor L?n?rt took 0 lines to write:
> Hello,
>
> Ok, you're absolutly right here. My problem is to find some solution and not
> to change the behaviour of fork() of course :) It's quite annoying to
> introduce some kind of IPC between parent and childs just for transferring a
> single pid_t ;-) Using exit status would be great (I would transfer "n")

But IPC, especially shared memory, would be great for this if you can
set up the shmid ahead of time. It would certainly be fast.

Kurt
--
The study of non-linear physics is like the study of non-elephant
biology.

2006-01-12 17:23:27

by Hugh Dickins

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Wed, 11 Jan 2006, Kurt Wall wrote:
> On Wed, Jan 11, 2006 at 02:02:55PM +0100, Gábor Lénárt took 0 lines to write:
> >
> > Ok, you're absolutly right here. My problem is to find some solution and not
> > to change the behaviour of fork() of course :) It's quite annoying to
> > introduce some kind of IPC between parent and childs just for transferring a
> > single pid_t ;-) Using exit status would be great (I would transfer "n")
>
> But IPC, especially shared memory, would be great for this if you can
> set up the shmid ahead of time. It would certainly be fast.

I've not been following the thread, but if your suggestion is good, then
better would be to use mmap MAP_SHARED|MAP_ANONYMOUS - that gives memory
shared between parent and children, without all the nuisance of shmids.

Hugh

2006-01-12 20:19:31

by Gábor Lénárt

[permalink] [raw]
Subject: Re: OT: fork(): parent or child should run first?

On Thu, Jan 12, 2006 at 05:23:48PM +0000, Hugh Dickins wrote:
> I've not been following the thread, but if your suggestion is good, then
> better would be to use mmap MAP_SHARED|MAP_ANONYMOUS - that gives memory
> shared between parent and children, without all the nuisance of shmids.

Well you would be right, but children processes do exec() for application(s)
does not know anything about my ideas :) That's why I wanted to take care
about them in parent and do 'cleanup' there.

--
- G?bor