summaryrefslogtreecommitdiff
path: root/term
diff options
context:
space:
mode:
Diffstat (limited to 'term')
-rw-r--r--term/users.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/term/users.c b/term/users.c
index 43646e3c..1c8cf4b8 100644
--- a/term/users.c
+++ b/term/users.c
@@ -63,6 +63,10 @@ struct winsize window_size;
static void call_asyncs (void);
+static int sigs_in_progress;
+static struct condition input_sig_wait = CONDITION_INITIALIZER;
+static int input_sig_wakeup;
+
/* Attach this on the hook of any protid that is a ctty. */
struct protid_hook
{
@@ -500,6 +504,28 @@ trivfs_S_io_read (struct trivfs_protid *cred,
mutex_unlock (&global_lock);
return EINTR;
}
+
+ /* If a signal is being delivered, and we got woken up by
+ arriving input, then there's a possible race; we have to not
+ read from the queue as long as the signal is in progress.
+ Now, you might think that we should not read from the queue
+ when a signal is in progress even if we didn't block, but
+ that's not so. It's specifically that we have to get
+ *interrupted* by signals in progress (when the signallee is
+ this thread and wants to interrupt is) that is the race we
+ are avoiding. A reader who gets in after the signal begins,
+ while the signal is in progress, is harmless, because this
+ case is indiscernable from one where the reader gets in after
+ the signal has completed. */
+ if (sigs_in_progress)
+ {
+ input_sig_wakeup++;
+ if (hurd_condition_wait (&input_sig_wait, &global_lock))
+ {
+ mutex_unlock (&global_lock);
+ return EINTR;
+ }
+ }
}
avail = qsize (inputq);
@@ -1729,6 +1755,23 @@ trivfs_S_io_map (struct trivfs_protid *cred,
return EOPNOTSUPP;
}
+static void
+report_sig_start ()
+{
+ sigs_in_progress++;
+}
+
+static void
+report_sig_end ()
+{
+ sigs_in_progress--;
+ if ((sigs_in_progress == 0) && input_sig_wakeup)
+ {
+ input_sig_wakeup = 0;
+ condition_broadcast (&input_sig_wait);
+ }
+}
+
/* Call all the scheduled async I/O handlers */
static void
call_asyncs ()
@@ -1744,9 +1787,11 @@ call_asyncs ()
if ((termflags & ICKY_ASYNC) && !(termflags & NO_OWNER))
{
+ report_sig_start ();
mutex_unlock (&global_lock);
hurd_sig_post (foreground_id, SIGIO, async_icky_id);
mutex_lock (&global_lock);
+ report_sig_end ();
}
for (ar = async_requests, prevp = &async_requests;
@@ -1778,9 +1823,11 @@ send_signal (int signo)
right = ports_get_right (cttyid);
mach_port_insert_right (mach_task_self (), right, right,
MACH_MSG_TYPE_MAKE_SEND);
+ report_sig_start ();
mutex_unlock (&global_lock);
hurd_sig_post (foreground_id, signo, right);
mutex_lock (&global_lock);
+ report_sig_end ();
mach_port_deallocate (mach_task_self (), right);
}
}