Pthread scheduling hooks
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 4 May 2015 16:14:39 +0000 (12:14 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Wed, 6 May 2015 21:14:31 +0000 (17:14 -0400)
There are a bunch of ways to set scheduling priorities, policies, and
scope.  We'll allow programs to try to set these values, but they won't
do much.

Our current scheduler is a SCOPE_PROCESS, SCHED_FIFO, with only one
priority level: 0.

user/pthread/pthread.c
user/pthread/pthread.h

index af7a5fc..fa26d2f 100644 (file)
@@ -498,8 +498,13 @@ void pthread_need_tls(bool need)
 
 int pthread_attr_init(pthread_attr_t *a)
 {
+       a->stackaddr = 0;
        a->stacksize = PTHREAD_STACK_SIZE;
        a->detachstate = PTHREAD_CREATE_JOINABLE;
+       /* priority and policy should be set by anyone changing inherit. */
+       a->sched_priority = 0;
+       a->sched_policy = 0;
+       a->sched_inherit = PTHREAD_INHERIT_SCHED;
        return 0;
 }
 
@@ -591,6 +596,8 @@ void pthread_lib_init(void)
        __sigemptyset(&t->sigmask);
        __sigemptyset(&t->sigpending);
        assert(t->id == 0);
+       t->sched_policy = SCHED_FIFO;
+       t->sched_priority = 0;
        /* Put the new pthread (thread0) on the active queue */
        mcs_pdr_lock(&queue_lock);
        threads_active++;
@@ -661,6 +668,7 @@ int __pthread_create(pthread_t *thread, const pthread_attr_t *attr,
        struct uth_thread_attr uth_attr = {0};
        run_once(pthread_lib_init());
        /* Create the actual thread */
+       struct pthread_tcb *parent = (struct pthread_tcb*)current_uthread;
        struct pthread_tcb *pthread;
        int ret = posix_memalign((void**)&pthread, __alignof__(struct pthread_tcb),
                                 sizeof(struct pthread_tcb));
@@ -674,12 +682,19 @@ int __pthread_create(pthread_t *thread, const pthread_attr_t *attr,
        pthread->sigmask = ((pthread_t)current_uthread)->sigmask;
        __sigemptyset(&pthread->sigpending);
        pthread->sigdata = NULL;
+       /* Might override these later, based on attr && EXPLICIT_SCHED */
+       pthread->sched_policy = parent->sched_policy;
+       pthread->sched_priority = parent->sched_priority;
        /* Respect the attributes */
        if (attr) {
                if (attr->stacksize)                                    /* don't set a 0 stacksize */
                        pthread->stacksize = attr->stacksize;
                if (attr->detachstate == PTHREAD_CREATE_DETACHED)
                        pthread->detached = TRUE;
+               if (attr->sched_inherit == PTHREAD_EXPLICIT_SCHED) {
+                       pthread->sched_policy = attr->sched_policy;
+                       pthread->sched_priority = attr->sched_priority;
+               }
        }
        /* allocate a stack */
        if (__pthread_allocate_stack(pthread))
@@ -1282,6 +1297,111 @@ int pthread_setspecific(pthread_key_t key, const void *value)
        return 0;
 }
 
+
+/* Scheduling Stuff */
+
+static bool policy_is_supported(int policy)
+{
+       /* As our scheduler changes, we can add more policies here */
+       switch (policy) {
+               case SCHED_FIFO:
+                       return TRUE;
+               default:
+                       return FALSE;
+       }
+}
+
+int pthread_attr_setschedparam(pthread_attr_t *attr,
+                               const struct sched_param *param)
+{
+       /* The set of acceptable priorities are based on the scheduling policy.
+        * We'll just accept any old number, since we might not know the policy
+        * yet.  I didn't see anything in the man pages saying attr had to have a
+        * policy set before setting priority. */
+       attr->sched_priority = param->sched_priority;
+       return 0;
+}
+
+int pthread_attr_getschedparam(pthread_attr_t *attr,
+                               struct sched_param *param)
+{
+       param->sched_priority = attr->sched_priority;
+       return 0;
+}
+
+int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+       if (!policy_is_supported(policy))
+               return -EINVAL;
+       attr->sched_policy = policy;
+       return 0;
+}
+
+int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy)
+{
+       *policy = attr->sched_policy;
+       return 0;
+}
+
+/* We only support SCOPE_PROCESS, so we don't even use the attr. */
+int pthread_attr_setscope(pthread_attr_t *attr, int scope)
+{
+       if (scope != PTHREAD_SCOPE_PROCESS)
+               return -ENOTSUP;
+       return 0;
+}
+
+int pthread_attr_getscope(pthread_attr_t *attr, int *scope)
+{
+       *scope = PTHREAD_SCOPE_PROCESS;
+       return 0;
+}
+
+/* Inheritance refers to policy, priority, scope */
+int pthread_attr_setinheritsched(pthread_attr_t *attr,
+                                 int inheritsched)
+{
+       switch (inheritsched) {
+               case PTHREAD_INHERIT_SCHED:
+               case PTHREAD_EXPLICIT_SCHED:
+                       break;
+               default:
+                       return -EINVAL;
+       }
+       attr->sched_inherit = inheritsched;
+       return 0;
+}
+
+int pthread_attr_getinheritsched(const pthread_attr_t *attr,
+                                 int *inheritsched)
+{
+       *inheritsched = attr->sched_inherit;
+       return 0;
+}
+
+int pthread_setschedparam(pthread_t thread, int policy,
+                           const struct sched_param *param)
+{
+       if (!policy_is_supported(policy))
+               return -EINVAL;
+       thread->sched_policy = policy;
+       /* We actually could check if the priority falls in the range of the
+        * specified policy here, since we have both policy and priority. */
+       thread->sched_priority = param->sched_priority;
+       return 0;
+}
+
+int pthread_getschedparam(pthread_t thread, int *policy,
+                           struct sched_param *param)
+{
+       *policy = thread->sched_policy;
+       param->sched_priority = thread->sched_priority;
+       return 0;
+}
+
+
+/* Unsupported Stuff */
+
 int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex,
                                        const struct timespec *__restrict
                                        __abstime)
@@ -1290,6 +1410,7 @@ int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex,
        abort();
        return -1;
 }
+
 int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,
                                   pthread_mutex_t *__restrict __mutex,
                                   const struct timespec *__restrict __abstime)
index 0f14fb2..10e1137 100644 (file)
@@ -8,6 +8,8 @@
 #include <mcs.h>
 #include <dtls.h>
 #include <spinlock.h>
+/* GNU / POSIX scheduling crap */
+#include <sched.h>
 
 #ifdef __cplusplus
   extern "C" {
@@ -42,6 +44,8 @@ struct pthread_tcb {
        sigset_t sigmask;
        sigset_t sigpending;
        struct sigdata *sigdata;
+       int sched_policy;
+       int sched_priority;             /* careful, GNU #defines this to __sched_priority */
 };
 typedef struct pthread_tcb* pthread_t;
 TAILQ_HEAD(pthread_queue, pthread_tcb);
@@ -103,6 +107,7 @@ enum
 // more space if we go too far.
 #define PTHREAD_STACK_PAGES 4
 #define PTHREAD_STACK_SIZE (PTHREAD_STACK_PAGES*PGSIZE)
+#define PTHREAD_STACK_MIN PTHREAD_STACK_SIZE
 
 typedef int clockid_t;
 typedef struct
@@ -127,6 +132,9 @@ typedef struct
        void *stackaddr;
        size_t stacksize;
        int detachstate;
+       int sched_priority;
+       int sched_policy;
+       int sched_inherit;
 } pthread_attr_t;
 typedef int pthread_barrierattr_t;
 typedef int pthread_once_t;
@@ -215,6 +223,32 @@ int pthread_getattr_np(pthread_t __th, pthread_attr_t *__attr);
 int pthread_attr_getstack(const pthread_attr_t *__attr,
                            void **__stackaddr, size_t *__stacksize);
 
+/* Scheduling Stuff, mostly ignored by the actual 2LS */
+int pthread_attr_setschedparam(pthread_attr_t *attr,
+                               const struct sched_param *param);
+int pthread_attr_getschedparam(pthread_attr_t *attr,
+                               struct sched_param *param);
+/* Policies are from sched.h. */
+int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
+int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy);
+
+#define PTHREAD_SCOPE_SYSTEM   1
+#define PTHREAD_SCOPE_PROCESS  2
+int pthread_attr_setscope(pthread_attr_t *attr, int scope);
+int pthread_attr_getscope(pthread_attr_t *attr, int *scope);
+
+#define PTHREAD_INHERIT_SCHED  1
+#define PTHREAD_EXPLICIT_SCHED 2
+int pthread_attr_setinheritsched(pthread_attr_t *attr,
+                                 int inheritsched);
+int pthread_attr_getinheritsched(const pthread_attr_t *attr,
+                                 int *inheritsched);
+
+int pthread_setschedparam(pthread_t thread, int policy,
+                          const struct sched_param *param);
+int pthread_getschedparam(pthread_t thread, int *policy,
+                          struct sched_param *param);
+
 /* Unsupported Stuff */
 typedef void *upthread_once_t;
 extern int pthread_mutex_timedlock (pthread_mutex_t *__restrict __mutex,