Sanitize vcoreid from untrusted sources
[akaros.git] / kern / src / rendez.c
index 6c2665a..f046556 100644 (file)
@@ -22,10 +22,12 @@ void rendez_sleep(struct rendez *rv, int (*cond)(void*), void *arg)
 {
        int8_t irq_state = 0;
        struct cv_lookup_elm cle;
-       /* Do a quick check before registering and sleeping.  this is the 'check,
-        * signal, check again' pattern, where the first check is an optimization.
-        * Many rendezes will already be satisfied, so we want to avoid excessive
-        * locking associated with reg/dereg. */
+
+       assert(can_block(this_pcpui_ptr()));
+       /* Do a quick check before registering and sleeping.  this is the
+        * 'check, signal, check again' pattern, where the first check is an
+        * optimization.  Many rendezes will already be satisfied, so we want to
+        * avoid excessive locking associated with reg/dereg. */
        cv_lock_irqsave(&rv->cv, &irq_state);
        if (cond(arg)) {
                cv_unlock_irqsave(&rv->cv, &irq_state);
@@ -35,12 +37,12 @@ void rendez_sleep(struct rendez *rv, int (*cond)(void*), void *arg)
        /* Mesa-style semantics, which is definitely what you want.  See the
         * discussion at the end of the URL above. */
        while (!cond(arg)) {
-               /* it's okay if we miss the ABORT flag; we hold the cv lock, so an
-                * aborter's broadcast is waiting until we unlock. */
+               /* it's okay if we miss the ABORT flag; we hold the cv lock, so
+                * an aborter's broadcast is waiting until we unlock. */
                if (should_abort(&cle)) {
                        cv_unlock_irqsave(&rv->cv, &irq_state);
                        dereg_abortable_cv(&cle);
-                       error("syscall aborted");
+                       error(EINTR, "syscall aborted");
                }
                cv_wait(&rv->cv);
                cpu_relax();
@@ -55,21 +57,42 @@ void rendez_sleep(struct rendez *rv, int (*cond)(void*), void *arg)
 static void rendez_alarm_handler(struct alarm_waiter *awaiter)
 {
        struct rendez *rv = (struct rendez*)awaiter->data;
+
        rendez_wakeup(rv);
 }
 
-/* Like sleep, but it will timeout in 'msec' milliseconds. */
+void rendez_debug_waiter(struct alarm_waiter *awaiter)
+{
+       struct rendez *rv = (struct rendez*)awaiter->data;
+       struct cond_var *cv = &rv->cv;
+       struct kthread *kth;
+       int8_t irq_state = 0;
+
+       cv_lock_irqsave(cv, &irq_state);
+       TAILQ_FOREACH(kth, &cv->waiters, link) {
+               print_lock();
+               printk("-------- kth %s ----------\n", kth->name);
+               backtrace_kthread(kth);
+               printk("-----------------\n");
+               print_unlock();
+       }
+       cv_unlock_irqsave(cv, &irq_state);
+}
+
+/* Like sleep, but it will timeout in 'usec' microseconds. */
 void rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg,
-                          unsigned int msec)
+                          uint64_t usec)
 {
        int8_t irq_state = 0;
        struct alarm_waiter awaiter;
        struct cv_lookup_elm cle;
        struct timer_chain *pcpui_tchain = &per_cpu_info[core_id()].tchain;
 
-       assert((int)msec > 0);
-       /* Doing this cond check early, but then unlocking again.  Mostly just to
-        * avoid weird issues with the CV lock and the alarm tchain lock. */
+       assert(can_block(this_pcpui_ptr()));
+       if (!usec)
+               return;
+       /* Doing this cond check early, but then unlocking again.  Mostly just
+        * to avoid weird issues with the CV lock and the alarm tchain lock. */
        cv_lock_irqsave(&rv->cv, &irq_state);
        if (cond(arg)) {
                cv_unlock_irqsave(&rv->cv, &irq_state);
@@ -77,26 +100,27 @@ void rendez_sleep_timeout(struct rendez *rv, int (*cond)(void*), void *arg,
        }
        cv_unlock_irqsave(&rv->cv, &irq_state);
        /* The handler will call rendez_wake, but won't mess with the condition
-        * state.  It's enough to break us out of cv_wait() to see .on_tchain. */
+        * state.  It's enough to break us out of cv_wait() to see .on_tchain is
+        * clear, which is a proxy for "has my alarm fired or will it soon." */
        init_awaiter(&awaiter, rendez_alarm_handler);
        awaiter.data = rv;
-       set_awaiter_rel(&awaiter, msec * 1000);
-       /* Set our alarm on this cpu's tchain.  Note that when we sleep in cv_wait,
-        * we could be migrated, and later on we could be unsetting the alarm
-        * remotely. */
+       set_awaiter_rel(&awaiter, usec);
+       /* Set our alarm on this cpu's tchain.  Note that when we sleep in
+        * cv_wait, we could be migrated, and later on we could be unsetting the
+        * alarm remotely. */
        set_alarm(pcpui_tchain, &awaiter);
        cv_lock_irqsave(&rv->cv, &irq_state);
        __reg_abortable_cv(&cle, &rv->cv);
        /* We could wake early for a few reasons.  Legit wakeups after a changed
-        * condition (and we should exit), other alarms with different timeouts (and
-        * we should go back to sleep), etc.  Note it is possible for our alarm to
-        * fire immediately upon setting it: before we even cv_lock. */
-       while (!cond(arg) && awaiter.on_tchain) {
+        * condition (and we should exit), other alarms with different timeouts
+        * (and we should go back to sleep), etc.  Note it is possible for our
+        * alarm to fire immediately upon setting it: before we even cv_lock. */
+       while (!cond(arg) && !alarm_expired(&awaiter)) {
                if (should_abort(&cle)) {
                        cv_unlock_irqsave(&rv->cv, &irq_state);
                        unset_alarm(pcpui_tchain, &awaiter);
                        dereg_abortable_cv(&cle);
-                       error("syscall aborted");
+                       error(EINTR, "syscall aborted");
                }
                cv_wait(&rv->cv);
                cpu_relax();
@@ -114,8 +138,10 @@ bool rendez_wakeup(struct rendez *rv)
 {
        int8_t irq_state = 0;
        bool ret;
-       /* The plan9 style "one sleeper, one waker" could get by with a signal here.
-        * But we want to make sure all potential waiters are woken up. */
+
+       /* The plan9 style "one sleeper, one waker" could get by with a signal
+        * here.  But we want to make sure all potential waiters are woken up.
+        */
        cv_lock_irqsave(&rv->cv, &irq_state);
        ret = rv->cv.nr_waiters ? TRUE : FALSE;
        __cv_broadcast(&rv->cv);