Pthread state tracking
[akaros.git] / user / pthread / pthread.c
index 6c7d476..0eb1ff8 100644 (file)
@@ -102,6 +102,7 @@ void __attribute__((noreturn)) pth_sched_entry(void)
                 * bit before yielding (or not at all if you want to be greedy). */
                vcore_yield(FALSE);
        } while (1);
                 * bit before yielding (or not at all if you want to be greedy). */
                vcore_yield(FALSE);
        } while (1);
+       assert(new_thread->state == PTH_RUNNABLE);
        run_uthread((struct uthread*)new_thread);
        assert(0);
 }
        run_uthread((struct uthread*)new_thread);
        assert(0);
 }
@@ -116,6 +117,23 @@ static void __pthread_run(void)
 void pth_thread_runnable(struct uthread *uthread)
 {
        struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
 void pth_thread_runnable(struct uthread *uthread)
 {
        struct pthread_tcb *pthread = (struct pthread_tcb*)uthread;
+       /* At this point, the 2LS can see why the thread blocked and was woken up in
+        * the first place (coupling these things together).  On the yield path, the
+        * 2LS was involved and was able to set the state.  Now when we get the
+        * thread back, we can take a look. */
+       printd("pthread %08p runnable, state was %d\n", pthread, pthread->state);
+       switch (pthread->state) {
+               case (PTH_CREATED):
+               case (PTH_BLK_YIELDING):
+               case (PTH_BLK_JOINING):
+               case (PTH_BLK_SYSC):
+               case (PTH_BLK_MUTEX):
+                       /* can do whatever for each of these cases */
+                       break;
+               default:
+                       printf("Odd state %d for pthread %08p\n", pthread->state, pthread);
+       }
+       pthread->state = PTH_RUNNABLE;
        /* Insert the newly created thread into the ready queue of threads.
         * It will be removed from this queue later when vcore_entry() comes up */
        mcs_pdr_lock(&queue_lock);
        /* Insert the newly created thread into the ready queue of threads.
         * It will be removed from this queue later when vcore_entry() comes up */
        mcs_pdr_lock(&queue_lock);
@@ -139,7 +157,7 @@ void pth_thread_yield(struct uthread *uthread)
        threads_active--;
        TAILQ_REMOVE(&active_queue, pthread, next);
        mcs_pdr_unlock(&queue_lock);
        threads_active--;
        TAILQ_REMOVE(&active_queue, pthread, next);
        mcs_pdr_unlock(&queue_lock);
-       if (pthread->flags & PTHREAD_EXITING) {
+       if (pthread->state == PTH_EXITING) {
                /* Destroy the pthread */
                uthread_cleanup(uthread);
                /* Cleanup, mirroring pthread_create() */
                /* Destroy the pthread */
                uthread_cleanup(uthread);
                /* Cleanup, mirroring pthread_create() */
@@ -158,7 +176,7 @@ void pth_thread_yield(struct uthread *uthread)
                                uthread_runnable((struct uthread*)temp_pth);
                        }
                }
                                uthread_runnable((struct uthread*)temp_pth);
                        }
                }
-       } else if (pthread->flags & PTHREAD_JOINING) {
+       } else if (pthread->state == PTH_BLK_JOINING) {
                /* We're trying to join, yield til we get woken up */
                /* put ourselves in the join target's joiner slot.  If we get anything
                 * back, we lost the race and need to wake ourselves. */
                /* We're trying to join, yield til we get woken up */
                /* put ourselves in the join target's joiner slot.  If we get anything
                 * back, we lost the race and need to wake ourselves. */
@@ -175,6 +193,7 @@ void pth_thread_yield(struct uthread *uthread)
                        uthread_runnable((struct uthread*)pthread);
                }
        } else {
                        uthread_runnable((struct uthread*)pthread);
                }
        } else {
+               assert(pthread->state == PTH_BLK_YIELDING);
                /* Yielding for no apparent reason (being nice / help break deadlocks).
                 * Just wake it up and make it ready again. */
                uthread_runnable((struct uthread*)pthread);
                /* Yielding for no apparent reason (being nice / help break deadlocks).
                 * Just wake it up and make it ready again. */
                uthread_runnable((struct uthread*)pthread);
@@ -222,7 +241,7 @@ static void restart_thread(struct syscall *sysc)
        struct uthread *ut_restartee = (struct uthread*)sysc->u_data;
        /* uthread stuff here: */
        assert(ut_restartee);
        struct uthread *ut_restartee = (struct uthread*)sysc->u_data;
        /* uthread stuff here: */
        assert(ut_restartee);
-       //assert(ut_restartee->state == UT_BLOCKED);
+       assert(((struct pthread_tcb*)ut_restartee)->state == PTH_BLK_SYSC);
        assert(ut_restartee->sysc == sysc);
        ut_restartee->sysc = 0; /* so we don't 'reblock' on this later */
        uthread_runnable(ut_restartee);
        assert(ut_restartee->sysc == sysc);
        ut_restartee->sysc = 0; /* so we don't 'reblock' on this later */
        uthread_runnable(ut_restartee);
@@ -260,9 +279,9 @@ void pth_blockon_sysc(struct syscall *sysc)
        bool need_to_restart = FALSE;
        uint32_t vcoreid = vcore_id();
 
        bool need_to_restart = FALSE;
        uint32_t vcoreid = vcore_id();
 
-       //assert(current_uthread->state == UT_BLOCKED);
        /* rip from the active queue */
        struct pthread_tcb *pthread = (struct pthread_tcb*)current_uthread;
        /* rip from the active queue */
        struct pthread_tcb *pthread = (struct pthread_tcb*)current_uthread;
+       pthread->state = PTH_BLK_SYSC;
        mcs_pdr_lock(&queue_lock);
        threads_active--;
        TAILQ_REMOVE(&active_queue, pthread, next);
        mcs_pdr_lock(&queue_lock);
        threads_active--;
        TAILQ_REMOVE(&active_queue, pthread, next);
@@ -346,7 +365,7 @@ static int pthread_lib_init(void)
        t->stacksize = USTACK_NUM_PAGES * PGSIZE;
        t->stacktop = (void*)USTACKTOP;
        t->detached = TRUE;
        t->stacksize = USTACK_NUM_PAGES * PGSIZE;
        t->stacktop = (void*)USTACKTOP;
        t->detached = TRUE;
-       t->flags = 0;
+       t->state = PTH_RUNNING;
        t->join_target = 0;
        t->joiner = 0;
        assert(t->id == 0);
        t->join_target = 0;
        t->joiner = 0;
        assert(t->id == 0);
@@ -426,7 +445,7 @@ int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
        pthread = (pthread_t)calloc(1, sizeof(struct pthread_tcb));
        assert(pthread);
        pthread->stacksize = PTHREAD_STACK_SIZE;        /* default */
        pthread = (pthread_t)calloc(1, sizeof(struct pthread_tcb));
        assert(pthread);
        pthread->stacksize = PTHREAD_STACK_SIZE;        /* default */
-       pthread->flags = 0;
+       pthread->state = PTH_CREATED;
        pthread->id = get_next_pid();
        pthread->detached = FALSE;                              /* default */
        pthread->join_target = 0;
        pthread->id = get_next_pid();
        pthread->detached = FALSE;                              /* default */
        pthread->join_target = 0;
@@ -469,7 +488,7 @@ int pthread_join(pthread_t thread, void** retval)
         * early check is an optimization, pth_thread_yield() handles the race). */
        if (!thread->joiner) {
                /* Time to join, set things up so pth_thread_yield() knows what to do */
         * early check is an optimization, pth_thread_yield() handles the race). */
        if (!thread->joiner) {
                /* Time to join, set things up so pth_thread_yield() knows what to do */
-               caller->flags |= PTHREAD_JOINING;
+               caller->state = PTH_BLK_JOINING;
                caller->join_target = thread;
                uthread_yield(TRUE);
                /* When we return/restart, the thread will be done */
                caller->join_target = thread;
                uthread_yield(TRUE);
                /* When we return/restart, the thread will be done */
@@ -484,6 +503,8 @@ int pthread_join(pthread_t thread, void** retval)
 
 int pthread_yield(void)
 {
 
 int pthread_yield(void)
 {
+       struct pthread_tcb *caller = (struct pthread_tcb*)current_uthread;
+       caller->state = PTH_BLK_YIELDING;
        uthread_yield(TRUE);
        return 0;
 }
        uthread_yield(TRUE);
        return 0;
 }
@@ -667,7 +688,7 @@ void pthread_exit(void *ret)
        struct pthread_tcb *pthread = pthread_self();
        pthread->retval = ret;
        /* So our pth_thread_yield knows we want to exit */
        struct pthread_tcb *pthread = pthread_self();
        pthread->retval = ret;
        /* So our pth_thread_yield knows we want to exit */
-       pthread->flags |= PTHREAD_EXITING;
+       pthread->state = PTH_EXITING;
        uthread_yield(FALSE);
 }
 
        uthread_yield(FALSE);
 }