vmm: Moves gpci into guest_thread
[akaros.git] / user / parlib / mutex.c
index d2a9c8e..c391c03 100644 (file)
@@ -108,7 +108,8 @@ static void __semaphore_cb(struct uthread *uth, void *arg)
         *
         * Also note the lock-ordering rule.  The sem lock is grabbed before any
         * locks the 2LS might grab. */
-       uthread_has_blocked(uth, &sem->sync_obj, UTH_EXT_BLK_MUTEX);
+       uthread_has_blocked(uth, UTH_EXT_BLK_MUTEX);
+       __uth_sync_enqueue(uth, &sem->sync_obj);
        spin_pdr_unlock(&sem->lock);
 }
 
@@ -396,7 +397,8 @@ static void __cv_wait_cb(struct uthread *uth, void *arg)
         *
         * Also note the lock-ordering rule.  The cv lock is grabbed before any
         * locks the 2LS might grab. */
-       uthread_has_blocked(uth, &cv->sync_obj, UTH_EXT_BLK_MUTEX);
+       uthread_has_blocked(uth, UTH_EXT_BLK_MUTEX);
+       __uth_sync_enqueue(uth, &cv->sync_obj);
        spin_pdr_unlock(&cv->lock);
        /* This looks dangerous, since both the CV and MTX could use the
         * uth->sync_next TAILQ_ENTRY (or whatever the 2LS uses), but the uthread
@@ -542,21 +544,18 @@ void uth_cond_var_signal(uth_cond_var_t *cv)
 
 void uth_cond_var_broadcast(uth_cond_var_t *cv)
 {
-       struct uth_tailq restartees = TAILQ_HEAD_INITIALIZER(restartees);
-       struct uthread *i, *safe;
+       uth_sync_t restartees;
 
        parlib_run_once(&cv->once_ctl, __uth_cond_var_init, cv);
        spin_pdr_lock(&cv->lock);
-       /* If this turns out to be slow or painful for 2LSs, we can implement a
-        * get_all or something (default used to use TAILQ_SWAP). */
-       while ((i = __uth_sync_get_next(&cv->sync_obj))) {
-               /* Once the uth is out of the sync obj, we can reuse sync_next. */
-               TAILQ_INSERT_TAIL(&restartees, i, sync_next);
+       if (__uth_sync_is_empty(&cv->sync_obj)) {
+               spin_pdr_unlock(&cv->lock);
+               return;
        }
+       __uth_sync_init(&restartees);
+       __uth_sync_swap(&restartees, &cv->sync_obj);
        spin_pdr_unlock(&cv->lock);
-       /* Need the SAFE, since we can't touch the linkage once the uth could run */
-       TAILQ_FOREACH_SAFE(i, &restartees, sync_next, safe)
-               uthread_runnable(i);
+       __uth_sync_wake_all(&restartees);
 }
 
 
@@ -608,7 +607,8 @@ static void __rwlock_rd_cb(struct uthread *uth, void *arg)
 {
        struct uth_rwlock *rwl = (struct uth_rwlock*)arg;
 
-       uthread_has_blocked(uth, &rwl->readers, UTH_EXT_BLK_MUTEX);
+       uthread_has_blocked(uth, UTH_EXT_BLK_MUTEX);
+       __uth_sync_enqueue(uth, &rwl->readers);
        spin_pdr_unlock(&rwl->lock);
 }
 
@@ -645,7 +645,8 @@ static void __rwlock_wr_cb(struct uthread *uth, void *arg)
 {
        struct uth_rwlock *rwl = (struct uth_rwlock*)arg;
 
-       uthread_has_blocked(uth, &rwl->writers, UTH_EXT_BLK_MUTEX);
+       uthread_has_blocked(uth, UTH_EXT_BLK_MUTEX);
+       __uth_sync_enqueue(uth, &rwl->writers);
        spin_pdr_unlock(&rwl->lock);
 }
 
@@ -748,6 +749,13 @@ static void uth_default_sync_destroy(uth_sync_t *sync)
        assert(TAILQ_EMPTY(tq));
 }
 
+static void uth_default_sync_enqueue(struct uthread *uth, uth_sync_t *sync)
+{
+       struct uth_tailq *tq = (struct uth_tailq*)sync;
+
+       TAILQ_INSERT_TAIL(tq, uth, sync_next);
+}
+
 static struct uthread *uth_default_sync_get_next(uth_sync_t *sync)
 {
        struct uth_tailq *tq = (struct uth_tailq*)sync;
@@ -773,16 +781,23 @@ static bool uth_default_sync_get_uth(uth_sync_t *sync, struct uthread *uth)
        return FALSE;
 }
 
-/************** External uthread sync interface **************/
+static void uth_default_sync_swap(uth_sync_t *a, uth_sync_t *b)
+{
+       struct uth_tailq *tq_a = (struct uth_tailq*)a;
+       struct uth_tailq *tq_b = (struct uth_tailq*)b;
+
+       TAILQ_SWAP(tq_a, tq_b, uthread, sync_next);
+}
 
-/* Called by the 2LS->has_blocked op, if they are using the default sync.*/
-void __uth_default_sync_enqueue(struct uthread *uth, uth_sync_t *sync)
+static bool uth_default_sync_is_empty(uth_sync_t *sync)
 {
        struct uth_tailq *tq = (struct uth_tailq*)sync;
 
-       TAILQ_INSERT_TAIL(tq, uth, sync_next);
+       return TAILQ_EMPTY(tq);
 }
 
+/************** External uthread sync interface **************/
+
 /* Called by 2LS-independent sync code when a sync object needs initialized. */
 void __uth_sync_init(uth_sync_t *sync)
 {
@@ -803,6 +818,16 @@ void __uth_sync_destroy(uth_sync_t *sync)
        uth_default_sync_destroy(sync);
 }
 
+/* Called by 2LS-independent sync code when a thread blocks on sync */
+void __uth_sync_enqueue(struct uthread *uth, uth_sync_t *sync)
+{
+       if (sched_ops->sync_enqueue) {
+               sched_ops->sync_enqueue(uth, sync);
+               return;
+       }
+       uth_default_sync_enqueue(uth, sync);
+}
+
 /* Called by 2LS-independent sync code when a thread needs to be woken. */
 struct uthread *__uth_sync_get_next(uth_sync_t *sync)
 {
@@ -819,3 +844,36 @@ bool __uth_sync_get_uth(uth_sync_t *sync, struct uthread *uth)
                return sched_ops->sync_get_uth(sync, uth);
        return uth_default_sync_get_uth(sync, uth);
 }
+
+/* Called by 2LS-independent sync code to swap members of sync objects. */
+void __uth_sync_swap(uth_sync_t *a, uth_sync_t *b)
+{
+       if (sched_ops->sync_swap) {
+               sched_ops->sync_swap(a, b);
+               return;
+       }
+       uth_default_sync_swap(a, b);
+}
+
+/* Called by 2LS-independent sync code */
+bool __uth_sync_is_empty(uth_sync_t *sync)
+{
+       if (sched_ops->sync_is_empty)
+               return sched_ops->sync_is_empty(sync);
+       return uth_default_sync_is_empty(sync);
+}
+
+/* Called by 2LS-independent sync code to wake up all uths on sync.  You should
+ * probably not hold locks while you do this - swap the items to a local sync
+ * object first. */
+void __uth_sync_wake_all(uth_sync_t *wakees)
+{
+       struct uthread *uth_i;
+
+       if (sched_ops->thread_bulk_runnable) {
+               sched_ops->thread_bulk_runnable(wakees);
+       } else {
+               while ((uth_i = __uth_sync_get_next(wakees)))
+                       uthread_runnable(uth_i);
+       }
+}