mirror of
https://github.com/opnsense/src.git
synced 2026-04-27 17:17:19 -04:00
Use kernel facilities to support real-time scheduling.
This commit is contained in:
parent
444576c0c4
commit
7b4f8f037f
7 changed files with 105 additions and 126 deletions
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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(¶m, 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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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, ¶m)) == 0) {
|
||||
param.sched_priority = prio;
|
||||
ret = _pthread_setschedparam(pthread, policy, ¶m);
|
||||
param.sched_priority = prio;
|
||||
if (pthread == curthread) {
|
||||
THR_LOCK(curthread);
|
||||
ret = sched_setparam((pid_t)curthread->tid, ¶m);
|
||||
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, ¶m);
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue