Re: System calls interrupted by signals - or not

2018-02-01 Thread Danny Milosavljevic
Hi Mark,

On Thu, 01 Feb 2018 03:13:33 -0500
Mark H Weaver  wrote:

> Guile is a library meant for use within existing applications, and
> therefore needs to be able to cope with whatever signal handling policy
> those applications have chosen.  We certainly cannot assume that all
> kinds of signals will be configured for SA_RESTART.

That's too bad.  It can't be helped, then.
Then see the table for a little overview.

(I've tried very hard to sensibly handle EINTR in the past and it's
surprisingly difficult - that table is what I got out of it - and
the decision to avoid PC-losering signals whenever I can)

And even for the purported use of EINTR (so that you can have complicated
signal-unsafe handler actions after an "if (errno == EINTR)" block)
it's difficult to get right.  That's because you only get EINTR when a system
call has been interrupted by a signal.  It can happen that you aren't yet in
the system call, the signal handler runs (to completion), and then you enter a
system call.
You *don't* get EINTR for the missed signal then.
I don't know what they were thinking.

> There are cases where you may want the
> ability to interrupt a system call without killing the thread.  Suppose
> you are waiting for a large I/O operation to complete over a slow
> network or device.  Signals are the only way I know of in POSIX to
> interrupt a system call, but it can only be done if there's at least one
> kind of signal that's not configured for SA_RESTART.

That's a good point.

But many people just use

  do { syscall } while (errno == EINTR);

in random libraries and then you can't interrupt the system call after all
in your user program.

Also, there's a race because you can be right before entering a system call,
your signal handler runs, and then the system call isn't interrupted after
all (because there was nothing to interrupt - and now you can't branch
on it anymore.  That's how I started to enter this EINTR rabbit hole -
one of my programs had such a bug).

>   "When you don’t specify with ‘sigaction’ or ‘siginterrupt’ what a
>particular handler should do, it uses a default choice.  The default
>choice in the GNU C Library is to make primitives fail with ‘EINTR’."

:-(



Re: System calls interrupted by signals - or not

2018-02-01 Thread Mark H Weaver
Hi Danny,

Danny Milosavljevic  writes:

>>This can happen if interrupted by a signal, 
>
> If only BSD-style signals (SA_RESTART) are used, as is very likely, this
> should not happen.

Guile is a library meant for use within existing applications, and
therefore needs to be able to cope with whatever signal handling policy
those applications have chosen.  We certainly cannot assume that all
kinds of signals will be configured for SA_RESTART.

> It only happens with old "PC-losering" style signal handlers - which even
> signal(2) doesn't install anymore (and I know of no reason why anyone
> should ever use those).

Although SA_RESTART is more convenient, less error prone, and arguably
the sensible default, it is also strictly less powerful than what you
can do without SA_RESTART.  There are cases where you may want the
ability to interrupt a system call without killing the thread.  Suppose
you are waiting for a large I/O operation to complete over a slow
network or device.  Signals are the only way I know of in POSIX to
interrupt a system call, but it can only be done if there's at least one
kind of signal that's not configured for SA_RESTART.

At least that's my understanding.  Please correct me if I'm wrong.

Note that EINTR is the default behavior in GNU libc when using the
advanced signal handling interfaces:



  "When you don’t specify with ‘sigaction’ or ‘siginterrupt’ what a
   particular handler should do, it uses a default choice.  The default
   choice in the GNU C Library is to make primitives fail with ‘EINTR’."

  Mark



System calls interrupted by signals - or not

2018-01-31 Thread Danny Milosavljevic
Hi Mark,

>This can happen if interrupted by a signal, 

If only BSD-style signals (SA_RESTART) are used, as is very likely, this
should not happen.

It only happens with old "PC-losering" style signal handlers - which even
signal(2) doesn't install anymore (and I know of no reason why anyone
should ever use those).

If an OK design limitation is to support only SA_RESTART handlers, I think it
suffices to forbid anyone from using msgrcv and msgsnd.  That's all.  No EINTR
loops or buffer position adjustments necessary.

Otherwise I made a table some years ago when this bit me, I'll paste it here:

Affected Linux syscalls in glibc 2.19 (each lists the newest version only):
E futex
E semop
E semtimedop
E pause
f ptrace (FIXME)
E rt_sigsuspend
E   T rt_sigtimedwait
E sigsuspend
E waitid
E waitpid
E creat
E open
E openat
E B   read
E B   write
  close (DO NOT retry on EINTR)
E   U pselect6
E dup
E dup2
E dup3
E   T epoll_pwait
E   T epoll_wait
E fallocate
E fcntl64
E flock
E ftruncate64
E truncate64
E   T poll
E   T ppoll
E   T io_getevents (timeout not modified) (libaio) (only for the direct 
syscall! otherwise F)
E fstatfs64
E statfs64
E accept4
E connect
E B   recv
E B   recvfrom
E B   recvmsg
E B   send
E B   sendmsg
E B   sendto
E request_key
e   t clock_nanosleep
E   t nanosleep
E B t mq_timedreceive
E B t mq_timedsend
E B   msgrcv [IGNORES SA_RESTART]
E B   msgsnd [IGNORES SA_RESTART]
E B   preadv
E B   readv
E B   pwritev
E B   writev
E   U newselect
E B   getrandom

Meaning:
E ... returns (-1), sets errno == EINTR
e ... returns EINTR directly.
f ... returns (-1) whenever it feels like it, but sets errno on errors.
F ... returns less than min_nr on error.
B ... have to adjust buffer
T ... have to adjust timeout. Note that timeout is optional usually.
t ... have to adjust timeout, but that's easy. Note that timeout is 
optional usually.
U ... have to adjust timeout, but "timeout is undefined". Note that 
timeout is optional usually.

Note: read() returns EFAULT on SEGV instead of doing SIGSEGV.

>or if the file system was full.

Yeah, I think I had this too some time ago.