Module: xenomai-3 Branch: next Commit: c9b0c028d3f72dd0049d27c33e7d196cdc9d5e1e URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=c9b0c028d3f72dd0049d27c33e7d196cdc9d5e1e
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, 74 insertions(+) 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 bd5e34a..e534471 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 3addd62..b9efa05 100644 --- a/kernel/cobalt/posix/syscall.c +++ b/kernel/cobalt/posix/syscall.c @@ -731,6 +731,15 @@ restart: goto ret_handled; } switched = 1; + } else { + /* + * 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)); diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c index d00714c..7db3c1b 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> @@ -1961,6 +1962,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; } @@ -2082,6 +2088,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); @@ -2157,6 +2197,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