[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