Fixes slab page allocators
[akaros.git] / user / parlib / vcore.c
index 73d8d6e..5354ae7 100644 (file)
@@ -9,7 +9,6 @@
 #include <stdlib.h>
 #include <sys/mman.h>
 #include <stdio.h>
-#include <glibc-tls.h>
 #include <event.h>
 #include <uthread.h>
 #include <ucq.h>
 static size_t _max_vcores_ever_wanted = 1;
 atomic_t nr_new_vcores_wanted;
 atomic_t vc_req_being_handled;
-/* Simple ev_q (bits, IPIs, vc0) for scp syscalls, signals, etc */
-struct event_queue *__scp_simple_evq = 0;
 
 extern void** vcore_thread_control_blocks;
-
-/* Get a TLS, returns 0 on failure.  Vcores have their own TLS, and any thread
- * created by a user-level scheduler needs to create a TLS as well. */
-void *allocate_tls(void)
-{
-       extern void *_dl_allocate_tls(void *mem) internal_function;
-       void *tcb = _dl_allocate_tls(NULL);
-       if (!tcb)
-               return 0;
-       /* Make sure the TLS is set up properly - its tcb pointer points to itself.
-        * Keep this in sync with sysdeps/ros/XXX/tls.h.  For whatever reason,
-        * dynamically linked programs do not need this to be redone, but statics
-        * do. */
-       tcbhead_t *head = (tcbhead_t*)tcb;
-       head->tcb = tcb;
-       head->self = tcb;
-       return tcb;
-}
-
-/* Free a previously allocated TLS region */
-void free_tls(void *tcb)
-{
-       extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
-       assert(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();
-}
+__thread struct syscall __vcore_one_sysc = {.flags = (atomic_t)SC_DONE, 0};
 
 /* TODO: probably don't want to dealloc.  Considering caching */
 static void free_transition_tls(int id)
@@ -165,16 +126,6 @@ vcore_init_fail:
        return -1;
 }
 
-/* this, plus tricking gcc into thinking this is -u (undefined), AND including
- * the event_init in it, causes the linker to need to check parlib.a and see the
- * strong symbol... */
-void force_parlib_symbols(void)
-{
-       vcore_event_init();
-       ros_syscall_blockon(0); /* don't seem to need to force this for now */
-       assert(0);
-}
-
 /* This gets called in glibc before calling the programs 'main'.  Need to set
  * ourselves up so that thread0 is a uthread, and then register basic signals to
  * go to vcore 0. */
@@ -182,12 +133,6 @@ void vcore_event_init(void)
 {
        /* set up our thread0 as a uthread */
        uthread_slim_init();
-       /* Set up an ev_q for blocking _Ss on syscalls.  Events will get sent to
-        * vcore0's VCPD public mbox.  We'll get a bit, instead of a full message,
-        * since we don't need to know *sysc.  Also note that the event handler is
-        * 0, until set by a 2LS.  We don't need a handler - just need to get woken
-        * up. */
-       __scp_simple_evq = get_event_q_vcpd(0, EVENT_NOMSG | EVENT_IPI);
        /* TODO: register for other kevents/signals and whatnot (can probably reuse
         * the simple ev_q).  Could also do this via explicit functions from the
         * program. */
@@ -311,36 +256,41 @@ try_handle_it:
        return 0;
 }
 
-/* This can return, if you failed to yield due to a concurrent event. */
+/* This can return, if you failed to yield due to a concurrent event.  Note
+ * we're atomicly setting the CAN_RCV flag, and aren't bothering with CASing
+ * (either with the kernel or uthread's handle_indirs()).  We don't particularly
+ * care what other code does - we intend to set those flags no matter what. */
 void vcore_yield(bool preempt_pending)
 {
        uint32_t vcoreid = vcore_id();
        struct preempt_data *vcpd = vcpd_of(vcoreid);
-       vcpd->can_rcv_msg = FALSE;
+       __sync_fetch_and_and(&vcpd->flags, ~VC_CAN_RCV_MSG);
        /* no wrmb() necessary, clear_notif() has an mb() */
        /* Clears notif pending.  If we had an event outstanding, this will handle
         * it and return TRUE, at which point we want to unwind and return to the
         * 2LS loop (where we may not want to yield anymore).  Note that the kernel
-        * only cares about can_rcv_msg for the desired vcore, not for a FALLBACK.
+        * only cares about CAN_RCV_MSG for the desired vcore, not for a FALLBACK.
         * We need to deal with this notif_pending business regardless of
-        * can_rcv_msg.  We just want to avoid a yield syscall if possible.  It is
+        * CAN_RCV_MSG.  We just want to avoid a yield syscall if possible.  It is
         * important that clear_notif_pending will handle_events().  That is
-        * necessary to do/check after setting can_rcv_msg to FALSE. */
+        * necessary to do/check after turning off CAN_RCV_MSG. */
        if (clear_notif_pending(vcoreid)) {
-               vcpd->can_rcv_msg = TRUE;
+               __sync_fetch_and_or(&vcpd->flags, VC_CAN_RCV_MSG);
                return;
        }
-       /* Tell the kernel we want one less vcore.  If yield fails (slight race), we
-        * may end up having more vcores than amt_wanted for a while, and might lose
-        * one later on (after a preempt/timeslicing) - the 2LS will have to notice
-        * eventually if it actually needs more vcores (which it already needs to
-        * do).  We need to atomically decrement, though I don't want the kernel's
-        * data type here to be atomic_t (only userspace cares in this one case). */
-       __sync_fetch_and_sub(&__procdata.res_req[RES_CORES].amt_wanted, 1);
+       /* If we are yielding since we don't want the core, tell the kernel we want
+        * one less vcore.  If yield fails (slight race), we may end up having more
+        * vcores than amt_wanted for a while, and might lose one later on (after a
+        * preempt/timeslicing) - the 2LS will have to notice eventually if it
+        * actually needs more vcores (which it already needs to do).  We need to
+        * atomically decrement, though I don't want the kernel's data type here to
+        * be atomic_t (only userspace cares in this one case). */
+       if (!preempt_pending)
+               __sync_fetch_and_sub(&__procdata.res_req[RES_CORES].amt_wanted, 1);
        /* We can probably yield.  This may pop back up if notif_pending became set
         * by the kernel after we cleared it and we lost the race. */
        sys_yield(preempt_pending);
-       vcpd->can_rcv_msg = TRUE;
+       __sync_fetch_and_or(&vcpd->flags, VC_CAN_RCV_MSG);
 }
 
 /* Clear pending, and try to handle events that came in between a previous call
@@ -462,3 +412,30 @@ void cpu_relax_vc(uint32_t vcoreid)
        }
        cpu_relax();
 }
+
+/* Check with the kernel to determine what vcore we are.  Normally, you should
+ * never call this, since your vcoreid is stored in your TLS.  Also, if you call
+ * it from a uthread, you could get migrated, so you should drop into some form
+ * of vcore context (DONT_MIGRATE on) */
+uint32_t get_vcoreid(void)
+{
+       if (!in_vcore_context()) {
+               assert(current_uthread);
+               assert(current_uthread->flags & UTHREAD_DONT_MIGRATE);
+       }
+       return __get_vcoreid();
+}
+
+/* Debugging helper.  Pass in the string you want printed if your vcoreid is
+ * wrong, and pass in what vcoreid you think you are.  Don't call from uthread
+ * context unless migrations are disabled.  Will print some stuff and return
+ * FALSE if you were wrong. */
+bool check_vcoreid(const char *str, uint32_t vcoreid)
+{
+       uint32_t kvcoreid = get_vcoreid();
+       if (vcoreid != kvcoreid) {
+               ros_debug("%s: VC %d thought it was VC %d\n", str, kvcoreid, vcoreid);
+               return FALSE;
+       }
+       return TRUE;
+}