Moves retvals, start_routine, and args to the 2LSs
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 3 Mar 2011 01:55:41 +0000 (17:55 -0800)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:59 +0000 (17:35 -0700)
Gets the vcore/uthread code out of the business of worrying about
function arguments, stacks, return values, etc.  It also cleans up the
pthread code a bid (don't have to look into the uthread much), with the
exception of init_user_tf().  No way to avoid that look (either for
that, or for stacktop).

It also splits uthread_create() from uthread_runnable(), which was
necessary for the arg indirection (which we did in uthread before), and
is also sort of nice.

Not 100% on this.  Depends if we're going to want schedulers that don't
care about retvals, args, and such, or if they want to do it in a way
that isn't pthreads.  Imagine a creating a thread that takes more than
one argument!!!  *gasp*!  My main concern is that pthread-specific
things get buried in the vcore/uthread code.

user/parlib/include/vcore.h
user/parlib/vcore.c
user/pthread/pthread.c
user/pthread/pthread.h

index 97da920..99ff4af 100644 (file)
@@ -55,12 +55,6 @@ struct uthread {
        struct user_trapframe utf;
        struct ancillary_state as;
        void *tls_desc;
-       /* these four could be put in the 2LSs, but since their main use is by
-        * init_user_tf, which mucks with utf, we'll keep it in vcore code for now*/
-       void *(*start_routine)(void*);
-       void *arg;
-       void *stacktop;
-       void *retval;   /* tied to join, which isn't as clean as i'd like */
        /* whether or not the scheduler can migrate you from your vcore */
        bool dont_migrate;
 };
@@ -71,7 +65,7 @@ struct schedule_ops {
        /* Functions supporting thread ops */
        struct uthread *(*sched_init)(void);
        void (*sched_entry)(void);
-       struct uthread *(*thread_create)(void *);
+       struct uthread *(*thread_create)(void (*func)(void), void *);
        void (*thread_runnable)(struct uthread *);
        void (*thread_yield)(struct uthread *);
        void (*thread_exit)(struct uthread *);
@@ -85,13 +79,12 @@ extern struct schedule_ops *sched_ops;
  * pthread_create(), which can wrap these with their own stuff (like attrs,
  * retvals, etc). */
 
-/* Creates a uthread.  Will pass udata to sched_ops's thread_create.  For now,
- * the vcore/default 2ls code handles start routines and args.  Mostly because
- * this is used when initing a utf, which is vcore specific for now. */
-struct uthread *uthread_create(void *(*start_routine)(void *), void *arg,
-                               void *udata);
+/* Creates a uthread.  Will pass udata to sched_ops's thread_create.  Func is
+ * what gets run, and if you want args, wrap it (like pthread) */
+struct uthread *uthread_create(void (*func)(void), void *udata);
+void uthread_runnable(struct uthread *uthread);
 void uthread_yield(void);
-void uthread_exit(void *retval);
+void uthread_exit(void);
 
 /* Helpers, which sched_entry() can call */
 void run_current_uthread(void);
index a73477c..7d34bb3 100644 (file)
@@ -257,18 +257,10 @@ void __attribute__((noreturn)) vcore_entry()
        assert(0);
 }
 
-/* Could move this, along with start_routine and arg, into the 2LSs */
-static void __uthread_run(void)
-{
-       struct uthread *me = current_thread;
-       uthread_exit(me->start_routine(me->arg));
-}
-
 /* Creates a uthread.  Will pass udata to sched_ops's thread_create.  For now,
  * the vcore/default 2ls code handles start routines and args.  Mostly because
  * this is used when initing a utf, which is vcore specific for now. */
-struct uthread *uthread_create(void *(*start_routine)(void *), void *arg,
-                               void *udata)
+struct uthread *uthread_create(void (*func)(void), void *udata)
 {
        /* First time through, init the vcore code (which makes a uthread out of
         * thread0 / the current code.  Could move this to a ctor. */
@@ -280,14 +272,7 @@ struct uthread *uthread_create(void *(*start_routine)(void *), void *arg,
        }
        assert(!in_vcore_context());
        assert(sched_ops->thread_create);
-       struct uthread *new_thread = sched_ops->thread_create(udata);
-       assert(new_thread->stacktop);
-       new_thread->start_routine = start_routine;
-       new_thread->arg = arg;
-       /* Set the u_tf to start up in __pthread_run, which will call the real
-        * start_routine and pass it the arg. */
-       init_user_tf(&new_thread->utf, (uint32_t)__uthread_run, 
-                 (uint32_t)(new_thread->stacktop));
+       struct uthread *new_thread = sched_ops->thread_create(func, udata);
        /* Get a TLS */
        assert(!__uthread_allocate_tls(new_thread));
        /* Switch into the new guys TLS and let it know who it is */
@@ -307,9 +292,14 @@ struct uthread *uthread_create(void *(*start_routine)(void *), void *arg,
        /* Okay to migrate now. */
        wmb();
        caller->dont_migrate = FALSE;
+       return new_thread;
+}
+
+void uthread_runnable(struct uthread *uthread)
+{
        /* Allow the 2LS to make the thread runnable, and do whatever. */
        assert(sched_ops->thread_runnable);
-       sched_ops->thread_runnable(new_thread);
+       sched_ops->thread_runnable(uthread);
        /* This is where we'll call out to a smarter 2LS function to see if we want
         * to get more cores (and how many). */
        /* Need to get some vcores.  If this is the first time, we'd like to get
@@ -337,7 +327,6 @@ struct uthread *uthread_create(void *(*start_routine)(void *), void *arg,
                 * one or not, so long as we still have at least 1. */
                vcore_request(1);
        }
-       return new_thread;
 }
 
 /* Need to have this as a separate, non-inlined function since we clobber the
@@ -430,11 +419,10 @@ __uthread_exit(struct uthread *uthread)
 }
 
 /* Exits from the uthread */
-void uthread_exit(void *retval)
+void uthread_exit(void)
 {
        assert(!in_vcore_context());
        struct uthread *uthread = current_thread;
-       uthread->retval = retval;
        /* Don't migrate this thread to anothe vcore, since it depends on being on
         * the same vcore throughout. */
        uthread->dont_migrate = TRUE; // won't set to false later, since he is dying
index fc705d9..34dc8be 100644 (file)
@@ -30,7 +30,7 @@ static inline void spin_to_sleep(unsigned int spins, unsigned int *spun);
 /* Pthread 2LS operations */
 struct uthread *pth_init(void);
 void pth_sched_entry(void);
-struct uthread *pth_thread_create(void *udata);
+struct uthread *pth_thread_create(void (*func)(void), void *udata);
 void pth_thread_runnable(struct uthread *uthread);
 void pth_thread_yield(struct uthread *uthread);
 void pth_thread_exit(struct uthread *uthread);
@@ -111,7 +111,15 @@ void pth_sched_entry(void)
        assert(0);
 }
 
-struct uthread *pth_thread_create(void *udata)
+/* Could move this, along with start_routine and arg, into the 2LSs */
+static void __pthread_run(void)
+{
+       struct pthread_tcb *me = pthread_self();
+       pthread_exit(me->start_routine(me->arg));
+}
+
+/* Responible for creating the uthread and initializing its user trap frame */
+struct uthread *pth_thread_create(void (*func)(void), void *udata)
 {
        struct pthread_tcb *pthread;
        pthread_attr_t *attr = (pthread_attr_t*)udata;
@@ -129,6 +137,11 @@ struct uthread *pth_thread_create(void *udata)
        /* allocate a stack */
        if (__pthread_allocate_stack(pthread))
                printf("We're fucked\n");
+       /* Set the u_tf to start up in __pthread_run, which will call the real
+        * start_routine and pass it the arg.  Note those aren't set until later in
+        * pthread_create(). */
+       init_user_tf(&pthread->uthread.utf, (uint32_t)__pthread_run, 
+                 (uint32_t)(pthread->stacktop));
        return (struct uthread*)pthread;
 }
 
@@ -205,7 +218,7 @@ int pthread_attr_destroy(pthread_attr_t *a)
 
 static void __pthread_free_stack(struct pthread_tcb *pt)
 {
-       assert(!munmap(pt->uthread.stacktop - PTHREAD_STACK_SIZE, PTHREAD_STACK_SIZE));
+       assert(!munmap(pt->stacktop - PTHREAD_STACK_SIZE, PTHREAD_STACK_SIZE));
 }
 
 static int __pthread_allocate_stack(struct pthread_tcb *pt)
@@ -216,7 +229,7 @@ static int __pthread_allocate_stack(struct pthread_tcb *pt)
                              MAP_POPULATE|MAP_ANONYMOUS, -1, 0);
        if (stackbot == MAP_FAILED)
                return -1; // errno set by mmap
-       pt->uthread.stacktop = stackbot + pt->stacksize;
+       pt->stacktop = stackbot + pt->stacksize;
        return 0;
 }
 
@@ -241,10 +254,14 @@ int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
 int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
                    void *(*start_routine)(void *), void* arg)
 {
-       struct uthread *uthread = uthread_create(start_routine, arg, (void*)attr);
-       if (!uthread)
+       struct pthread_tcb *pthread =
+              (struct pthread_tcb*)uthread_create(__pthread_run, (void*)attr);
+       if (!pthread)
                return -1;
-       *thread = (struct pthread_tcb*)uthread;
+       pthread->start_routine = start_routine;
+       pthread->arg = arg;
+       uthread_runnable((struct uthread*)pthread);
+       *thread = pthread;
        return 0;
 }
 
@@ -260,7 +277,7 @@ int pthread_join(pthread_t thread, void** retval)
        while (!thread->finished)
                pthread_yield();
        if (retval)
-               *retval = thread->uthread.retval;
+               *retval = thread->retval;
        free(thread);
        return 0;
 }
@@ -444,7 +461,9 @@ int pthread_equal(pthread_t t1, pthread_t t2)
  * scheduler.  Will need to sort that shit out. */
 void pthread_exit(void *ret)
 {
-       uthread_exit(ret);
+       struct pthread_tcb *pthread = pthread_self();
+       pthread->retval = ret;
+       uthread_exit();
 }
 
 int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
index 9bc93a8..5fae89d 100644 (file)
@@ -18,6 +18,10 @@ struct pthread_tcb {
        bool detached;
        uint32_t id;
        uint32_t stacksize;
+       void *(*start_routine)(void*);
+       void *arg;
+       void *stacktop;
+       void *retval;
 };
 typedef struct pthread_tcb* pthread_t;
 TAILQ_HEAD(pthread_queue, pthread_tcb);