Allows uthread_init() to be called repeatedly
[akaros.git] / user / parlib / vcore.c
index 8f4bb30..b521fdf 100644 (file)
@@ -12,6 +12,7 @@
 #include <glibc-tls.h>
 #include <event.h>
 #include <uthread.h>
+#include <ucq.h>
 #include <ros/arch/membar.h>
 
 /* starting with 1 since we alloc vcore0's stacks and TLS in vcore_init(). */
@@ -46,6 +47,17 @@ void free_tls(void *tcb)
        _dl_deallocate_tls(tcb, TRUE);
 }
 
+/* Reinitialize / reset / refresh a TLS to its initial values.  This doesn't do
+ * it properly yet, it merely frees and re-allocates the TLS, which is why we're
+ * slightly ghetto and return the pointer you should use for the TCB. */
+void *reinit_tls(void *tcb)
+{
+       /* TODO: keep this in sync with the methods used in
+        * allocate_transition_tls() */
+       free_tls(tcb);
+       return allocate_tls();
+}
+
 /* TODO: probably don't want to dealloc.  Considering caching */
 static void free_transition_tls(int id)
 {
@@ -100,6 +112,7 @@ static int allocate_transition_stack(int id)
 int vcore_init()
 {
        static int initialized = 0;
+       uintptr_t mmap_block;
        if(initialized)
                return 0;
 
@@ -114,6 +127,22 @@ int vcore_init()
        if(allocate_transition_stack(0) || allocate_transition_tls(0))
                goto vcore_init_tls_fail;
 
+       /* Initialize our VCPD event queues' ucqs, two pages per vcore */
+       mmap_block = (uintptr_t)mmap(0, PGSIZE * 2 * max_vcores(),
+                                    PROT_WRITE | PROT_READ,
+                                    MAP_POPULATE | MAP_ANONYMOUS, -1, 0);
+       /* Yeah, this doesn't fit in the error-handling scheme, but this whole
+        * system doesn't really handle failure, and needs a rewrite involving less
+        * mmaps/munmaps. */
+       assert(mmap_block);
+       /* Note we may end up doing vcore 0's elsewhere, for _Ss, or else have a
+        * separate ev_q for that. */
+       for (int i = 0; i < max_vcores(); i++) {
+               /* two pages each from the big block */
+               ucq_init_raw(&__procdata.vcore_preempt_data[i].ev_mbox.ev_msgs,
+                            mmap_block + (2 * i    ) * PGSIZE, 
+                            mmap_block + (2 * i + 1) * PGSIZE); 
+       }
        assert(!in_vcore_context());
        initialized = 1;
        return 0;
@@ -166,8 +195,19 @@ fail:
        return ret;
 }
 
+/* This can return, if you failed to yield due to a concurrent event. */
 void vcore_yield()
 {
+       uint32_t vcoreid = vcore_id();
+       struct preempt_data *vcpd = &__procdata.vcore_preempt_data[vcoreid];
+       vcpd->can_rcv_msg = FALSE;
+       wmb();
+       if (handle_events(vcoreid)) {
+               /* we handled outstanding events, turn the flag back on and return */
+               vcpd->can_rcv_msg = TRUE;
+               return;
+       }
+       /* o/w, we can safely yield */
        sys_yield(0);
 }