From 1e21e78bf7a5c24c217446d8760be7b7188711c2 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Sun, 11 Nov 2012 15:38:04 -0500 Subject: [PATCH] add support for thread scheduling (POSIX TPS option) 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. --- include/pthread.h | 4 ++++ include/sched.h | 3 +++ include/spawn.h | 5 ++++ src/internal/pthread_impl.h | 5 ++++ src/process/posix_spawnattr_sched.c | 25 +++++++++++++++++++ src/sched/sched_get_priority_max.c | 5 ++-- src/sched/sched_getparam.c | 3 ++- src/sched/sched_getscheduler.c | 3 ++- src/sched/sched_rr_get_interval.c | 1 - src/sched/sched_setparam.c | 4 ++-- src/sched/sched_setscheduler.c | 4 ++-- src/thread/pthread_attr_getinheritsched.c | 7 ++++++ src/thread/pthread_attr_getschedparam.c | 2 +- src/thread/pthread_attr_getschedpolicy.c | 7 ++++++ src/thread/pthread_attr_getscope.c | 1 + src/thread/pthread_attr_setinheritsched.c | 8 +++++++ src/thread/pthread_attr_setschedparam.c | 2 +- src/thread/pthread_attr_setschedpolicy.c | 7 ++++++ src/thread/pthread_attr_setscope.c | 10 ++++++-- src/thread/pthread_create.c | 29 +++++++++++++++++++++++ src/thread/pthread_getschedparam.c | 17 +++++++++++++ src/thread/pthread_setschedparam.c | 10 ++++++++ src/thread/pthread_setschedprio.c | 10 ++++++++ 23 files changed, 159 insertions(+), 13 deletions(-) create mode 100644 src/process/posix_spawnattr_sched.c create mode 100644 src/thread/pthread_attr_getinheritsched.c create mode 100644 src/thread/pthread_attr_getschedpolicy.c create mode 100644 src/thread/pthread_attr_setinheritsched.c create mode 100644 src/thread/pthread_attr_setschedpolicy.c create mode 100644 src/thread/pthread_getschedparam.c create mode 100644 src/thread/pthread_setschedparam.c create mode 100644 src/thread/pthread_setschedprio.c diff --git a/include/pthread.h b/include/pthread.h index 74d86006..660a64d9 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -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); diff --git a/include/sched.h b/include/sched.h index 3df4c7bd..994260d0 100644 --- a/include/sched.h +++ b/include/sched.h @@ -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 diff --git a/include/spawn.h b/include/spawn.h index a28ae691..92b77f79 100644 --- a/include/spawn.h +++ b/include/spawn.h @@ -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 *); diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h index 9424a5b7..4215e67a 100644 --- a/src/internal/pthread_impl.h +++ b/src/internal/pthread_impl.h @@ -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 index 00000000..e2ba0d19 --- /dev/null +++ b/src/process/posix_spawnattr_sched.c @@ -0,0 +1,25 @@ +#include +#include +#include + +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; +} diff --git a/src/sched/sched_get_priority_max.c b/src/sched/sched_get_priority_max.c index 64cbca93..30ae5100 100644 --- a/src/sched/sched_get_priority_max.c +++ b/src/sched/sched_get_priority_max.c @@ -1,11 +1,12 @@ #include +#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); } diff --git a/src/sched/sched_getparam.c b/src/sched/sched_getparam.c index 65be1075..76f10e49 100644 --- a/src/sched/sched_getparam.c +++ b/src/sched/sched_getparam.c @@ -1,7 +1,8 @@ #include +#include #include "syscall.h" int sched_getparam(pid_t pid, struct sched_param *param) { - return syscall(SYS_sched_getparam, pid, param); + return __syscall_ret(-ENOSYS); } diff --git a/src/sched/sched_getscheduler.c b/src/sched/sched_getscheduler.c index 4c922f69..394e508b 100644 --- a/src/sched/sched_getscheduler.c +++ b/src/sched/sched_getscheduler.c @@ -1,7 +1,8 @@ #include +#include #include "syscall.h" int sched_getscheduler(pid_t pid) { - return syscall(SYS_sched_getscheduler, pid); + return __syscall_ret(-ENOSYS); } diff --git a/src/sched/sched_rr_get_interval.c b/src/sched/sched_rr_get_interval.c index 43bc4904..4b01028f 100644 --- a/src/sched/sched_rr_get_interval.c +++ b/src/sched/sched_rr_get_interval.c @@ -5,4 +5,3 @@ int sched_rr_get_interval(pid_t pid, struct timespec *ts) { return syscall(SYS_sched_rr_get_interval, pid, ts); } - diff --git a/src/sched/sched_setparam.c b/src/sched/sched_setparam.c index 07d61aea..18623ee4 100644 --- a/src/sched/sched_setparam.c +++ b/src/sched/sched_setparam.c @@ -1,8 +1,8 @@ #include +#include #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); } diff --git a/src/sched/sched_setscheduler.c b/src/sched/sched_setscheduler.c index 19580660..4435f216 100644 --- a/src/sched/sched_setscheduler.c +++ b/src/sched/sched_setscheduler.c @@ -1,8 +1,8 @@ #include +#include #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 index 00000000..392a5df8 --- /dev/null +++ b/src/thread/pthread_attr_getinheritsched.c @@ -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; +} diff --git a/src/thread/pthread_attr_getschedparam.c b/src/thread/pthread_attr_getschedparam.c index 5806bdf1..de5fbfe2 100644 --- a/src/thread/pthread_attr_getschedparam.c +++ b/src/thread/pthread_attr_getschedparam.c @@ -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 index 00000000..09e893a3 --- /dev/null +++ b/src/thread/pthread_attr_getschedpolicy.c @@ -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; +} diff --git a/src/thread/pthread_attr_getscope.c b/src/thread/pthread_attr_getscope.c index c0167b6a..b8dfd123 100644 --- a/src/thread/pthread_attr_getscope.c +++ b/src/thread/pthread_attr_getscope.c @@ -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 index 00000000..c91d8f83 --- /dev/null +++ b/src/thread/pthread_attr_setinheritsched.c @@ -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; +} diff --git a/src/thread/pthread_attr_setschedparam.c b/src/thread/pthread_attr_setschedparam.c index 77ce9c98..d4c1204f 100644 --- a/src/thread/pthread_attr_setschedparam.c +++ b/src/thread/pthread_attr_setschedparam.c @@ -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 index 00000000..bb71f393 --- /dev/null +++ b/src/thread/pthread_attr_setschedpolicy.c @@ -0,0 +1,7 @@ +#include "pthread_impl.h" + +int pthread_attr_setschedpolicy(pthread_attr_t *a, int policy) +{ + a->_a_policy = policy; + return 0; +} diff --git a/src/thread/pthread_attr_setscope.c b/src/thread/pthread_attr_setscope.c index d56ee391..46b520c0 100644 --- a/src/thread/pthread_attr_setscope.c +++ b/src/thread/pthread_attr_setscope.c @@ -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; + } } diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index a7aadb51..a65e88e1 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -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 index 00000000..7b6a95f1 --- /dev/null +++ b/src/thread/pthread_getschedparam.c @@ -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, ¶m); + 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 index 00000000..8e8b5a19 --- /dev/null +++ b/src/thread/pthread_setschedparam.c @@ -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, ¶m); + __unlock(t->killlock); + return r; +} diff --git a/src/thread/pthread_setschedprio.c b/src/thread/pthread_setschedprio.c new file mode 100644 index 00000000..e0bdc03b --- /dev/null +++ b/src/thread/pthread_setschedprio.c @@ -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; +} -- 2.25.1