This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] Toward Shareable POSIX Signals


On Thu, Mar 8, 2018 at 12:52 PM, Daniel Colascione <dancol@dancol.org> wrote:
> I've written up a proposal for improving the application signal APIs,
> written below. Might there be any interest in prototyping this work
> in glibc?

I want to say first of all that I think you have identified a real
problem and I appreciate your having taken the time to write up a
proposed solution.  However, along with most of the other posters in
this thread, I don't like the proposed solution -- and not just
because I don't like signals (although, indeed, I do not like signals)
but because I think the basic mechanism you suggest, chained handlers,
is inherently unreliable and will cause more problems than it solves.
We have had nothing but bad luck with mechanisms that rely on several
user space components, not all maintained by the same people,
cooperating in access to a shared resource.  Adding signal_register()
to a universe that already has signal() also introduces a nasty
compatibility problem: suppose library A uses the new API to register
a handler for SIGINT (for example), but library B, or the application,
calls signal(SIGINT, SIG_IGN), or sighold(SIGINT): what do you do?

I also think you haven't gone deep enough into the root cause of the
problem you're trying to solve.  You set out to make it possible to
have more than one signal handler per process for each signal, but
_why_ is that an undesirable limitation?  In most cases, it's because
_signals are too coarse_.  When you get a SIGCHLD or a SIGIO or a
SIGSEGV, you don't know which of many possible child processes / file
descriptors / memory addresses is relevant.  If we had a mechanism for
dispatching _specific_ events in these categories directly to the code
that cared about them, then we wouldn't need to have SIGwhatever
handlers in the first place, and we also wouldn't need to worry about
buggy or malevolent handlers eating events that were not for them.
_That_ should be your goal.

With that in mind, let's run down the list of signals with their uses:

CHLD, PIPE, POLL/IO, URG, RTMIN through RTMAX -- These all represent
I/O events.  In most cases it is already possible to receive a
notification tied to the specific file descriptor that's relevant,
instead.  The biggest gap I know about is that child processes are not
represented by file descriptors, and this would be solved by adopting
pdfork() (with some improvements).  You also mentioned async I/O; I am
not up to date on the exact state of async I/O, but I do see a gap in
the sigevent(7) manpage: there ought to be a new alternative,
SIGEV_FD, in which the kernel writes a siginfo_t structure to the
specified file descriptor when I/O completes.  (In fact, if this
existed, I believe SIGEV_SIGNAL and SIGEV_THREAD could be implemented
entirely in user space, on top of it.)

HUP, INT, QUIT, TERM, TSTP, TTIN, TTOU, WINCH, USR1, USR2, XCPU, PWR,
ALRM, VTALRM, PROF -- Often is right to conceptualize these as I/O
events as well, and many of them can already be turned into normal I/O
(e.g. by putting the tty in raw mode, or by using timer_create instead
of alarm), and for those that can't it should be made possible.  But
another valid way to look at them is that they represent _broadcast_
notifications that are already as fine-grained as they can be.  So,
for these, I could be persuaded to support a multi-handler approach --
but one in which all of the registered handlers are always called, no
matter what.  I would need to hear a compelling answer to the
coordination problem I mentioned above, though (what do you do if
there are registered handlers and then someone else uses the legacy
API to ignore the signal?)

ILL, ABRT, FPE, SEGV, BUS, SYS, TRAP, IOT, EMT, STKFLT -- Synchronous
signals arising from processor faults deserve a specialized mechanism
all their own.  The notion I currently like, at the kernel level, is
just-in-time instantiation of a ptrace monitor, because that avoids
the problem of recovering from memory corruption from within the
corrupted address space.  At the C-library level, there are several
plausible strategies for deciding whose responsibility a processor
fault is: special ELF sections that label regions of code with
handlers (like the except_table in the Linux kernel); dynamically
registered annotations on memory regions; SEH; etc.  But notice that
all of those can be built on top of "instantiate a ptrace monitor
instead of delivering a fatal signal."  Someone would need to do
something about how hard it is to write ptrace monitors, but that is
technically a separate issue.

0, STOP, CONT, KILL -- These aren't really signals at all, they are
process-control system calls.  In a from-scratch design we would have
IsProcessRunning(), SuspendProcess(), ResumeProcess(), and
TerminateProcess() primitives instead.  I don't see any real need to
mess with them.

zw


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]