Re: SIGCHLD and sigaction()

2020-08-19 Thread Kamil Rytarowski
On 19.08.2020 20:02, Roy Marples wrote:
> On 18/08/2020 20:52, Mouse wrote:
 Perhaps it would need a new flavour of file descriptor, [...]
>>> Linux has apparently done this: pidfd (file descriptors representing
>>> a process).  The idea is that you can pass them to various system
>>> call variants that otherwise take pids, without the risk that the
>>> process has exited in the mean time and the pid re-used.
>>
>> I've been thinking about something like that myself, starting with
>> AF_PID sockets, then deciding they wouldn't/couldn't work (as think I
>> mentioned in this thread, the socket infrastructure really wants the
>> contents of a socket to be independent of who's accessing it).
>> Personally, I've wanted it as a way to provide an out-of-band channel
>> to userland programs (like a control command channel for various
>> daemons), but...hmm.
>>
>> Feels strange to find an idea I like coming from Linux.
> 
> You can relax.
> FreeBSD did it first for Capsicum.
> 
> https://www.freebsd.org/cgi/man.cgi?query=pdfork&sektion=2
> 
> Roy

Hi,

I have got a draft work on this.

It's composed of:

1. New id_t type in P_PIDFD.
2. sigsendset(2) + sigsend(3), picked from SVID (Solaris, etc) It's a
generalized version of kill(2). It allows specifying P_PIDFD.
3. waitid supporting new id type: P_PIDFD.

Linux is close to the above, except reinventing the wheel instead of
picking sigsendset(2) + integration with /proc.

FreeBSD went with a distinct direction and invented new semantics of
process file descriptors, that differs to references over pid_t. For
example whenever you close(2) a file descriptor, it kills the process.
You also must wait for process events in FreeBSD using kevent(2). This
introduced incompatibilities with the established UNIX semantics. Linux
went a different path and whenever a process dies, we get ESRCH, which
is sensible as it avoids e.g. killing a random process with recycled pid_t.

We want process file descriptors to reference process handles through
PID namespaces, for hopefully upcoming support of containers.



signature.asc
Description: OpenPGP digital signature


Re: SIGCHLD and sigaction()

2020-08-19 Thread Roy Marples

On 18/08/2020 20:52, Mouse wrote:

Perhaps it would need a new flavour of file descriptor, [...]

Linux has apparently done this: pidfd (file descriptors representing
a process).  The idea is that you can pass them to various system
call variants that otherwise take pids, without the risk that the
process has exited in the mean time and the pid re-used.


I've been thinking about something like that myself, starting with
AF_PID sockets, then deciding they wouldn't/couldn't work (as think I
mentioned in this thread, the socket infrastructure really wants the
contents of a socket to be independent of who's accessing it).
Personally, I've wanted it as a way to provide an out-of-band channel
to userland programs (like a control command channel for various
daemons), but...hmm.

Feels strange to find an idea I like coming from Linux.


You can relax.
FreeBSD did it first for Capsicum.

https://www.freebsd.org/cgi/man.cgi?query=pdfork&sektion=2

Roy


Re: SIGCHLD and sigaction()

2020-08-18 Thread Mouse
>> Perhaps it would need a new flavour of file descriptor, [...]
> Linux has apparently done this: pidfd (file descriptors representing
> a process).  The idea is that you can pass them to various system
> call variants that otherwise take pids, without the risk that the
> process has exited in the mean time and the pid re-used.

I've been thinking about something like that myself, starting with
AF_PID sockets, then deciding they wouldn't/couldn't work (as think I
mentioned in this thread, the socket infrastructure really wants the
contents of a socket to be independent of who's accessing it).
Personally, I've wanted it as a way to provide an out-of-band channel
to userland programs (like a control command channel for various
daemons), but...hmm.

Feels strange to find an idea I like coming from Linux.

/~\ The ASCII Mouse
\ / Ribbon Campaign
 X  Against HTMLmo...@rodents-montreal.org
/ \ Email!   7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B


Re: SIGCHLD and sigaction()

2020-08-18 Thread Rhialto
On Sat 15 Aug 2020 at 16:46:13 -0400, Mouse wrote:
> Personally, I don't like it; I think signals should be much like
> hardware interrupts in that a second instance happening before the
> first is serviced gets silently merged.  If you want some sort of
> queued notification of child death, it seems to me a much righter, much
> more UNIXy, tack to take is to add something like AF_CHILD sockets or
> some such and get child death notifications that way.  (Actually, I'm
> not sure sockets would work without severe hackery; too much of the
> socket machinery assumes the data in a socket is independent of who
> reads from it.  Perhaps it would need a new flavour of file descriptor,
> akin to kevent or timerfd descriptors.

Linux has apparently done this: pidfd (file descriptors representing a
process). The idea is that you can pass them to various system call
variants that otherwise take pids, without the risk that the process has
exited in the mean time and the pid re-used. See
https://man7.org/linux/man-pages/man2/pidfd_open.2.html

Personally I'd think you should be able to get pidfds from the /proc
file system, but here Linux seems to have missed a chance.

-Olaf.
-- 
Olaf 'Rhialto' Seibert -- rhialto at falu dot nl
___  Anyone who is capable of getting themselves made President should on
\X/  no account be allowed to do the job.   --Douglas Adams, "THGTTG"


signature.asc
Description: PGP signature


Re: SIGCHLD and sigaction()

2020-08-16 Thread Mouse
>> I don't understand what problem queued SIGCHLD was invented to
>> address.

> My impression is that it allows you to get notified of state changes
> of your child processes.  If one signal could annonce several state
> changes, how would you know what these state changes are?

You'd call wait4(2) (or waitpid or wait3) with WNOHANG until it
returned 0 (or returned -1 with ECHILD), collecting one child status
change each time.  You'd still need to do more or less the same with
queued SIGCHLD; the only difference is it would let you skip the
WNOHANG and call it exactly once per signal.  (Unless a single child
changed state twice, such as by being stopped and then killed, in which
case the implementation had better queue wait stati as well or you'll
be calling wait too often!)

/~\ The ASCII Mouse
\ / Ribbon Campaign
 X  Against HTMLmo...@rodents-montreal.org
/ \ Email!   7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B


Re: SIGCHLD and sigaction()

2020-08-16 Thread Edgar Fuß
> I don't understand what problem queued SIGCHLD was invented to address.
My impression is that it allows you to get notified of state changes of your 
child processes. If one signal could annonce several state changes, how 
would you know what these state changes are?


Re: SIGCHLD and sigaction()

2020-08-16 Thread Mouse
>>> When I install a SIGCHLD handler via sigaction() using SA_SIGINFO,
>>> is it guaranteed that my handler is called (at least) once per
>>> death-of-a-child?
>> "Maybe."  It depends on how portable you want to be.
>> [...]
> While we're on this topic. Unix signals don't exactly work like
> hardware interrupts anyhow, I suspect, and it's a thing that have
> constantly befuddled me.

(Caveat: this is all just my understanding.  I think it's accurate, but
I welcome corrections.)

No, they don't.  To the extent that they do, they work like (latched)
edge-triggered interrupts.  There is no signal analog to a
level-triggered interrupt.  And, as you say, there are some important
differences even beyond that.

> As far as I can tell, there is a problematic race condition in the
> old signal mechanism, and that is the reason (I believe) why the new
> semantics were introduced).

I think you are right.  But it's not just "old" and "new".  There are
really old signal semantics, where the handler is uninstalled, I think
it is, when the signal is delivered, and it's up to the code to
reinstall it.  This is vulnerable to, if nothing else, the race where a
second signal arrives before the handler gets reinstalled, though
that's less important for SIGCHLD (see below).  (There may be an even
older form of signal handling, but if so I know nothing about it.)

This then led to (so-called) reliable signals, where the handler stays
installed (or at least can be set to do so) but signals can be blocked,
and get blocked (or, again, at least can be set to be) when the handler
is called.  However, there is still only a single pending bit per
signal.  I think these came in sometime in the 4BSD era, but I don't
recall details - indeed, I'm not sure I ever knew details.

Turning SIGCHLD into something queued, something more like bytes in a
pipe, is, in my perception, more recent yet.  I'm not sure who invented
them (but see below).

There are traces of the first form in modern NetBSD, in the form of the
SA_RESETHAND bit.  I don't *think* that gives full unreliable-signal
semantics, but I haven't checked in enough detail to be sure - I think
you'd also need an SA_DONTBLOCK flag or something of the sort, or the
handler would have to explicitly unblock the signal.

> You have two child processes.  One exit, and you get into your signal
> handler.  In there you then call wait to reap the child and process
> things.  You then call wait again, and repeat until there are no
> children left to reap, as you only get one signal, even if you get
> multiple children that exits.  When no more unreaped children exist,
> you exit the signal handler, and a new signal can be delivered.

Right.

> However, what happens if the second child exists between the call to
> wait, and the exit from the signal handler?  It would seem the signal
> would get lost, since we are in the process of handling the signal,
> and a new signal is not delivered during this time.

If you're using unreliable signals - the first sort I outlined above -
then yes, there is either this race, or, if you reinstall the handler
before you do your last wait call, a different race.  (Provided your
handler doesn't mind being called recursively between reinstall and
return, this may be tolerable.)

If you're using reliable signals but without queued SIGCHLD, this is
not a problem, because the second SIGCHLD (and any additional later
SIGCHLDs) will set the pending bit for SIGCHLD.  As soon as you return
from the handler (or explicitly unblock the signal), it will be
delivered.

> Now, have I misunderstood something about how non-queued signal
> handling works, or is/was there a problem there?

There was, but it was a problem with the oldest of the above three
kinds of signal.  Queued SIGCHLD was not necessary for it - I don't
understand what problem queued SIGCHLD was invented to address.  The
only thing I can think of was that it came from SRV4, which had a NIH
attitude towards BSD reliable signals, so they invented queued SIGCHLD
to get reliable child death handling, and then someone (POSIX maybe?)
decided it would be good to include all of both mechanisms.

/~\ The ASCII Mouse
\ / Ribbon Campaign
 X  Against HTMLmo...@rodents-montreal.org
/ \ Email!   7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B


Re: SIGCHLD and sigaction()

2020-08-16 Thread Johnny Billquist

On 2020-08-16 12:49, Johnny Billquist wrote:

On 2020-08-15 22:46, Mouse wrote:

When I install a SIGCHLD handler via sigaction() using SA_SIGINFO, is
it guaranteed that my handler is called (at least) once per
death-of-a-child?


"Maybe."  It depends on how portable you want to be.

Historically, "no": in some older systems, a second SIGCHLD delivered
when there's already one pending delivery gets, lost same as any other
signal.

Then someone - POSIX? SVR4? I don't know - decided to invent a flavour
of signal that's more like writes to a pipe: multiple of them can be
pending at once.  Some systems decided this was sane and implemented
it.

Personally, I don't like it; I think signals should be much like
hardware interrupts in that a second instance happening before the
first is serviced gets silently merged.


While we're on this topic. Unix signals don't exactly work like hardware 
interrupts anyhow, I suspect, and it's a thing that have constantly 
befuddled me. As far as I can tell, there is a problematic race 
condition in the old signal mechanism, and that is the reason (I 
believe) why the new semantics were introduced).


The problem goes like this:

You have two child processes. One exit, and you get into your signal 
handler. In there you then call wait to reap the child and process 
things. You then call wait again, and repeat until there are no children 
left to reap, as you only get one signal, even if you get multiple 
children that exits. When no more unreaped children exist, you exit the 
signal handler, and a new signal can be delivered.


However, what happens if the second child exists between the call to 
wait, and the exit from the signal handler? It would seem the signal 
would get lost, since we are in the process of handling the signal, and 
a new signal is not delivered during this time.


In real hardware this usually don't happen, because the actual interrupt 
request can be reissued by the device while you are in the interrupt 
handler. There are some hardware interrupt designs, with edge triggered 
interrupts, where similar problems can exist, and those you have to be 
very careful with how you handle them so you don't get to the same kind 
of race condition.


Now, have I misunderstood something about how non-queued signal handling 
works, or is/was there a problem there?


Reading the current documentation, I would assume that at the call to 
the signal handler, the signal is blocked, and also removed from pending 
signals, so a new even would queue up a new signal to be delivered when 
returning from the signal handler. However, the text above is from 
trying to recall how it used to be going back in time, to when you had 
to re-install the signal handler after each activation. I can't seem to 
find documentation for how it worked back in the day. I can't even 
remember when/where I was reading up on that and thinking there might be 
a problem here, but it was a long time ago. So this is possibly just of 
historical interest.


By the way, I haven't seen any explicit mention of the pending signal 
being cleared at signal handler entry, so that is just my assumption 
right now. If that is wrong, then I would expect there is a race 
condition in there. Maybe someone else knows where that detail is 
documented?


  Johnny

--
Johnny Billquist  || "I'm on a bus
  ||  on a psychedelic trip
email: b...@softjar.se ||  Reading murder books
pdp is alive! ||  tryin' to stay hip" - B. Idol


Re: SIGCHLD and sigaction()

2020-08-16 Thread Johnny Billquist

On 2020-08-15 22:46, Mouse wrote:

When I install a SIGCHLD handler via sigaction() using SA_SIGINFO, is
it guaranteed that my handler is called (at least) once per
death-of-a-child?


"Maybe."  It depends on how portable you want to be.

Historically, "no": in some older systems, a second SIGCHLD delivered
when there's already one pending delivery gets, lost same as any other
signal.

Then someone - POSIX? SVR4? I don't know - decided to invent a flavour
of signal that's more like writes to a pipe: multiple of them can be
pending at once.  Some systems decided this was sane and implemented
it.

Personally, I don't like it; I think signals should be much like
hardware interrupts in that a second instance happening before the
first is serviced gets silently merged.


While we're on this topic. Unix signals don't exactly work like hardware 
interrupts anyhow, I suspect, and it's a thing that have constantly 
befuddled me. As far as I can tell, there is a problematic race 
condition in the old signal mechanism, and that is the reason (I 
believe) why the new semantics were introduced).


The problem goes like this:

You have two child processes. One exit, and you get into your signal 
handler. In there you then call wait to reap the child and process 
things. You then call wait again, and repeat until there are no children 
left to reap, as you only get one signal, even if you get multiple 
children that exits. When no more unreaped children exist, you exit the 
signal handler, and a new signal can be delivered.


However, what happens if the second child exists between the call to 
wait, and the exit from the signal handler? It would seem the signal 
would get lost, since we are in the process of handling the signal, and 
a new signal is not delivered during this time.


In real hardware this usually don't happen, because the actual interrupt 
request can be reissued by the device while you are in the interrupt 
handler. There are some hardware interrupt designs, with edge triggered 
interrupts, where similar problems can exist, and those you have to be 
very careful with how you handle them so you don't get to the same kind 
of race condition.


Now, have I misunderstood something about how non-queued signal handling 
works, or is/was there a problem there?


  Johnny

--
Johnny Billquist  || "I'm on a bus
  ||  on a psychedelic trip
email: b...@softjar.se ||  Reading murder books
pdp is alive! ||  tryin' to stay hip" - B. Idol


Re: SIGCHLD and sigaction()

2020-08-15 Thread Mouse
> When I install a SIGCHLD handler via sigaction() using SA_SIGINFO, is
> it guaranteed that my handler is called (at least) once per
> death-of-a-child?

"Maybe."  It depends on how portable you want to be.

Historically, "no": in some older systems, a second SIGCHLD delivered
when there's already one pending delivery gets, lost same as any other
signal.

Then someone - POSIX? SVR4? I don't know - decided to invent a flavour
of signal that's more like writes to a pipe: multiple of them can be
pending at once.  Some systems decided this was sane and implemented
it.

Personally, I don't like it; I think signals should be much like
hardware interrupts in that a second instance happening before the
first is serviced gets silently merged.  If you want some sort of
queued notification of child death, it seems to me a much righter, much
more UNIXy, tack to take is to add something like AF_CHILD sockets or
some such and get child death notifications that way.  (Actually, I'm
not sure sockets would work without severe hackery; too much of the
socket machinery assumes the data in a socket is independent of who
reads from it.  Perhaps it would need a new flavour of file descriptor,
akin to kevent or timerfd descriptors.  I have no doubt it could be
done one way or another.  But arguably it's best to just use SIGCHLD
and a loop that uses WNOHANG.)

/~\ The ASCII Mouse
\ / Ribbon Campaign
 X  Against HTMLmo...@rodents-montreal.org
/ \ Email!   7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B


SIGCHLD and sigaction()

2020-08-15 Thread Edgar Fuß
Another question in the context of SIGCHLD:

When I install a SIGCHLD handler via sigaction() using SA_SIGINFO, 
is it guaranteed that my handler is called (at least) once per 
death-of-a-child? There is sentence in SUS

If SA_SIGINFO is set in sa_flags, then subsequent occurrences of sig 
generated by sigqueue() or as a result of any signal-generating function 
that supports the specification of an application-defined value (when sig 
is already pending) shall be queued in FIFO order until delivered or accepted;

that may cover this but that I don't understand.