uth: add got_posix_signal() to the 2LS ops
[akaros.git] / user / parlib / thread0_sched.c
index ca1d0a0..62a7f6f 100644 (file)
@@ -27,6 +27,7 @@ static void thread0_thread_runnable(struct uthread *uth);
 static void thread0_thread_has_blocked(struct uthread *uth, int flags);
 static void thread0_thread_exited(struct uthread *uth);
 static struct uthread *thread0_thread_create(void *(*func)(void *), void *arg);
+static void thread0_got_posix_signal(int sig_nr, struct siginfo *info);
 static void thread0_sync_init(uth_sync_t *s);
 static void thread0_sync_destroy(uth_sync_t *s);
 static void thread0_sync_enqueue(struct uthread *uth, uth_sync_t *s);
@@ -46,6 +47,7 @@ struct schedule_ops thread0_2ls_ops = {
        .thread_has_blocked = thread0_thread_has_blocked,
        .thread_exited = thread0_thread_exited,
        .thread_create = thread0_thread_create,
+       .got_posix_signal = thread0_got_posix_signal,
        .sync_init = thread0_sync_init,
        .sync_destroy = thread0_sync_destroy,
        .sync_enqueue = thread0_sync_enqueue,
@@ -64,7 +66,7 @@ struct uthread *thread0_uth;
  * don't actually attach this mgmt info to it.  But since we just have one
  * thread, it doesn't matter. */
 struct thread0_info {
-       bool                                            is_blocked;
+       bool                            is_blocked;
 };
 static struct thread0_info thread0_info;
 static struct event_queue *sysc_evq;
@@ -90,7 +92,8 @@ void thread0_sched_init(void)
        ret = posix_memalign((void**)&thread0_uth, __alignof__(struct uthread),
                             sizeof(struct uthread));
        assert(!ret);
-       memset(thread0_uth, 0, sizeof(struct uthread)); /* aggressively 0 for bugs*/
+       /* aggressively 0 for bugs*/
+       memset(thread0_uth, 0, sizeof(struct uthread));
        memset(&thread0_info, 0, sizeof(thread0_info));
        /* we don't care about the message, so don't bother with a UCQ */
        sysc_evq = get_eventq(EV_MBOX_BITMAP);
@@ -123,6 +126,7 @@ static void thread0_sched_entry(void)
 static void thread0_thread_blockon_sysc(struct uthread *uthread, void *arg)
 {
        struct syscall *sysc = (struct syscall*)arg;
+
        thread0_thread_has_blocked(uthread, 0);
        if (!register_evq(sysc, sysc_evq))
                thread0_thread_runnable(uthread);
@@ -191,6 +195,21 @@ static struct uthread *thread0_thread_create(void *(*func)(void *), void *arg)
        panic("Thread0 sched asked to create more threads!");
 }
 
+static void thread0_got_posix_signal(int sig_nr, struct siginfo *info)
+{
+       if (current_uthread)
+               trigger_posix_signal(sig_nr, info, get_cur_uth_ctx());
+       else
+               trigger_posix_signal(sig_nr, info, &thread0_uth->u_ctx);
+       /* Legacy single-threaded programs, which often use thread0, expect
+        * signals to interrupt their syscall.  For most 2LSes, we can't match a
+        * process-wide signal to a particular thread; the kernel knows nothing
+        * of threads, we're just receiving an event.  However, thread0 has only
+        * one thread. */
+       if (thread0_uth->sysc)
+               sys_abort_sysc(thread0_uth->sysc);
+}
+
 static void thread0_sync_init(uth_sync_t *s)
 {
        memset(s, 0x5a, sizeof(uth_sync_t));
@@ -207,8 +226,9 @@ static void thread0_sync_enqueue(struct uthread *uth, uth_sync_t *s)
 static struct uthread *thread0_sync_get_next(uth_sync_t *s)
 {
        if (thread0_info.is_blocked) {
-               /* Note we don't clear is_blocked.  Runnable does that, which should be
-                * called before the next get_next (since we have only one thread). */
+               /* Note we don't clear is_blocked.  Runnable does that, which
+                * should be called before the next get_next (since we have only
+                * one thread). */
                return thread0_uth;
        } else {
                return NULL;