Allows uthread_init() to be called repeatedly
[akaros.git] / user / parlib / vcore.c
index e51abd8..b521fdf 100644 (file)
@@ -47,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)
 {
@@ -119,7 +130,7 @@ int vcore_init()
        /* 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, -1, 0);
+                                    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. */
@@ -128,9 +139,9 @@ int vcore_init()
         * separate ev_q for that. */
        for (int i = 0; i < max_vcores(); i++) {
                /* two pages each from the big block */
-               ucq_init(&__procdata.vcore_preempt_data[i].ev_mbox.ev_msgs,
-                        mmap_block + (2 * i    ) * PGSIZE, 
-                        mmap_block + (2 * i + 1) * PGSIZE); 
+               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;
@@ -184,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);
 }