Module: xenomai-3 Branch: wip/dovetail Commit: 4eee0136b4bcb744b9dfdc195f18dd839b3e2198 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=4eee0136b4bcb744b9dfdc195f18dd839b3e2198
Author: Philippe Gerum <r...@xenomai.org> Date: Fri Mar 18 12:12:50 2016 +0100 cobalt/thread: add schedparam lazy propagation Provide a mechanism for carrying out a lazy propagation of schedparam updates to the regular kernel, so that userland does not have to switch to secondary mode for this. When userland issues sc_cobalt_thread_setschedparam_ex for updating the scheduling parameters of a Xenomai thread, a request for propagating this change to the regular kernel is made pending. Such request will be committed later, either when: - the thread relaxes if it is running in primary mode when the update request is received; - next time the thread calls back into the Cobalt core as a result of receiving a HOME action from a SIGSHADOW notification, which is sent if such thread was relaxed at the time of the update request. As a result, the target thread will have propagated the schedparams update to the regular kernel as soon as it resumes (relaxed) execution in user-space. --- include/cobalt/kernel/thread.h | 8 +++++ include/cobalt/uapi/kernel/thread.h | 1 + include/cobalt/uapi/signal.h | 1 + kernel/cobalt/posix/syscall.c | 9 ++++-- kernel/cobalt/thread.c | 55 +++++++++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+), 2 deletions(-) diff --git a/include/cobalt/kernel/thread.h b/include/cobalt/kernel/thread.h index 07b6996..a4d826e 100644 --- a/include/cobalt/kernel/thread.h +++ b/include/cobalt/kernel/thread.h @@ -567,6 +567,14 @@ int xnthread_set_schedparam(struct xnthread *thread, int xnthread_killall(int grace, int mask); +void __xnthread_propagate_schedparam(struct xnthread *curr); + +static inline void xnthread_propagate_schedparam(struct xnthread *curr) +{ + if (xnthread_test_info(curr, XNSCHEDP)) + __xnthread_propagate_schedparam(curr); +} + extern struct xnthread_personality xenomai_personality; /** @} */ diff --git a/include/cobalt/uapi/kernel/thread.h b/include/cobalt/uapi/kernel/thread.h index 0cfc5c8..8d26f16 100644 --- a/include/cobalt/uapi/kernel/thread.h +++ b/include/cobalt/uapi/kernel/thread.h @@ -71,6 +71,7 @@ #define XNROBBED 0x00000020 /**< Robbed from resource ownership */ #define XNCANCELD 0x00000040 /**< Cancellation request is pending */ #define XNPIALERT 0x00000080 /**< Priority inversion alert (SIGDEBUG sent) */ +#define XNSCHEDP 0x00000100 /**< schedparam propagation is pending */ /* Local information flags (private to current thread) */ diff --git a/include/cobalt/uapi/signal.h b/include/cobalt/uapi/signal.h index b5483d7..8a7ea15 100644 --- a/include/cobalt/uapi/signal.h +++ b/include/cobalt/uapi/signal.h @@ -47,6 +47,7 @@ /* SIGSHADOW action codes. */ #define SIGSHADOW_ACTION_HARDEN 1 #define SIGSHADOW_ACTION_BACKTRACE 2 +#define SIGSHADOW_ACTION_HOME 3 #define SIGSHADOW_BACKTRACE_DEPTH 16 #define SIGDEBUG SIGXCPU diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c index a2e87ab..9893b30 100644 --- a/kernel/cobalt/posix/syscall.c +++ b/kernel/cobalt/posix/syscall.c @@ -717,11 +717,16 @@ restart: goto ret_handled; } switched = 1; - } else + } else { /* - * We want to run the syscall in the Linux domain. + * We want to run the syscall in the current Linux + * domain. This is a slow path, so proceed with any + * pending schedparam update on the fly. */ switched = 0; + if (thread) + xnthread_propagate_schedparam(thread); + } ret = handler(__xn_reg_arglist(regs)); if (ret == -ENOSYS && (sysflags & __xn_exec_adaptive) != 0) { diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c index 0ea746d..cabc6b8 100644 --- a/kernel/cobalt/thread.c +++ b/kernel/cobalt/thread.c @@ -24,6 +24,7 @@ #include <linux/wait.h> #include <linux/signal.h> #include <linux/pid.h> +#include <linux/sched.h> #include <cobalt/kernel/sched.h> #include <cobalt/kernel/timer.h> #include <cobalt/kernel/synch.h> @@ -1974,6 +1975,11 @@ int __xnthread_set_schedparam(struct xnthread *thread, thread->lock_count == 0) xnsched_putback(thread); + xnthread_set_info(thread, XNSCHEDP); + /* Ask the target thread to call back if relaxed. */ + if (xnthread_test_state(thread, XNRELAX)) + xnthread_signal(thread, SIGSHADOW, SIGSHADOW_ACTION_HOME); + return ret; } @@ -2095,6 +2101,40 @@ static void post_wakeup(struct task_struct *p) ipipe_post_work_root(&wakework, work); } +void __xnthread_propagate_schedparam(struct xnthread *curr) +{ + int kpolicy = SCHED_FIFO, kprio = curr->bprio, ret; + struct task_struct *p = current; + struct sched_param param; + spl_t s; + + /* + * Test-set race for XNSCHEDP is ok, the propagation is meant + * to be done asap but not guaranteed to be carried out + * immediately, and the request will remain pending until it + * is eventually handled. We just have to protect against a + * set-clear race. + */ + xnlock_get_irqsave(&nklock, s); + xnthread_clear_info(curr, XNSCHEDP); + xnlock_put_irqrestore(&nklock, s); + + /* + * Map our policies/priorities to the regular kernel's + * (approximated). + */ + if (xnthread_test_state(curr, XNWEAK) && kprio == 0) + kpolicy = SCHED_NORMAL; + else if (kprio >= MAX_USER_RT_PRIO) + kprio = MAX_USER_RT_PRIO - 1; + + if (p->policy != kpolicy || (kprio > 0 && p->rt_priority != kprio)) { + param.sched_priority = kprio; + ret = sched_setscheduler_nocheck(p, kpolicy, ¶m); + XENO_WARN_ON(COBALT, ret != 0); + } +} + /** * @internal * @fn void xnthread_relax(int notify, int reason); @@ -2170,6 +2210,21 @@ void xnthread_relax(int notify, int reason) /* Account for secondary mode switch. */ xnstat_counter_inc(&thread->stat.ssw); + /* + * When relaxing, we check for propagating to the regular + * kernel new Cobalt schedparams that might have been set for + * us while we were running in primary mode. + * + * CAUTION: This obviously won't update the schedparams cached + * by the glibc for the caller in user-space, but this is the + * deal: we don't relax threads which issue + * pthread_setschedparam[_ex]() from primary mode, but then + * only the kernel side (Cobalt and the host kernel) will be + * aware of the change, and glibc might cache obsolete + * information. + */ + xnthread_propagate_schedparam(thread); + if (xnthread_test_state(thread, XNUSER) && notify) { xndebug_notify_relax(thread, reason); if (xnthread_test_state(thread, XNWARN)) { _______________________________________________ Xenomai-git mailing list Xenomai-git@xenomai.org https://xenomai.org/mailman/listinfo/xenomai-git