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.
This commit is contained in:
Rich Felker 2012-11-11 15:38:04 -05:00
commit 1e21e78bf7
23 changed files with 159 additions and 13 deletions

View file

@ -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;
}

View 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;
}

View file

@ -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;
}

View file

@ -2,5 +2,6 @@
int pthread_attr_getscope(const pthread_attr_t *restrict a, int *restrict scope)
{
*scope = PTHREAD_SCOPE_SYSTEM;
return 0;
}

View file

@ -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;
}

View 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;
}

View file

@ -0,0 +1,7 @@
#include "pthread_impl.h"
int pthread_attr_setschedpolicy(pthread_attr_t *a, int policy)
{
a->_a_policy = policy;
return 0;
}

View 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;
}
}

View 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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}