libev's child reaping breaks system() function

Marc Lehmann schmorp at
Fri Aug 27 22:28:26 CEST 2010

On Fri, Aug 27, 2010 at 12:35:46PM +0200, Robin Haberkorn <rh at> wrote:
> libev can easily do something about it: make child reaping more
> flexible by allowing SIGCHLD ev_signals.

Since you can install your own sigchld handler already, this doesn't seem
to be so helpful?

> Also system() isn't broken by multithreading - it works fine as
> long as only one thread's executing system() at a time.
> It's the child reaping that breaks it.

It works fine without multithreading, so how is it libev?

So far, you have not explained how libev "breaks" system, btw. On a naive
implementation, you'd simply get ECHILD, which is documented by POSIX for
this case, so apparently libev doesn't break anything at all.

> *any* other waitpid() occurrence by resulting in race
> conditions. waitpid() is even defined as thread-safe.

The (documented) behaviour of waitpid is not changed by libev though.

libev doesn't force you to use it's facilities for child reaping. If they
are a problem for you, libev fully supports not using them, in a variety
of ways - you can even implement your own.

> ok, suppose I won't use system() anymore. The thing is if I
> would rewrite it on my own, I would have to do it very
> similar to the libc implementation. As a result, I would
> experience the same kind of race condition.

Nobody said multithreading is easy - it "breaks" a lot of very standard
functions in subtle ways (for example, using libeio from perl will make
theoretically impossible to call fork/system/open etc., but thats a
problem with POSIX and/or the implementation, not with libeio). If you
look closely, you will find that the "breakage" is a documented feature of
POSIX however, so it's not really breaking, just changing the rules.

Most systems try to implement POSIX, and some stop there. The problems you
experience are caused by the way POSIX works. It might be unexpected, but
thats life?

> Using an event-based child termination handling while keeping
> the system()-like function synchronous/blocking would
> introduce an unnecessary synchronization overhead
> (like adding ev_childs to the default loop belonging to
> another thread and using condition variables) as well

Does it? I am not sure. Even if, what could libev do more than it does
right now? If you want to use a less efficient reaping mechanism because
you think it's overhead is less than whatever other method, then you cna
fully do so, without breaking libev. If you don't know how, please read
the documentation and ask about anything thats left unclear.

> Making the mechanism asynchronous/non-blocking, would
> require major code refactoring and make conceptually
> simple code dis-proportionally harder to read.

Seems like an empty claim - can you back it up?

> I don't see why this shouldn't be possible (and as I
> pointed out, it is already using a custom signal handler and
> async watcher).

Well, how?

> Is there a design decision that says: either be content
> with libev's default child reaping or don't use any event-based
> child reaping approach at all?

No, not at all, libev allows you to implement any child reaping mechanism
you like.

                The choice of a       Deliantra, the free code+content MORPG
      -----==-     _GNU_    
      ----==-- _       generation
      ---==---(_)__  __ ____  __      Marc Lehmann
      --==---/ / _ \/ // /\ \/ /      schmorp at
      -=====/_/_//_/\_,_/ /_/\_\

More information about the libev mailing list