Use kernel facilities to support real-time scheduling.

This commit is contained in:
David Xu 2006-07-12 06:13:18 +00:00
parent 444576c0c4
commit 7b4f8f037f
7 changed files with 105 additions and 126 deletions

View file

@ -434,9 +434,17 @@ _pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *para
policy = (*attr)->sched_policy;
if (param->sched_priority < _thr_priorities[policy-1].pri_min ||
param->sched_priority > _thr_priorities[policy-1].pri_max)
if (policy == SCHED_FIFO || policy == SCHED_RR) {
if (param->sched_priority < _thr_priorities[policy-1].pri_min ||
param->sched_priority > _thr_priorities[policy-1].pri_max)
return (ENOTSUP);
} else {
/*
* Ignore it for SCHED_OTHER now, patches for glib ports
* are wrongly using M:N thread library's internal macro
* THR_MIN_PRIORITY and THR_MAX_PRIORITY.
*/
}
(*attr)->prio = param->sched_priority;

View file

@ -50,6 +50,7 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
{
struct pthread *curthread, *new_thread;
struct thr_param param;
struct thr_sched_param sched_param;
int ret = 0, locked, create_suspended;
sigset_t set, oset;
@ -105,30 +106,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
new_thread->arg = arg;
new_thread->cancelflags = PTHREAD_CANCEL_ENABLE |
PTHREAD_CANCEL_DEFERRED;
/*
* Check if this thread is to inherit the scheduling
* attributes from its parent:
*/
if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED) {
/*
* Copy the scheduling attributes. Lock the scheduling
* lock to get consistent scheduling parameters.
*/
THR_LOCK(curthread);
new_thread->base_priority = curthread->base_priority;
new_thread->attr.prio = curthread->base_priority;
new_thread->attr.sched_policy = curthread->attr.sched_policy;
THR_UNLOCK(curthread);
} else {
/*
* Use just the thread priority, leaving the
* other scheduling attributes as their
* default values:
*/
new_thread->base_priority = new_thread->attr.prio;
}
new_thread->active_priority = new_thread->base_priority;
/* Initialize the mutex queue: */
TAILQ_INIT(&new_thread->mutexq);
@ -166,6 +143,13 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
param.flags = 0;
if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM)
param.flags |= THR_SYSTEM_SCOPE;
if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED)
param.sched = NULL;
else {
param.sched = &sched_param;
sched_param.policy = new_thread->attr.sched_policy;
sched_param.param.sched_priority = new_thread->attr.prio;
}
/* Schedule the new thread. */
if (create_suspended) {
@ -177,6 +161,15 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
ret = thr_new(&param, sizeof(param));
if (ret != 0) {
ret = errno;
/*
* Translate EPROCLIM into well-known POSIX code EAGAIN.
*/
if (ret == EPROCLIM)
ret = EAGAIN;
}
if (create_suspended)
__sys_sigprocmask(SIG_SETMASK, &oset, NULL);
@ -196,7 +189,6 @@ _pthread_create(pthread_t * thread, const pthread_attr_t * attr,
_thr_ref_delete_unlocked(curthread, new_thread);
THREAD_LIST_UNLOCK(curthread);
(*thread) = 0;
ret = EAGAIN;
} else if (locked) {
_thr_report_creation(curthread, new_thread);
THR_THREAD_UNLOCK(curthread, new_thread);

View file

@ -46,32 +46,47 @@ _pthread_getschedparam(pthread_t pthread, int *policy,
struct sched_param *param)
{
struct pthread *curthread = _get_curthread();
int ret, tmp;
int ret;
if ((param == NULL) || (policy == NULL))
/* Return an invalid argument error: */
ret = EINVAL;
else if (pthread == curthread) {
if (policy == NULL || param == NULL)
return (EINVAL);
if (pthread == curthread) {
/*
* Avoid searching the thread list when it is the current
* thread.
*/
THR_THREAD_LOCK(curthread, curthread);
param->sched_priority = pthread->base_priority;
tmp = pthread->attr.sched_policy;
THR_THREAD_UNLOCK(curthread, curthread);
*policy = tmp;
ret = 0;
THR_LOCK(curthread);
/*
* XXX Here we need two separated syscalls, atomic is only
* guaranteed in thread library, a new syscall is needed.
*/
*policy = sched_getscheduler((pid_t)curthread->tid);
if (*policy == -1)
ret = errno;
else {
ret = sched_getparam((pid_t)curthread->tid, param);
if (ret == -1)
ret = errno;
}
THR_UNLOCK(curthread);
}
/* Find the thread in the list of active threads. */
else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
== 0) {
THR_THREAD_LOCK(curthread, pthread);
param->sched_priority = pthread->base_priority;
tmp = pthread->attr.sched_policy;
*policy = sched_getscheduler((pid_t)pthread->tid);
if (*policy == -1)
ret = errno;
else {
ret = sched_getparam((pid_t)pthread->tid, param);
if (ret == -1)
ret = errno;
}
THR_THREAD_UNLOCK(curthread, pthread);
_thr_ref_delete(curthread, pthread);
*policy = tmp;
}
return (ret);
}

View file

@ -40,6 +40,7 @@
#include <sys/sysctl.h>
#include <sys/ttycom.h>
#include <sys/mman.h>
#include <sys/rtprio.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
@ -67,14 +68,10 @@ int _thread_active_threads = 1;
atfork_head _thr_atfork_list = TAILQ_HEAD_INITIALIZER(_thr_atfork_list);
umtx_t _thr_atfork_lock;
/*
* XXX these values should be updated from kernel at startup,
* but current they are same.
*/
struct pthread_prio _thr_priorities[3] = {
{0, 31, 0}, /* FIF0 */
{-20, 20, 0}, /* OTHER */
{0, 31, 0} /* RR */
{RTP_PRIO_MIN, RTP_PRIO_MAX, 0}, /* FIFO */
{0, 0, 63}, /* OTHER */
{RTP_PRIO_MIN, RTP_PRIO_MAX, 0} /* RR */
};
struct pthread_attr _pthread_attr_default = {
@ -156,8 +153,6 @@ STATIC_LIB_REQUIRE(_sendto);
STATIC_LIB_REQUIRE(_sigaction);
STATIC_LIB_REQUIRE(_sigprocmask);
STATIC_LIB_REQUIRE(_sigsuspend);
STATIC_LIB_REQUIRE(_socket);
STATIC_LIB_REQUIRE(_socketpair);
STATIC_LIB_REQUIRE(_thread_init_hack);
STATIC_LIB_REQUIRE(_wait4);
STATIC_LIB_REQUIRE(_write);
@ -407,11 +402,6 @@ init_main_thread(struct pthread *thread)
thread->cancelflags = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED;
thr_set_name(thread->tid, "initial thread");
/* Default the priority of the initial thread: */
thread->base_priority = THR_DEF_PRIORITY;
thread->active_priority = THR_DEF_PRIORITY;
thread->inherited_priority = 0;
/* Initialize the mutex queue: */
TAILQ_INIT(&thread->mutexq);

View file

@ -262,7 +262,7 @@ struct pthread_attr {
* Define priorities returned by kernel.
*/
#define THR_MIN_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_min)
#define THR_MAX_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_min)
#define THR_MAX_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_max)
#define THR_DEF_PRIORITY (_thr_priorities[SCHED_OTHER-1].pri_default)
#define THR_MIN_RR_PRIORITY (_thr_priorities[SCHED_RR-1].pri_min)
@ -271,7 +271,7 @@ struct pthread_attr {
/* XXX The SCHED_FIFO should have same priority range as SCHED_RR */
#define THR_MIN_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO_1].pri_min)
#define THR_MAX_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO-1].pri_min)
#define THR_MAX_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO-1].pri_max)
#define THR_DEF_FIFO_PRIORITY (_thr_priorities[SCHED_FIFO-1].pri_default)
struct pthread_prio {
@ -413,32 +413,6 @@ struct pthread {
#define TLFLAGS_IN_GCLIST 0x0004 /* thread in gc list */
#define TLFLAGS_DETACHED 0x0008 /* thread is detached */
/*
* Base priority is the user setable and retrievable priority
* of the thread. It is only affected by explicit calls to
* set thread priority and upon thread creation via a thread
* attribute or default priority.
*/
char base_priority;
/*
* Inherited priority is the priority a thread inherits by
* taking a priority inheritence or protection mutex. It
* is not affected by base priority changes. Inherited
* priority defaults to and remains 0 until a mutex is taken
* that is being waited on by any other thread whose priority
* is non-zero.
*/
char inherited_priority;
/*
* Active priority is always the maximum of the threads base
* priority and inherited priority. When there is a change
* in either the base or inherited priority, the active
* priority must be recalculated.
*/
char active_priority;
/* Queue of currently owned simple type mutexes. */
TAILQ_HEAD(, pthread_mutex) mutexq;

View file

@ -43,14 +43,29 @@ __weak_reference(_pthread_setprio, pthread_setprio);
int
_pthread_setprio(pthread_t pthread, int prio)
{
int ret, policy;
struct sched_param param;
struct pthread *curthread = _get_curthread();
struct sched_param param;
int ret;
if ((ret = _pthread_getschedparam(pthread, &policy, &param)) == 0) {
param.sched_priority = prio;
ret = _pthread_setschedparam(pthread, policy, &param);
param.sched_priority = prio;
if (pthread == curthread) {
THR_LOCK(curthread);
ret = sched_setparam((pid_t)curthread->tid, &param);
if (ret == -1)
ret = errno;
else
curthread->attr.prio = prio;
THR_UNLOCK(curthread);
} else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
== 0) {
THR_THREAD_LOCK(curthread, pthread);
ret = sched_setparam((pid_t)pthread->tid, &param);
if (ret == -1)
ret = errno;
else
pthread->attr.prio = prio;
THR_THREAD_UNLOCK(curthread, pthread);
_thr_ref_delete(curthread, pthread);
}
/* Return the error status: */
return (ret);
}

View file

@ -50,45 +50,30 @@ int
_pthread_setschedparam(pthread_t pthread, int policy,
const struct sched_param *param)
{
struct pthread *curthread = _get_curthread();
int ret = 0;
struct pthread *curthread = _get_curthread();
int ret;
if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) {
ret = EINVAL;
} else if (param->sched_priority < _thr_priorities[policy-1].pri_min ||
param->sched_priority > _thr_priorities[policy-1].pri_max) {
ret = ENOTSUP;
} else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
== 0) {
/*
* Lock the threads scheduling queue while we change
* its priority:
*/
THR_THREAD_LOCK(curthread, pthread);
if (pthread->state == PS_DEAD) {
THR_THREAD_UNLOCK(curthread, pthread);
_thr_ref_delete(curthread, pthread);
return (ESRCH);
}
/* Set the scheduling policy: */
pthread->attr.sched_policy = policy;
if (param->sched_priority == pthread->base_priority)
/*
* There is nothing to do; unlock the threads
* scheduling queue.
*/
THR_THREAD_UNLOCK(curthread, pthread);
if (pthread == curthread) {
THR_LOCK(curthread);
ret = sched_setscheduler((pid_t)curthread->tid, policy, param);
if (ret == -1)
ret = errno;
else {
pthread->base_priority = param->sched_priority;
/* Recalculate the active priority: */
pthread->active_priority = MAX(pthread->base_priority,
pthread->inherited_priority);
THR_THREAD_UNLOCK(curthread, pthread);
curthread->attr.sched_policy = policy;
curthread->attr.prio = param->sched_priority;
}
THR_UNLOCK(curthread);
} else if ((ret = _thr_ref_add(curthread, pthread, /*include dead*/0))
== 0) {
THR_THREAD_LOCK(curthread, pthread);
ret = sched_setscheduler((pid_t)pthread->tid, policy, param);
if (ret == -1)
ret = errno;
else {
pthread->attr.sched_policy = policy;
pthread->attr.prio = param->sched_priority;
}
THR_THREAD_UNLOCK(curthread, pthread);
_thr_ref_delete(curthread, pthread);
}
return (ret);