summaryrefslogtreecommitdiff
path: root/libguile/error.c
diff options
context:
space:
mode:
authorAndy Wingo <wingo@pobox.com>2010-10-10 11:24:29 +0200
committerAndy Wingo <wingo@pobox.com>2010-10-10 11:25:50 +0200
commit41e826492a44d66b6056818c5718164f1d7d065b (patch)
treeaafc6d41057abab5447b030e92ff235b01313a13 /libguile/error.c
parenta627100bf39c64f986536e9faff564e5602e0efa (diff)
downloadguile-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.c32
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,