Date: Sun, 6 Jun 2010 18:31:26 +0200 From: Jilles Tjoelker <jilles@stack.nl> To: Bruce Evans <brde@optusnet.com.au> Cc: Kostik Belousov <kostikbel@gmail.com>, svn-src-head@FreeBSD.org, svn-src-all@FreeBSD.org, src-committers@FreeBSD.org, Gabor Kovesdan <gabor@FreeBSD.org> Subject: Re: svn commit: r208868 - in head/usr.bin: bc dc Message-ID: <20100606163126.GA70256@stack.nl> In-Reply-To: <20100607004046.C30264@delplex.bde.org> References: <201006061136.o56Ba9tr029717@svn.freebsd.org> <20100606120004.GH83316@deviant.kiev.zoral.com.ua> <20100607004046.C30264@delplex.bde.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, Jun 07, 2010 at 01:17:34AM +1000, Bruce Evans wrote: > The old code attempted to deal with this by using the usual hack of > only setting a variable of type sig_atomic_t (bmachine.interrupted) > in the interrupt handler, but that usually doesn't work on any BSDish > system since BSDish systems by default restart most syscalls after an > interrupt, so if the syscall is waiting for user input, it will be > restarted after a user SIGINT and resume waiting. > top(1) is broken in FreeBSD in the same way that dc was, while in the > vendor version it is broken in theory but rarely in practice by the > undefined behaviour. Try this: start top and enter command mode, > e.g. by "s<Enter>. Now ^C at the prompt appears not to work. But > a newline (possibly preceded by other input) makes the old ^C work > unexpectedly. This mostly works in the vendor version because the > signal handler is unsafe and just exits. Someone "fixed" this in > FreeBSD using the flag hack, without adding the (possibly very large) > complications needed to make the flag hack actually work. > To make the hack work you must either: > - turn off SA_RESTART for most signal actions. Then deal with most > syscalls possibly failing with errno = EINTR. Code portable to > old non-BSD systems need complications to deal with these EINTRS. > Now POSIX with XSI extensions in 2001 (maybe standard now) has > SA_RESTART, so a not-so-portable portable application can turn on > SA_RESTART so as not to have to deal with the EINTRS, and have > the BSD problems instead. In most cases, relying on EINTR like this introduces a race condition: it could be that the signal handler is called between the last check of the flag and blocking in a system call (checked for EINTR). In that case, the system call must complete before the program reacts to the signal, which could take very long. Exceptions include sigsuspend(2) and pselect(2) (note some FreeBSD versions have a pselect(3) purely in libc, which does not avoid this race condition). Another function of interest is sigtimedwait(2). A kludge for this race condition and problems where the flag is not checked often enough is an alarm(3) or similar call in the signal handler, forcing the program to be terminated bluntly if it does not react fast enough. Other methods include using signal masks or flags to make terminating the program or longjmp'ing from the signal handler safe. This works best if there are few places where the program can block for longer periods. (If you arrange that your signal handler never interrupts an async-signal-unsafe function, or if it is known that this particular invocation did not interrupt an async-signal-unsafe function, it may call async-signal-unsafe functions without problems.) > - locate all syscalls for i/o on interactive devices and other syscalls > of interest, and turn off SA_RESTART only while making these syscalls > and deal with the resulting EINTRs only for these syscalls. This is > probably easier than a global turnoff of SA_RESTART. This is probably > practical in a small application like top or dc (there seems to be only > 1 critical read() syscall in top), but probably impossible in a large > application and difficult in one where the i/o is in libraries. Many libraries retry potentially blocking system calls on EINTR. If you are wasting two system calls per "slow" system call anyway, it would likely be better if they were unmask/mask signals rather than toggling SA_RESTART. -- Jilles Tjoelker
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100606163126.GA70256>