diff options
author | Rich Felker <dalias@aerifal.cx> | 2012-11-11 15:38:04 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2012-11-11 15:38:04 -0500 |
commit | 1e21e78bf7a5c24c217446d8760be7b7188711c2 (patch) | |
tree | 83920f2f5aad8bc090ddb55e57f74e062743e592 | |
parent | e9b885ee550e8a3eabc9d11c469baf1cfaf64f55 (diff) | |
download | musl-1e21e78bf7a5c24c217446d8760be7b7188711c2.tar.gz musl-1e21e78bf7a5c24c217446d8760be7b7188711c2.tar.bz2 musl-1e21e78bf7a5c24c217446d8760be7b7188711c2.tar.xz musl-1e21e78bf7a5c24c217446d8760be7b7188711c2.zip |
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.
23 files changed, 159 insertions, 13 deletions
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 <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; +} 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 <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); } 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 <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); } 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 <sched.h> +#include <errno.h> #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 <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); } 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 <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 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; +} |