kthread_usleep()
[akaros.git] / kern / src / kthread.c
index 50d5372..8dbc0b6 100644 (file)
@@ -107,7 +107,7 @@ void restart_kthread(struct kthread *kthread)
                pcpui->cur_proc = kthread->proc;
        }
        /* Finally, restart our thread */
-       pop_kernel_ctx(&kthread->context);
+       longjmp(&kthread->context, 1);
 }
 
 /* Kmsg handler to launch/run a kthread.  This must be a routine message, since
@@ -180,6 +180,17 @@ void kthread_yield(void)
        sem_down(sem);
 }
 
+void kthread_usleep(uint64_t usec)
+{
+       /* TODO: classic ksched issue: where do we want the wake up to happen? */
+       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
+       struct alarm_waiter a_waiter;
+       init_awaiter(&a_waiter, 0);
+       set_awaiter_rel(&a_waiter, usec);
+       set_alarm(tchain, &a_waiter);
+       sleep_on_awaiter(&a_waiter);
+}
+
 static void __ktask_wrapper(uint32_t srcid, long a0, long a1, long a2)
 {
        ERRSTACK(1);
@@ -278,7 +289,6 @@ bool sem_trydown(struct semaphore *sem)
  * signal is already there is not optimized. */
 void sem_down(struct semaphore *sem)
 {
-       volatile bool blocking = TRUE;  /* signal to short circuit when restarting*/
        struct kthread *kthread, *new_kthread;
        register uintptr_t new_stacktop;
        struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
@@ -360,40 +370,30 @@ void sem_down(struct semaphore *sem)
        } else {
                kthread->proc = 0;
        } 
-       /* Save the context, toggle blocking for the reactivation */
-       save_kernel_ctx(&kthread->context);
-       if (!blocking)
+       if (setjmp(&kthread->context))
                goto block_return_path;
-       blocking = FALSE;                                       /* for when it starts back up */
-       /* Down the semaphore.  We need this to be inline.  If we're sleeping, once
-        * we unlock the kthread could be started up again and can return and start
-        * trashing this function's stack, hence the weird control flow. */
        spin_lock(&sem->lock);
        if (sem->nr_signals-- <= 0) {
                TAILQ_INSERT_TAIL(&sem->waiters, kthread, link);
-               debug_downed_sem(sem);
+               debug_downed_sem(sem);  /* need to debug after inserting */
                /* At this point, we know we'll sleep and change stacks later.  Once we
                 * unlock, we could have the kthread restarted (possibly on another
                 * core), so we need to disable irqs until we are on our new stack.
                 * Otherwise, if we take an IRQ, we'll be using our stack while another
                 * core is using it (restarted kthread).  Basically, disabling irqs
-                * allows us to atomically unlock and 'yield'. */
+                * allows us to atomically unlock and 'yield'.  Also, IRQs might have
+                * already been disabled if this was an irqsave sem. */
                disable_irq();
-       } else {                                                        /* we didn't sleep */
-               debug_downed_sem(sem);
-               goto unwind_sleep_prep;
+               spin_unlock(&sem->lock);
+               /* Switch to the core's default stack.  After this, don't use local
+                * variables. */
+               set_stack_pointer(new_stacktop);
+               smp_idle();                                                     /* reenables irqs eventually */
+               assert(0);
        }
-       spin_unlock(&sem->lock);
-       /* Switch to the core's default stack.  After this, don't use local
-        * variables.  TODO: we shouldn't be using new_stacktop either, can't always
-        * trust the register keyword (AFAIK). */
-       set_stack_pointer(new_stacktop);
-       smp_idle();                                                     /* reenables irqs eventually */
-       /* smp_idle never returns */
-       assert(0);
-unwind_sleep_prep:
        /* We get here if we should not sleep on sem (the signal beat the sleep).
-        * Note we are not optimizing for cases where the signal won. */
+        * We debug_downed_sem since we actually downed it - just didn't sleep. */
+       debug_downed_sem(sem);
        spin_unlock(&sem->lock);
        printd("[kernel] Didn't sleep, unwinding...\n");
        /* Restore the core's current and default stacktop */
@@ -412,12 +412,10 @@ unwind_sleep_prep:
 #endif /* CONFIG_KTHREAD_POISON */
 block_return_path:
        printd("[kernel] Returning from being 'blocked'! at %llu\n", read_tsc());
-       /* restart_kthread and pop_kernel_ctx do not reenable IRQs.  IRQs (and
-        * flags) are in whatever state they were in by the restart code (disabled,
-        * flags are garbage.  save_kernel_ctx expects the flags to be clobbered.
-        * ("cc")).  We need to make sure irqs are on if they were on when we
-        * started to block.  If they were already on and we short-circuited the
-        * block, it's harmless to reenable them. */
+       /* restart_kthread and longjmp did not reenable IRQs.  We need to make sure
+        * irqs are on if they were on when we started to block.  If they were
+        * already on and we short-circuited the block, it's harmless to reenable
+        * them. */
        if (irqs_were_on)
                enable_irq();
        return;