add support for thread scheduling (POSIX TPS option)
authorRich Felker <dalias@aerifal.cx>
Sun, 11 Nov 2012 20:38:04 +0000 (15:38 -0500)
committerRich Felker <dalias@aerifal.cx>
Sun, 11 Nov 2012 20:38:04 +0000 (15:38 -0500)
linux's sched_* syscalls actually implement the TPS (thread
scheduling) functionality, not the PS (process scheduling)
functionality which the sched_* functions are supposed to have.
omitting support for the PS option (and having the sched_* interfaces
fail with ENOSYS rather than omitting them, since some broken software
assumes they exist) seems to be the only conforming way to do this on
linux.

23 files changed:
include/pthread.h
include/sched.h
include/spawn.h
src/internal/pthread_impl.h
src/process/posix_spawnattr_sched.c [new file with mode: 0644]
src/sched/sched_get_priority_max.c
src/sched/sched_getparam.c
src/sched/sched_getscheduler.c
src/sched/sched_rr_get_interval.c
src/sched/sched_setparam.c
src/sched/sched_setscheduler.c
src/thread/pthread_attr_getinheritsched.c [new file with mode: 0644]
src/thread/pthread_attr_getschedparam.c
src/thread/pthread_attr_getschedpolicy.c [new file with mode: 0644]
src/thread/pthread_attr_getscope.c
src/thread/pthread_attr_setinheritsched.c [new file with mode: 0644]
src/thread/pthread_attr_setschedparam.c
src/thread/pthread_attr_setschedpolicy.c [new file with mode: 0644]
src/thread/pthread_attr_setscope.c
src/thread/pthread_create.c
src/thread/pthread_getschedparam.c [new file with mode: 0644]
src/thread/pthread_setschedparam.c [new file with mode: 0644]
src/thread/pthread_setschedprio.c [new file with mode: 0644]

index 74d86006a442e1f577358ac390e2ed5cdffbf0f0..660a64d98220481d7ba457926e6d910712198b3a 100644 (file)
@@ -91,6 +91,10 @@ int pthread_setcanceltype(int, int *);
 void pthread_testcancel(void);
 int pthread_cancel(pthread_t);
 
+int pthread_getschedparam(pthread_t, int *__restrict, struct sched_param *__restrict);
+int pthread_setschedparam(pthread_t, int, const struct sched_param *);
+int pthread_setschedprio(pthread_t, int);
+
 int pthread_once(pthread_once_t *, void (*)(void));
 
 int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *__restrict);
index 3df4c7bd4491873a2c63b19c0e8de312f7bced51..994260d097f48f5ac904f109ea869a624c7eef23 100644 (file)
@@ -32,6 +32,9 @@ int     sched_yield(void);
 #define SCHED_OTHER 0
 #define SCHED_FIFO 1
 #define SCHED_RR 2
+#define SCHED_BATCH 3
+#define SCHED_IDLE 5
+#define SCHED_RESET_ON_FORK 0x40000000
 
 #ifdef _GNU_SOURCE
 #define CSIGNAL                0x000000ff
index a28ae69168b4c54d6bc5972988a51347381ca954..92b77f79c47fb5272fa2931ace58bec0162538fe 100644 (file)
@@ -55,6 +55,11 @@ int posix_spawnattr_getsigmask(const posix_spawnattr_t *__restrict, sigset_t *__
 int posix_spawnattr_setsigdefault(posix_spawnattr_t *__restrict, const sigset_t *__restrict);
 int posix_spawnattr_getsigdefault(const posix_spawnattr_t *__restrict, sigset_t *__restrict);
 
+int posix_spawnattr_setschedparam(posix_spawnattr_t *__restrict, const struct sched_param *__restrict);
+int posix_spawnattr_getschedparam(const posix_spawnattr_t *__restrict, struct sched_param *__restrict);
+int posix_spawnattr_setschedpolicy(posix_spawnattr_t *__restrict, int);
+int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *__restrict, int *);
+
 int posix_spawn_file_actions_init(posix_spawn_file_actions_t *);
 int posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *);
 
index 9424a5b7039619d2031f99e2ee815e5055dd9bf0..4215e67ab6237835d512c14d6c639726adab3018 100644 (file)
@@ -40,6 +40,8 @@ struct pthread {
        locale_t locale;
        int killlock[2];
        int exitlock[2];
+       int startlock[2];
+       unsigned long sigmask[__SYSCALL_SSLEN/sizeof(long)];
 };
 
 struct __timer {
@@ -53,6 +55,9 @@ struct __timer {
 #define _a_guardsize __u.__s[1]
 #define _a_stackaddr __u.__s[2]
 #define _a_detach __u.__i[3*__SU+0]
+#define _a_sched __u.__i[3*__SU+1]
+#define _a_policy __u.__i[3*__SU+2]
+#define _a_prio __u.__i[3*__SU+3]
 #define _m_type __u.__i[0]
 #define _m_lock __u.__i[1]
 #define _m_waiters __u.__i[2]
diff --git a/src/process/posix_spawnattr_sched.c b/src/process/posix_spawnattr_sched.c
new file mode 100644 (file)
index 0000000..e2ba0d1
--- /dev/null
@@ -0,0 +1,25 @@
+#include <spawn.h>
+#include <sched.h>
+#include <errno.h>
+
+int posix_spawnattr_getschedparam(const posix_spawnattr_t *restrict attr,
+       struct sched_param *restrict schedparam)
+{
+       return ENOSYS;
+}
+
+int posix_spawnattr_setschedparam(posix_spawnattr_t *restrict attr,
+       const struct sched_param *restrict schedparam)
+{
+       return ENOSYS;
+}
+
+int posix_spawnattr_getschedpolicy(const posix_spawnattr_t *restrict attr, int *policy)
+{
+       return ENOSYS;
+}
+
+int posix_spawnattr_setschedpolicy(posix_spawnattr_t *restrict attr, int policy)
+{
+       return ENOSYS;
+}
index 64cbca93c9def1ca0e71851753cf3b803d5e0b89..30ae5100e1de4e5f863f16c131279851be3fbca5 100644 (file)
@@ -1,11 +1,12 @@
 #include <sched.h>
+#include "syscall.h"
 
 int sched_get_priority_max(int policy)
 {
-       return 0;
+       return syscall(SYS_sched_get_priority_max, policy);
 }
 
 int sched_get_priority_min(int policy)
 {
-       return 0;
+       return syscall(SYS_sched_get_priority_min, policy);
 }
index 65be10750fdd6484dfd8b58a40b51add9d35b37a..76f10e49d987710f8a80133a9110332fbbe2f910 100644 (file)
@@ -1,7 +1,8 @@
 #include <sched.h>
+#include <errno.h>
 #include "syscall.h"
 
 int sched_getparam(pid_t pid, struct sched_param *param)
 {
-       return syscall(SYS_sched_getparam, pid, param);
+       return __syscall_ret(-ENOSYS);
 }
index 4c922f695fd3b2287193edad844cf7fbc2bc1fcc..394e508b467cc5e71c2030b7b2c75b2d3070a4aa 100644 (file)
@@ -1,7 +1,8 @@
 #include <sched.h>
+#include <errno.h>
 #include "syscall.h"
 
 int sched_getscheduler(pid_t pid)
 {
-       return syscall(SYS_sched_getscheduler, pid);
+       return __syscall_ret(-ENOSYS);
 }
index 43bc49044ebb2e36d93ead9efecbdd809c786f58..4b01028f5ddaf102fcc37d39e7a4a915069b72bf 100644 (file)
@@ -5,4 +5,3 @@ int sched_rr_get_interval(pid_t pid, struct timespec *ts)
 {
        return syscall(SYS_sched_rr_get_interval, pid, ts);
 }
-
index 07d61aea98ad8371b64a27b931a37cc1471ed423..18623ee49b15ae91e30fe271466532f45d1b75c8 100644 (file)
@@ -1,8 +1,8 @@
 #include <sched.h>
+#include <errno.h>
 #include "syscall.h"
 
 int sched_setparam(pid_t pid, const struct sched_param *param)
 {
-       static const struct sched_param def;
-       return syscall(SYS_sched_setparam, pid, &def);
+       return __syscall_ret(-ENOSYS);
 }
index 195806606bffc3cc30d0f86aec711fb7b004a83e..4435f2164671fd5bfc5bb0fc135ddbd4aeb157ea 100644 (file)
@@ -1,8 +1,8 @@
 #include <sched.h>
+#include <errno.h>
 #include "syscall.h"
 
 int sched_setscheduler(pid_t pid, int sched, const struct sched_param *param)
 {
-       static const struct sched_param def;
-       return syscall(SYS_sched_setscheduler, pid, 0, &def);
+       return __syscall_ret(-ENOSYS);
 }
diff --git a/src/thread/pthread_attr_getinheritsched.c b/src/thread/pthread_attr_getinheritsched.c
new file mode 100644 (file)
index 0000000..392a5df
--- /dev/null
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_attr_getinheritsched(const pthread_attr_t *a, int *inherit)
+{
+       *inherit = a->_a_sched;
+       return 0;
+}
index 5806bdf19cb0f27c4c9bf5b8fedcb21c8a487132..de5fbfe29e3debc798de791bd05f05ea1174fd85 100644 (file)
@@ -2,6 +2,6 @@
 
 int pthread_attr_getschedparam(const pthread_attr_t *restrict a, struct sched_param *restrict param)
 {
-       param->sched_priority = 0;
+       param->sched_priority = a->_a_prio;
        return 0;
 }
diff --git a/src/thread/pthread_attr_getschedpolicy.c b/src/thread/pthread_attr_getschedpolicy.c
new file mode 100644 (file)
index 0000000..09e893a
--- /dev/null
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_attr_getschedpolicy(const pthread_attr_t *a, int *policy)
+{
+       *policy = a->_a_policy;
+       return 0;
+}
index c0167b6a9036c08f27e388f26ba4696971232ee8..b8dfd123a0097b88f00d1cf057025683538651c8 100644 (file)
@@ -2,5 +2,6 @@
 
 int pthread_attr_getscope(const pthread_attr_t *restrict a, int *restrict scope)
 {
+       *scope = PTHREAD_SCOPE_SYSTEM;
        return 0;
 }
diff --git a/src/thread/pthread_attr_setinheritsched.c b/src/thread/pthread_attr_setinheritsched.c
new file mode 100644 (file)
index 0000000..c91d8f8
--- /dev/null
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+int pthread_attr_setinheritsched(pthread_attr_t *a, int inherit)
+{
+       if (inherit > 1U) return EINVAL;
+       a->_a_sched = inherit;
+       return 0;
+}
index 77ce9c986a90b3eb368bb0e7bfa5992383558db8..d4c1204fdc58b119db212380962eb8f593e5e2e8 100644 (file)
@@ -2,6 +2,6 @@
 
 int pthread_attr_setschedparam(pthread_attr_t *restrict a, const struct sched_param *restrict param)
 {
-       if (param->sched_priority) return ENOTSUP;
+       a->_a_prio = param->sched_priority;
        return 0;
 }
diff --git a/src/thread/pthread_attr_setschedpolicy.c b/src/thread/pthread_attr_setschedpolicy.c
new file mode 100644 (file)
index 0000000..bb71f39
--- /dev/null
@@ -0,0 +1,7 @@
+#include "pthread_impl.h"
+
+int pthread_attr_setschedpolicy(pthread_attr_t *a, int policy)
+{
+       a->_a_policy = policy;
+       return 0;
+}
index d56ee391a1dd77aad23c83805856d3018af957ec..46b520c0412c99a22d5e608ff4074a35301f4122 100644 (file)
@@ -2,6 +2,12 @@
 
 int pthread_attr_setscope(pthread_attr_t *a, int scope)
 {
-       if (scope > 1U) return EINVAL;
-       return 0;
+       switch (scope) {
+       case PTHREAD_SCOPE_SYSTEM:
+               return 0;
+       case PTHREAD_SCOPE_PROCESS:
+               return ENOTSUP;
+       default:
+               return EINVAL;
+       }
 }
index a7aadb518645bb48db767cdff32cb271e097d98d..a65e88e153e90514c6e21e43af1a1f9974d99bbf 100644 (file)
@@ -62,6 +62,15 @@ void __do_cleanup_pop(struct __ptcb *cb)
 static int start(void *p)
 {
        pthread_t self = p;
+       if (self->startlock[0]) {
+               __wait(self->startlock, 0, 1, 1);
+               if (self->startlock[0]) {
+                       self->detached = 2;
+                       pthread_exit(0);
+               }
+               __syscall(SYS_rt_sigprocmask, SIG_SETMASK,
+                       self->sigmask, 0, __SYSCALL_SSLEN);
+       }
        if (self->unblock_cancel)
                __syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
                        SIGPT_SET, 0, __SYSCALL_SSLEN);
@@ -95,6 +104,7 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attr,
        struct pthread *self = pthread_self(), *new;
        unsigned char *map, *stack, *tsd;
        unsigned flags = 0x7d8f00;
+       int do_sched = 0;
 
        if (!self) return ENOSYS;
        if (!libc.threaded) {
@@ -144,6 +154,11 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attr,
                new->detached = 1;
                flags -= 0x200000;
        }
+       if (attr && attr->_a_sched) {
+               do_sched = new->startlock[0] = 1;
+               __syscall(SYS_rt_sigprocmask, SIG_BLOCK,
+                       SIGALL_SET, self->sigmask, __SYSCALL_SSLEN);
+       }
        new->unblock_cancel = self->cancel;
        new->canary = self->canary;
 
@@ -152,11 +167,25 @@ int pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict attr,
 
        __release_ptc();
 
+       if (do_sched) {
+               __syscall(SYS_rt_sigprocmask, SIG_SETMASK,
+                       new->sigmask, 0, __SYSCALL_SSLEN);
+       }
+
        if (ret < 0) {
                a_dec(&libc.threads_minus_1);
                munmap(map, size);
                return EAGAIN;
        }
+
+       if (do_sched) {
+               ret = __syscall(SYS_sched_setscheduler, new->tid,
+                       attr->_a_policy, &attr->_a_prio);
+               a_store(new->startlock, ret<0 ? 2 : 0);
+               __wake(new->startlock, 1, 1);
+               if (ret < 0) return -ret;
+       }
+
        *res = new;
        return 0;
 }
diff --git a/src/thread/pthread_getschedparam.c b/src/thread/pthread_getschedparam.c
new file mode 100644 (file)
index 0000000..7b6a95f
--- /dev/null
@@ -0,0 +1,17 @@
+#include "pthread_impl.h"
+
+int pthread_getschedparam(pthread_t t, int *restrict policy, struct sched_param *restrict param)
+{
+       int r;
+       __lock(t->killlock);
+       if (t->dead) {
+               r = ESRCH;
+       } else {
+               r = -__syscall(SYS_sched_getparam, t->tid, &param);
+               if (!r) {
+                       *policy = __syscall(SYS_sched_getscheduler, t->tid);
+               }
+       }
+       __unlock(t->killlock);
+       return r;
+}
diff --git a/src/thread/pthread_setschedparam.c b/src/thread/pthread_setschedparam.c
new file mode 100644 (file)
index 0000000..8e8b5a1
--- /dev/null
@@ -0,0 +1,10 @@
+#include "pthread_impl.h"
+
+int pthread_setschedparam(pthread_t t, int policy, const struct sched_param *param)
+{
+       int r;
+       __lock(t->killlock);
+       r = t->dead ? ESRCH : -__syscall(SYS_sched_setscheduler, t->tid, policy, &param);
+       __unlock(t->killlock);
+       return r;
+}
diff --git a/src/thread/pthread_setschedprio.c b/src/thread/pthread_setschedprio.c
new file mode 100644 (file)
index 0000000..e0bdc03
--- /dev/null
@@ -0,0 +1,10 @@
+#include "pthread_impl.h"
+
+int pthread_setschedprio(pthread_t t, int prio)
+{
+       int r;
+       __lock(t->killlock);
+       r = t->dead ? ESRCH : -__syscall(SYS_sched_setparam, t->tid, &prio);
+       __unlock(t->killlock);
+       return r;
+}