monotone-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

offtopic: POSIX signals (was Re: [Monotone-devel] auto updates)


From: Nathaniel Smith
Subject: offtopic: POSIX signals (was Re: [Monotone-devel] auto updates)
Date: Sun, 29 Oct 2006 17:57:54 -0800
User-agent: Mutt/1.5.13 (2006-08-11)

On Mon, Oct 30, 2006 at 01:15:15AM +0000, Nuno Lucas wrote:
> On 10/30/06, Nathaniel Smith <address@hidden> wrote:
> >On Sun, Oct 29, 2006 at 09:13:15AM +0000, Nuno Lucas wrote:
> >> Just do this for POSIX systems (I don't believe there is a problem
> >> with zombie processes on other systems):
> >>
> >> static void signal_handler( int sig, siginfo_t* si, void * context )
> >> {
> >>   int status;
> >>   wait (&status);
> >> }
> >
> >FYI, this is a bit buggy -- it can leave zombies if signals get
> >coalesced, or freeze if other processes might call wait() before the
> >signal handler runs.
> 
> That is new to me. I got that code on some book on advanced unix
> programming and that's what I use in my programs (if I want to wait
> for a program, I just use system() and WEXITSTATUS). Have to find that
> book again...
> 
> Always hated unix signals because of their racy conditions and stupid
> behaviours. This just adds to my global feeling...

Well, that's a bad book, then.  But unix signals are not so bad, when
you understand the context they exist in.

The ideal mechanism for sending messages from process A to process B
would be:
  1) available: sends always succeed
  2) asynchronous: neither process has to block
  3) reliable: each sent message corresponds to exactly one received
     message
However, it is a fact about how computation works that you can't have
all of these properties at once, unless you are willing to provide
unbounded storage space.  (Properties (1) and (2) mean that process A
can send arbitrarily many messages before process B processes any of
them; property (3) means that someone needs to keep track of what all
of these messages said, and that takes arbitrary amounts of space.)
In the Unix IPC context, this space has to be provided by the kernel,
and anyone who can cause the kernel to allocate arbitrary amounts of
space can trivially crash the machine.

Commonly, what people give up is either (1) or (2) -- for pipes and
sockets, for instance, the kernel keeps a fixed size buffer, but once
that fills up write() will either block (the default) or fail (with
EAGAIN, if you set the fd to async mode) until the other side has
processed some messages and allowed the kernel to forget about them.

Signals give up (3) instead.  The key to understanding signals is that
you are not really sending messages; really, you are setting flags.
Internally, the kernel has a bit set attached to each process that
says which signals are pending.  (Again, we see a fixed size buffer.
This is also why there are traditionally 32 signals -- the bit set is
implemented as a single 32-bit integer.)  "Sending" a signal sets the
corresponding flag on the target process; if a process has flags set,
then eventually the kernel will get around to "delivering" them, i.e.,
unsetting the flag and notifying the process that the flag had
previously been set.  Signals being "dropped" or "coalesced" just
means that you set the same flag twice before it was cleared, like
doing:
  x = 1;
  x = 1;
  x = 0;
Obviously the second line has no effect.

Signals still make a very useful primitive for IPC, though, because
they do what they do very well.  You just have to remember that what
they do is say "hey, at least one thing happened, so wake up and pay
attention".  They don't say "hey, some stuff happened, here's a list".
In this case, the right thing to do is:
  -- register a handler for SIGCHLD
  -- in this handler, handle zero or more children having exited.  You
     do this by calling waitpid() in a loop, with the WNOHANG option
     set, until you get ECHILD.
This is a little tricky to set up, but once you've done all that,
everything actually works!

There are also lots of IPC mechanisms that attempt to ignore these
universal laws, and it Doesn't Work Out Well.  See the perversion that
is "POSIX real-time signals", for instance... they attempt to keep
signals different in most cases, so 99% of the time you can use them
like actual messages, _but_ 1% of the time the kernel will be forced
to just drop signals on the floor without even a standard way to tell
you that anything was lost.  Result: it is actually impossible to use
them to build a reliable system...

Procrastinatingly yr's,
-- Nathaniel

-- 
So let us espouse a less contested notion of truth and falsehood, even
if it is philosophically debatable (if we listen to philosophers, we
must debate everything, and there would be no end to the discussion).
  -- Serendipities, Umberto Eco




reply via email to

[Prev in Thread] Current Thread [Next in Thread]