diff options
author | Andy Wingo <wingo@pobox.com> | 2010-10-10 11:24:29 +0200 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2010-10-10 11:25:50 +0200 |
commit | 41e826492a44d66b6056818c5718164f1d7d065b (patch) | |
tree | aafc6d41057abab5447b030e92ff235b01313a13 /libguile/error.c | |
parent | a627100bf39c64f986536e9faff564e5602e0efa (diff) | |
download | guile-41e826492a44d66b6056818c5718164f1d7d065b.tar.gz |
interrupted syscalls run asyncs before throwing syserror
* libguile/error.c (scm_syserror, scm_syserror_msg): Run pending pending
asyncs before throwing the error, as one of the asyncs might be a
signal handler. But there is unfortunately a race here, as noted in a
comment.
Diffstat (limited to 'libguile/error.c')
-rw-r--r-- | libguile/error.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/libguile/error.c b/libguile/error.c index 4b6bab868..b4ed7d055 100644 --- a/libguile/error.c +++ b/libguile/error.c @@ -147,6 +147,33 @@ void scm_syserror (const char *subr) { SCM err = scm_from_int (SCM_I_ERRNO ()); + + /* It could be that we're getting here because the syscall was + interrupted by a signal. In that case a signal handler might have + been queued to run. The signal handler probably throws an + exception. + + If we don't try to run the signal handler now, it will run later, + which would result in two exceptions being thrown: this syserror, + and then at some later time the exception thrown by the async + signal handler. + + The problem is that we don't know if handling the signal caused an + async to be queued. By this time scmsigs.c:take_signal will have + written a byte on the fd, but we don't know if the signal-handling + thread has read it off and queued an async. + + Ideally we need some API like scm_i_ensure_signals_delivered() to + catch up signal delivery. Barring that, we just cross our digits + and pray; it could be that we handle the signal in time, and just + throw once, or it could be that we miss the deadline and throw + twice. + */ +#ifdef EINTR + if (scm_to_int (err) == EINTR) + SCM_ASYNC_TICK; +#endif + scm_error (scm_system_error_key, subr, "~A", @@ -157,6 +184,11 @@ scm_syserror (const char *subr) void scm_syserror_msg (const char *subr, const char *message, SCM args, int eno) { + /* See above note about the EINTR signal handling race. */ +#ifdef EINTR + if (eno == EINTR) + SCM_ASYNC_TICK; +#endif scm_error (scm_system_error_key, subr, message, |