[Bug 3547] shell read is maybe too safe

Rich Felker dalias at aerifal.cx
Wed May 11 00:15:53 UTC 2011


On Wed, May 11, 2011 at 02:05:29AM +0200, Denys Vlasenko wrote:
> On Tuesday 10 May 2011 01:27, Rich Felker wrote:
> > On Tue, May 10, 2011 at 01:09:30AM +0200, Laurent Bercot wrote:
> > > > There is no reason for a correct program to ever check for EINTR
> > > > unless it specifically installs signal handlers and fails to specify
> > > > SA_RESTART for them. Checking for ret==-1&&errno==EINTR in your read
> > > > loop is purely bloat that does not belong in most programs.
> > > 
> > >  Well, I disagree, and I'll keep disagreeing until there's a release of
> > > the Single Unix specification that says explicitly that the default
> > > behaviour for every signal that does not terminate the process MUST be
> > > SA_RESTART.
> > 
> > The default action for a signal is either ignoring it or stopping or
> > terminating the process. Ignoring it obviously does not cause EINTR,
> > and for terminating the process it's irrelevant since no further code
> > is executed. This leaves only stopping. I'm uncertain if syscalls
> > interrupted by SIGSTOP are required to be restarted, but I'd certainly
> > consider restarting them a quality-of-implementation requirement for
> > any implementation I wanted to use..
> 
> Try SIGTOPing and SIGCONTing this:
> 
> #include <errno.h>
> #include <string.h>
> #include <stdio.h>
> #include <signal.h>
> #include <unistd.h>
> static void sig(int n)
> {
>      char buf[128];
>      int e = errno;
>      sprintf(buf, "sig: %d %s\n", n, strsignal(n));
>      write(1, buf, strlen(buf));
>      errno = e;
> }
> int main()
> {
>      signal(SIGSTOP, sig);
>      signal(SIGCONT, sig);
>      signal(SIGWINCH, sig);
>      signal(SIGABRT, sig);
>      printf("PID: %d\n", getpid());
>      fflush(NULL);
>      errno = 0;
>      sleep(30);
>      printf("errno:%d %s\n", errno, strerror(errno));
>      return 0;
> }
> 
> I am getting on 2.6.35-rc4:
> 
> $ ./a.out
> PID: 2821
> sig: 18 Continued
> errno:4 Interrupted system call
> 
> As you see, sleep() (nanosleep syscall)
> is returning EINTR on SIGSTOP/SIGCONT...

sleep is special. It always gets interrupted by signals even if
SA_RESTART is set. Likewise, read and write can be interrupted if
they've already successfully transferred at least 1 byte. It's only if
the syscall has "done nothing" that it gets restarted.

If you think about the implementations, this makes sense. sleep uses a
relative sleep time, not absolute, so there's no way the kernel, when
interrupting sleep, could setup the stack and instruction pointer so
that sleep resumes with the same originally-scheduled wakeup time.

If you change the sleep to read, you'll see different results.

Somewhere there should be a complete list of the functions in POSIX
with this "special" behavior for interruption/restarting, but I can't
find it right off...

Rich


More information about the busybox mailing list