Module: xenomai-gch Branch: for-forge Commit: ec7cb152793ac701287295b616129dff67175b5b URL: http://git.xenomai.org/?p=xenomai-gch.git;a=commit;h=ec7cb152793ac701287295b616129dff67175b5b
Author: Gilles Chanteperdrix <[email protected]> Date: Wed Dec 7 21:25:19 2011 +0100 cobalt: move sched system calls to thread.c --- include/cobalt/pthread.h | 16 -- include/cobalt/sched.h | 18 -- kernel/cobalt/Makefile | 1 - kernel/cobalt/sched.c | 515 ------------------------------------- kernel/cobalt/syscall.c | 17 +- kernel/cobalt/thread.c | 633 ++++++++++++++++++++++++++++++++++++---------- kernel/cobalt/thread.h | 66 +++--- 7 files changed, 536 insertions(+), 730 deletions(-) diff --git a/include/cobalt/pthread.h b/include/cobalt/pthread.h index b1bb2e1..3a39fbe 100644 --- a/include/cobalt/pthread.h +++ b/include/cobalt/pthread.h @@ -273,22 +273,6 @@ int pthread_attr_getaffinity_np(const pthread_attr_t *attr, int pthread_attr_setaffinity_np(pthread_attr_t *attr, xnarch_cpumask_t mask); -int pthread_getschedparam(pthread_t tid, - int *pol, - struct sched_param *par); - -int pthread_setschedparam(pthread_t tid, - int pol, - const struct sched_param *par); - -int pthread_getschedparam_ex(pthread_t tid, - int *pol, - struct sched_param_ex *par); - -int pthread_setschedparam_ex(pthread_t tid, - int pol, - const struct sched_param_ex *par); - int pthread_mutexattr_init(pthread_mutexattr_t *attr); int pthread_mutexattr_destroy(pthread_mutexattr_t *attr); diff --git a/include/cobalt/sched.h b/include/cobalt/sched.h index 7a8f7a4..6083fb7 100644 --- a/include/cobalt/sched.h +++ b/include/cobalt/sched.h @@ -35,24 +35,6 @@ #define SCHED_OTHER 0 -struct timespec; - -#ifdef __cplusplus -extern "C" { -#endif - -int sched_yield(void); - -int sched_get_priority_min(int policy); - -int sched_get_priority_max(int policy); - -int sched_rr_get_interval(int pid, struct timespec *interval); - -#ifdef __cplusplus -} -#endif - #else /* !(__KERNEL__ || __XENO_SIM__) */ #include_next <sched.h> diff --git a/kernel/cobalt/Makefile b/kernel/cobalt/Makefile index 5edf552..9eda880 100644 --- a/kernel/cobalt/Makefile +++ b/kernel/cobalt/Makefile @@ -1,7 +1,6 @@ obj-$(CONFIG_XENOMAI) += nucleus/ rtdm/ xeno_cobalt.o xeno_cobalt-y := \ - sched.o \ thread_attr.o \ thread.o \ mutex_attr.o \ diff --git a/kernel/cobalt/sched.c b/kernel/cobalt/sched.c deleted file mode 100644 index d7fcf9e..0000000 --- a/kernel/cobalt/sched.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * Written by Gilles Chanteperdrix <[email protected]>. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -/** - * @ingroup posix_thread - * @defgroup posix_sched Threads scheduling services. - * - * Thread scheduling services. - * - * Xenomai POSIX skin supports the scheduling policies SCHED_FIFO, - * SCHED_RR, SCHED_SPORADIC, SCHED_OTHER and SCHED_COBALT. - * - * The SCHED_OTHER policy is mainly useful for user-space non-realtime - * activities that need to synchronize with real-time activities. - * - * The SCHED_RR round-robin time slice is configured with the @a - * xeno_posix module parameter @a time_slice. - * - * The SCHED_SPORADIC policy provides a mean to schedule aperiodic or - * sporadic threads in periodic-based systems. - * - * The scheduling policy and priority of a thread is set when creating - * a thread, by using thread creation attributes (see - * pthread_attr_setinheritsched(), pthread_attr_setschedpolicy() and - * pthread_attr_setschedparam()), or when the thread is already - * running by using the service pthread_setschedparam(). - * - * @see - * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/xsh_chap02_08.html#tag_02_08_04"> - * Specification.</a> - * - *@{*/ - -#include "thread.h" - -/** - * Get minimum priority of the specified scheduling policy. - * - * This service returns the minimum priority of the scheduling policy @a - * policy. - * - * @param policy scheduling policy, one of SCHED_FIFO, SCHED_RR, - * SCHED_OTHER and SCHED_COBALT. - * - * @retval 0 on success; - * @retval -1 with @a errno set if: - * - EINVAL, @a policy is invalid. - * - * @see - * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/sched_get_priority_min.html"> - * Specification.</a> - * - */ -int sched_get_priority_min(int policy) -{ - switch (policy) { - case SCHED_FIFO: - case SCHED_RR: - case SCHED_SPORADIC: - case SCHED_COBALT: - return COBALT_MIN_PRIORITY; - - case SCHED_OTHER: - return 0; - - default: - thread_set_errno(EINVAL); - return -1; - } -} - -/** - * Get maximum priority of the specified scheduling policy. - * - * This service returns the maximum priority of the scheduling policy @a - * policy. - * - * @param policy scheduling policy, one of SCHED_FIFO, SCHED_COBALT, - * SCHED_RR, or SCHED_OTHER. - * - * @retval 0 on success; - * @retval -1 with @a errno set if: - * - EINVAL, @a policy is invalid. - * - * @see - * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/sched_get_priority_max.html"> - * Specification.</a> - * - */ -int sched_get_priority_max(int policy) -{ - switch (policy) { - case SCHED_FIFO: - case SCHED_RR: - case SCHED_SPORADIC: - return COBALT_MAX_PRIORITY; - - case SCHED_COBALT: - return XNSCHED_RT_MAX_PRIO; - - case SCHED_OTHER: - return 0; - - default: - thread_set_errno(EINVAL); - return -1; - } -} - -/** - * Get the round-robin scheduling time slice. - * - * This service returns the time quantum used by Xenomai POSIX skin SCHED_RR - * scheduling policy. - * - * In kernel-space, this service only works if pid is zero, in user-space, - * round-robin scheduling policy is not supported, and this service not - * implemented. - * - * @param pid must be zero; - * - * @param interval address where the round-robin scheduling time quantum will - * be returned on success. - * - * @retval 0 on success; - * @retval -1 with @a errno set if: - * - ESRCH, @a pid is invalid (not 0). - * - * @see - * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/sched_rr_get_interval.html"> - * Specification.</a> - * - */ -int sched_rr_get_interval(int pid, struct timespec *interval) -{ - /* The only valid pid is 0. */ - if (pid) { - thread_set_errno(ESRCH); - return -1; - } - - ns2ts(interval, cobalt_time_slice); - - return 0; -} - -/** - * Get the scheduling policy and parameters of the specified thread. - * - * This service returns, at the addresses @a pol and @a par, the current - * scheduling policy and scheduling parameters (i.e. priority) of the Xenomai - * POSIX skin thread @a tid. If this service is called from user-space and @a - * tid is not the identifier of a Xenomai POSIX skin thread, this service - * fallback to Linux regular pthread_getschedparam service. - * - * @param tid target thread; - * - * @param pol address where the scheduling policy of @a tid is stored on - * success; - * - * @param par address where the scheduling parameters of @a tid is stored on - * success. - * - * @return 0 on success; - * @return an error number if: - * - ESRCH, @a tid is invalid. - * - * @see - * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_getschedparam.html"> - * Specification.</a> - * - */ -int pthread_getschedparam(pthread_t tid, int *pol, struct sched_param *par) -{ - int prio; - spl_t s; - - xnlock_get_irqsave(&nklock, s); - - if (!cobalt_obj_active(tid, COBALT_THREAD_MAGIC, struct cobalt_thread)) { - xnlock_put_irqrestore(&nklock, s); - return ESRCH; - } - - prio = xnthread_base_priority(&tid->threadbase); - par->sched_priority = prio; - *pol = tid->sched_policy; - - xnlock_put_irqrestore(&nklock, s); - - return 0; -} - -/** - * Get the extended scheduling policy and parameters of the specified - * thread. - * - * This service is an extended version of pthread_getschedparam(), - * that also supports Xenomai-specific or additional POSIX scheduling - * policies, which are not available with the host Linux environment. - * - * Typically, SCHED_SPORADIC parameters can be retrieved from this - * call. - * - * @param tid target thread; - * - * @param pol address where the scheduling policy of @a tid is stored on - * success; - * - * @param par address where the scheduling parameters of @a tid is stored on - * success. - * - * @return 0 on success; - * @return an error number if: - * - ESRCH, @a tid is invalid. - * - * @see - * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_getschedparam.html"> - * Specification.</a> - * - */ -int pthread_getschedparam_ex(pthread_t tid, int *pol, struct sched_param_ex *par) -{ - struct xnsched_class *base_class; - struct xnthread *thread; - int prio; - spl_t s; - - xnlock_get_irqsave(&nklock, s); - - if (!cobalt_obj_active(tid, COBALT_THREAD_MAGIC, struct cobalt_thread)) { - xnlock_put_irqrestore(&nklock, s); - return ESRCH; - } - - thread = &tid->threadbase; - base_class = xnthread_base_class(thread); - prio = xnthread_base_priority(thread); - par->sched_priority = prio; - *pol = tid->sched_policy; - - if (base_class == &xnsched_class_rt) { - if (xnthread_test_state(thread, XNRRB)) - ns2ts(&par->sched_rr_quantum, xnthread_time_slice(thread)); - goto unlock_and_exit; - } - -#ifdef CONFIG_XENO_OPT_SCHED_SPORADIC - if (base_class == &xnsched_class_sporadic) { - par->sched_ss_low_priority = thread->pss->param.low_prio; - ns2ts(&par->sched_ss_repl_period, thread->pss->param.repl_period); - ns2ts(&par->sched_ss_init_budget, thread->pss->param.init_budget); - par->sched_ss_max_repl = thread->pss->param.max_repl; - goto unlock_and_exit; - } -#endif - -unlock_and_exit: - - xnlock_put_irqrestore(&nklock, s); - - return 0; -} - -/** - * Set the scheduling policy and parameters of the specified thread. - * - * This service set the scheduling policy of the Xenomai POSIX skin thread @a - * tid to the value @a pol, and its scheduling parameters (i.e. its priority) - * to the value pointed to by @a par. - * - * When used in user-space, passing the current thread ID as @a tid argument, - * this service turns the current thread into a Xenomai POSIX skin thread. If @a - * tid is neither the identifier of the current thread nor the identifier of a - * Xenomai POSIX skin thread this service falls back to the regular - * pthread_setschedparam() service, hereby causing the current thread to switch - * to secondary mode if it is Xenomai thread. - * - * @param tid target thread; - * - * @param pol scheduling policy, one of SCHED_FIFO, SCHED_COBALT, - * SCHED_RR or SCHED_OTHER; - * - * @param par scheduling parameters address. - * - * @return 0 on success; - * @return an error number if: - * - ESRCH, @a tid is invalid; - * - EINVAL, @a pol or @a par->sched_priority is invalid; - * - EAGAIN, in user-space, insufficient memory exists in the system heap, - * increase CONFIG_XENO_OPT_SYS_HEAPSZ; - * - EFAULT, in user-space, @a par is an invalid address; - * - EPERM, in user-space, the calling process does not have superuser - * permissions. - * - * @see - * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_setschedparam.html"> - * Specification.</a> - * - * @note - * - * When creating or shadowing a Xenomai thread for the first time in - * user-space, Xenomai installs a handler for the SIGWINCH signal. If you had - * installed a handler before that, it will be automatically called by Xenomai - * for SIGWINCH signals that it has not sent. - * - * If, however, you install a signal handler for SIGWINCH after creating - * or shadowing the first Xenomai thread, you have to explicitly call the - * function xeno_sigwinch_handler at the beginning of your signal handler, - * using its return to know if the signal was in fact an internal signal of - * Xenomai (in which case it returns 1), or if you should handle the signal (in - * which case it returns 0). xeno_sigwinch_handler prototype is: - * - * <b>int xeno_sigwinch_handler(int sig, siginfo_t *si, void *ctxt);</b> - * - * Which means that you should register your handler with sigaction, using the - * SA_SIGINFO flag, and pass all the arguments you received to - * xeno_sigwinch_handler. - * - */ -int pthread_setschedparam(pthread_t tid, int pol, const struct sched_param *par) -{ - union xnsched_policy_param param; - struct xnthread *thread; - xnticks_t tslice; - int prio; - spl_t s; - - xnlock_get_irqsave(&nklock, s); - - if (!cobalt_obj_active(tid, COBALT_THREAD_MAGIC, struct cobalt_thread)) { - xnlock_put_irqrestore(&nklock, s); - return ESRCH; - } - - thread = &tid->threadbase; - prio = par->sched_priority; - tslice = XN_INFINITE; - - switch (pol) { - case SCHED_OTHER: - if (prio) - goto fail; - break; - case SCHED_RR: - tslice = xnthread_time_slice(thread); - if (tslice == XN_INFINITE) - tslice = cobalt_time_slice; - /* falldown wanted */ - case SCHED_FIFO: - case SCHED_SPORADIC: - if (prio < COBALT_MIN_PRIORITY || prio > COBALT_MAX_PRIORITY) - goto fail; - break; - case SCHED_COBALT: - if (prio < COBALT_MIN_PRIORITY || prio > XNSCHED_RT_MAX_PRIO) - goto fail; - break; - default: - fail: - xnlock_put_irqrestore(&nklock, s); - return EINVAL; - } - - xnpod_set_thread_tslice(thread, tslice); - - tid->sched_policy = pol; - param.rt.prio = prio; - xnpod_set_thread_schedparam(thread, &xnsched_class_rt, ¶m); - - xnpod_schedule(); - - xnlock_put_irqrestore(&nklock, s); - - return 0; -} - -/** - * Set the extended scheduling policy and parameters of the specified - * thread. - * - * This service is an extended version of pthread_setschedparam(), - * that supports Xenomai-specific or additional scheduling policies, - * which are not available with the host Linux environment. - * - * Typically, a Xenomai thread policy can be set to SCHED_SPORADIC - * using this call. - * - * @param tid target thread; - * - * @param pol address where the scheduling policy of @a tid is stored on - * success; - * - * @param par address where the scheduling parameters of @a tid is stored on - * success. - * - * @return 0 on success; - * @return an error number if: - * - ESRCH, @a tid is invalid. - * - EINVAL, @a par contains invalid parameters. - * - ENOMEM, lack of memory to perform the operation. - * - * @see - * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_getschedparam.html"> - * Specification.</a> - * - */ -int pthread_setschedparam_ex(pthread_t tid, int pol, const struct sched_param_ex *par) -{ - union xnsched_policy_param param; - struct sched_param short_param; - xnticks_t tslice; - int ret = 0; - spl_t s; - - switch (pol) { - case SCHED_OTHER: - case SCHED_FIFO: - case SCHED_COBALT: - xnpod_set_thread_tslice(&tid->threadbase, XN_INFINITE); - short_param.sched_priority = par->sched_priority; - return pthread_setschedparam(tid, pol, &short_param); - default: - if (par->sched_priority < COBALT_MIN_PRIORITY || - par->sched_priority > COBALT_MAX_PRIORITY) { - return EINVAL; - } - } - - xnlock_get_irqsave(&nklock, s); - - if (!cobalt_obj_active(tid, COBALT_THREAD_MAGIC, struct cobalt_thread)) { - xnlock_put_irqrestore(&nklock, s); - return ESRCH; - } - - switch (pol) { - case SCHED_RR: - tslice = ts2ns(&par->sched_rr_quantum); - ret = xnpod_set_thread_tslice(&tid->threadbase, tslice); - break; - default: - - xnlock_put_irqrestore(&nklock, s); - return EINVAL; - -#ifdef CONFIG_XENO_OPT_SCHED_SPORADIC - case SCHED_SPORADIC: - xnpod_set_thread_tslice(&tid->threadbase, XN_INFINITE); - param.pss.normal_prio = par->sched_priority; - param.pss.low_prio = par->sched_ss_low_priority; - param.pss.current_prio = param.pss.normal_prio; - param.pss.init_budget = ts2ns(&par->sched_ss_init_budget); - param.pss.repl_period = ts2ns(&par->sched_ss_repl_period); - param.pss.max_repl = par->sched_ss_max_repl; - ret = xnpod_set_thread_schedparam(&tid->threadbase, - &xnsched_class_sporadic, ¶m); - break; -#else - (void)param; -#endif - } - - tid->sched_policy = pol; - - xnpod_schedule(); - - xnlock_put_irqrestore(&nklock, s); - - return -ret; -} - -/** - * Yield the processor. - * - * This function move the current thread at the end of its priority group. - * - * @retval 0 - * - * @see - * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/sched_yield.html"> - * Specification.</a> - * - */ -int sched_yield(void) -{ - xnpod_yield(); - return 0; -} - -/*@}*/ - -EXPORT_SYMBOL_GPL(sched_get_priority_min); -EXPORT_SYMBOL_GPL(sched_get_priority_max); -EXPORT_SYMBOL_GPL(sched_rr_get_interval); -EXPORT_SYMBOL_GPL(pthread_getschedparam); -EXPORT_SYMBOL_GPL(pthread_getschedparam_ex); -EXPORT_SYMBOL_GPL(pthread_setschedparam); -EXPORT_SYMBOL_GPL(pthread_setschedparam_ex); -EXPORT_SYMBOL_GPL(sched_yield); diff --git a/kernel/cobalt/syscall.c b/kernel/cobalt/syscall.c index 5b5a412..29036a6 100644 --- a/kernel/cobalt/syscall.c +++ b/kernel/cobalt/syscall.c @@ -36,6 +36,7 @@ #include "sem.h" #include "timer.h" #include "monitor.h" +#include "sched.h" #include <rtdm/rtdm_driver.h> #define RTDM_FD_MAX CONFIG_XENO_OPT_RTDM_FILDES @@ -899,18 +900,6 @@ static int __select(int nfds, return err; } -static int __sched_min_prio(int policy) -{ - int ret = sched_get_priority_min(policy); - return ret >= 0 ? ret : -thread_get_errno(); -} - -static int __sched_max_prio(int policy) -{ - int ret = sched_get_priority_max(policy); - return ret >= 0 ? ret : -thread_get_errno(); -} - int __cobalt_call_not_available(void) { return -ENOSYS; @@ -987,8 +976,8 @@ static struct xnsysent __systab[] = { SKINCALL_DEF(sc_cobalt_condattr_getpshared, __pthread_condattr_getpshared, any), SKINCALL_DEF(sc_cobalt_condattr_setpshared, __pthread_condattr_setpshared, any), SKINCALL_DEF(sc_cobalt_select, __select, primary), - SKINCALL_DEF(sc_cobalt_sched_minprio, __sched_min_prio, any), - SKINCALL_DEF(sc_cobalt_sched_maxprio, __sched_max_prio, any), + SKINCALL_DEF(sc_cobalt_sched_minprio, cobalt_sched_min_prio, any), + SKINCALL_DEF(sc_cobalt_sched_maxprio, cobalt_sched_max_prio, any), SKINCALL_DEF(sc_cobalt_monitor_init, cobalt_monitor_init, any), SKINCALL_DEF(sc_cobalt_monitor_destroy, cobalt_monitor_destroy, any), SKINCALL_DEF(sc_cobalt_monitor_enter, cobalt_monitor_enter, primary), diff --git a/kernel/cobalt/thread.c b/kernel/cobalt/thread.c index eb770de..5559ca7 100644 --- a/kernel/cobalt/thread.c +++ b/kernel/cobalt/thread.c @@ -139,7 +139,7 @@ static inline void cobalt_thread_unhash(const struct cobalt_hkey *hkey) xnfree(tidslot); } -static inline pthread_t cobalt_thread_find(const struct cobalt_hkey *hkey) +pthread_t cobalt_thread_find(const struct cobalt_hkey *hkey) { struct cobalt_hash *ptslot; pthread_t k_tid; @@ -194,6 +194,126 @@ static void thread_delete_hook(xnthread_t *xnthread) } /** + * Get the scheduling policy and parameters of the specified thread. + * + * This service returns, at the addresses @a pol and @a par, the current + * scheduling policy and scheduling parameters (i.e. priority) of the Xenomai + * POSIX skin thread @a tid. If this service is called from user-space and @a + * tid is not the identifier of a Xenomai POSIX skin thread, this service + * fallback to Linux regular pthread_getschedparam service. + * + * @param tid target thread; + * + * @param pol address where the scheduling policy of @a tid is stored on + * success; + * + * @param par address where the scheduling parameters of @a tid is stored on + * success. + * + * @return 0 on success; + * @return an error number if: + * - ESRCH, @a tid is invalid. + * + * @see + * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_getschedparam.html"> + * Specification.</a> + * + */ +static inline int +pthread_getschedparam(pthread_t tid, int *pol, struct sched_param *par) +{ + int prio; + spl_t s; + + xnlock_get_irqsave(&nklock, s); + + if (!cobalt_obj_active(tid, COBALT_THREAD_MAGIC, struct cobalt_thread)) { + xnlock_put_irqrestore(&nklock, s); + return ESRCH; + } + + prio = xnthread_base_priority(&tid->threadbase); + par->sched_priority = prio; + *pol = tid->sched_policy; + + xnlock_put_irqrestore(&nklock, s); + + return 0; +} + +/** + * Get the extended scheduling policy and parameters of the specified + * thread. + * + * This service is an extended version of pthread_getschedparam(), + * that also supports Xenomai-specific or additional POSIX scheduling + * policies, which are not available with the host Linux environment. + * + * Typically, SCHED_SPORADIC parameters can be retrieved from this + * call. + * + * @param tid target thread; + * + * @param pol address where the scheduling policy of @a tid is stored on + * success; + * + * @param par address where the scheduling parameters of @a tid is stored on + * success. + * + * @return 0 on success; + * @return an error number if: + * - ESRCH, @a tid is invalid. + * + * @see + * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_getschedparam.html"> + * Specification.</a> + * + */ +static inline int +pthread_getschedparam_ex(pthread_t tid, int *pol, struct sched_param_ex *par) +{ + struct xnsched_class *base_class; + struct xnthread *thread; + int prio; + spl_t s; + + xnlock_get_irqsave(&nklock, s); + + if (!cobalt_obj_active(tid, COBALT_THREAD_MAGIC, struct cobalt_thread)) { + xnlock_put_irqrestore(&nklock, s); + return ESRCH; + } + + thread = &tid->threadbase; + base_class = xnthread_base_class(thread); + prio = xnthread_base_priority(thread); + par->sched_priority = prio; + *pol = tid->sched_policy; + + if (base_class == &xnsched_class_rt) { + if (xnthread_test_state(thread, XNRRB)) + ns2ts(&par->sched_rr_quantum, xnthread_time_slice(thread)); + goto unlock_and_exit; + } + +#ifdef CONFIG_XENO_OPT_SCHED_SPORADIC + if (base_class == &xnsched_class_sporadic) { + par->sched_ss_low_priority = thread->pss->param.low_prio; + ns2ts(&par->sched_ss_repl_period, thread->pss->param.repl_period); + ns2ts(&par->sched_ss_init_budget, thread->pss->param.init_budget); + par->sched_ss_max_repl = thread->pss->param.max_repl; + goto unlock_and_exit; + } +#endif + +unlock_and_exit: + + xnlock_put_irqrestore(&nklock, s); + + return 0; +} + +/** * Create a thread. * * This service create a thread. The created thread may be used with all POSIX @@ -509,116 +629,214 @@ static inline int pthread_set_name_np(pthread_t thread, const char *name) return 0; } -/* - * We want to keep the native pthread_t token unmodified for Xenomai - * mapped threads, and keep it pointing at a genuine NPTL/LinuxThreads - * descriptor, so that portions of the POSIX interface which are not - * overriden by Xenomai fall back to the original Linux services. +/** + * Set the scheduling policy and parameters of the specified thread. * - * If the latter invoke Linux system calls, the associated shadow - * thread will simply switch to secondary exec mode to perform - * them. For this reason, we need an external index to map regular - * pthread_t values to Xenomai's internal thread ids used in - * syscalling the POSIX skin, so that the outer interface can keep on - * using the former transparently. + * This service set the scheduling policy of the Xenomai POSIX skin thread @a + * tid to the value @a pol, and its scheduling parameters (i.e. its priority) + * to the value pointed to by @a par. + * + * When used in user-space, passing the current thread ID as @a tid argument, + * this service turns the current thread into a Xenomai POSIX skin thread. If @a + * tid is neither the identifier of the current thread nor the identifier of a + * Xenomai POSIX skin thread this service falls back to the regular + * pthread_setschedparam() service, hereby causing the current thread to switch + * to secondary mode if it is Xenomai thread. + * + * @param tid target thread; + * + * @param pol scheduling policy, one of SCHED_FIFO, SCHED_COBALT, + * SCHED_RR or SCHED_OTHER; + * + * @param par scheduling parameters address. + * + * @return 0 on success; + * @return an error number if: + * - ESRCH, @a tid is invalid; + * - EINVAL, @a pol or @a par->sched_priority is invalid; + * - EAGAIN, in user-space, insufficient memory exists in the system heap, + * increase CONFIG_XENO_OPT_SYS_HEAPSZ; + * - EFAULT, in user-space, @a par is an invalid address; + * - EPERM, in user-space, the calling process does not have superuser + * permissions. + * + * @see + * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_setschedparam.html"> + * Specification.</a> + * + * @note + * + * When creating or shadowing a Xenomai thread for the first time in + * user-space, Xenomai installs a handler for the SIGWINCH signal. If you had + * installed a handler before that, it will be automatically called by Xenomai + * for SIGWINCH signals that it has not sent. + * + * If, however, you install a signal handler for SIGWINCH after creating + * or shadowing the first Xenomai thread, you have to explicitly call the + * function xeno_sigwinch_handler at the beginning of your signal handler, + * using its return to know if the signal was in fact an internal signal of + * Xenomai (in which case it returns 1), or if you should handle the signal (in + * which case it returns 0). xeno_sigwinch_handler prototype is: + * + * <b>int xeno_sigwinch_handler(int sig, siginfo_t *si, void *ctxt);</b> + * + * Which means that you should register your handler with sigaction, using the + * SA_SIGINFO flag, and pass all the arguments you received to + * xeno_sigwinch_handler. * - * Semaphores and mutexes do not have this constraint, since we fully - * override their respective interfaces with Xenomai-based - * replacements. */ - -int cobalt_thread_create(unsigned long tid, int policy, - struct sched_param_ex __user *u_param, - unsigned long __user *u_mode) +static inline int +pthread_setschedparam(pthread_t tid, int pol, const struct sched_param *par) { - struct task_struct *p = current; - struct sched_param_ex param; - struct cobalt_hkey hkey; - pthread_attr_t attr; - pthread_t k_tid; - pid_t h_tid; - int ret; - - if (__xn_safe_copy_from_user(¶m, u_param, sizeof(param))) - return -EFAULT; - /* - * We have been passed the pthread_t identifier the user-space - * POSIX library has assigned to our caller; we'll index our - * internal pthread_t descriptor in kernel space on it. - */ - hkey.u_tid = tid; - hkey.mm = p->mm; + union xnsched_policy_param param; + struct xnthread *thread; + xnticks_t tslice; + int prio; + spl_t s; - /* - * Build a default thread attribute, then make sure that a few - * critical fields are set in a compatible fashion wrt to the - * calling context. - */ - pthread_attr_init(&attr); - attr.policy = policy; - attr.detachstate = PTHREAD_CREATE_DETACHED; - attr.schedparam_ex = param; - attr.fp = 1; - attr.name = p->comm; + xnlock_get_irqsave(&nklock, s); - ret = pthread_create(&k_tid, &attr); - if (ret) - return ret; + if (!cobalt_obj_active(tid, COBALT_THREAD_MAGIC, struct cobalt_thread)) { + xnlock_put_irqrestore(&nklock, s); + return -ESRCH; + } - h_tid = task_pid_vnr(p); - ret = xnshadow_map(&k_tid->threadbase, NULL, u_mode); - if (ret) - goto fail; + thread = &tid->threadbase; + prio = par->sched_priority; + tslice = XN_INFINITE; - if (!cobalt_thread_hash(&hkey, k_tid, h_tid)) { - ret = -ENOMEM; - goto fail; + switch (pol) { + case SCHED_OTHER: + if (prio) + goto fail; + break; + case SCHED_RR: + tslice = xnthread_time_slice(thread); + if (tslice == XN_INFINITE) + tslice = cobalt_time_slice; + /* falldown wanted */ + case SCHED_FIFO: + case SCHED_SPORADIC: + if (prio < COBALT_MIN_PRIORITY || prio > COBALT_MAX_PRIORITY) + goto fail; + break; + case SCHED_COBALT: + if (prio < COBALT_MIN_PRIORITY || prio > XNSCHED_RT_MAX_PRIO) + goto fail; + break; + default: + fail: + xnlock_put_irqrestore(&nklock, s); + return -EINVAL; } - k_tid->hkey = hkey; + xnpod_set_thread_tslice(thread, tslice); - return 0; + tid->sched_policy = pol; + param.rt.prio = prio; + xnpod_set_thread_schedparam(thread, &xnsched_class_rt, ¶m); -fail: - xnpod_delete_thread(&k_tid->threadbase); + xnpod_schedule(); - return ret; + xnlock_put_irqrestore(&nklock, s); + + return 0; } -pthread_t cobalt_thread_shadow(struct task_struct *p, - struct cobalt_hkey *hkey, - unsigned long __user *u_mode_offset) +/** + * Set the extended scheduling policy and parameters of the specified + * thread. + * + * This service is an extended version of pthread_setschedparam(), + * that supports Xenomai-specific or additional scheduling policies, + * which are not available with the host Linux environment. + * + * Typically, a Xenomai thread policy can be set to SCHED_SPORADIC + * using this call. + * + * @param tid target thread; + * + * @param pol address where the scheduling policy of @a tid is stored on + * success; + * + * @param par address where the scheduling parameters of @a tid is stored on + * success. + * + * @return 0 on success; + * @return an error number if: + * - ESRCH, @a tid is invalid. + * - EINVAL, @a par contains invalid parameters. + * - ENOMEM, lack of memory to perform the operation. + * + * @see + * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_getschedparam.html"> + * Specification.</a> + * + */ +static inline int pthread_setschedparam_ex(pthread_t tid, int pol, + const struct sched_param_ex *par) { - pthread_attr_t attr; - pthread_t k_tid; - pid_t h_tid; - int err; + union xnsched_policy_param param; + struct sched_param short_param; + xnticks_t tslice; + int ret = 0; + spl_t s; - pthread_attr_init(&attr); - attr.detachstate = PTHREAD_CREATE_DETACHED; - attr.name = p->comm; + switch (pol) { + case SCHED_OTHER: + case SCHED_FIFO: + case SCHED_COBALT: + xnpod_set_thread_tslice(&tid->threadbase, XN_INFINITE); + short_param.sched_priority = par->sched_priority; + return pthread_setschedparam(tid, pol, &short_param); + default: + if (par->sched_priority < COBALT_MIN_PRIORITY || + par->sched_priority > COBALT_MAX_PRIORITY) { + return EINVAL; + } + } - err = pthread_create(&k_tid, &attr); + xnlock_get_irqsave(&nklock, s); - if (err) - return ERR_PTR(-err); + if (!cobalt_obj_active(tid, COBALT_THREAD_MAGIC, struct cobalt_thread)) { + xnlock_put_irqrestore(&nklock, s); + return -ESRCH; + } - h_tid = task_pid_vnr(p); - err = xnshadow_map(&k_tid->threadbase, NULL, u_mode_offset); - /* - * From now on, we run in primary mode, so we refrain from - * calling regular kernel services (e.g. like - * task_pid_vnr()). - */ - if (err == 0 && !cobalt_thread_hash(hkey, k_tid, h_tid)) - err = -EAGAIN; + switch (pol) { + case SCHED_RR: + tslice = ts2ns(&par->sched_rr_quantum); + ret = xnpod_set_thread_tslice(&tid->threadbase, tslice); + break; + default: - if (err) - xnpod_delete_thread(&k_tid->threadbase); - else - k_tid->hkey = *hkey; + xnlock_put_irqrestore(&nklock, s); + return -EINVAL; - return err ? ERR_PTR(err) : k_tid; +#ifdef CONFIG_XENO_OPT_SCHED_SPORADIC + case SCHED_SPORADIC: + xnpod_set_thread_tslice(&tid->threadbase, XN_INFINITE); + param.pss.normal_prio = par->sched_priority; + param.pss.low_prio = par->sched_ss_low_priority; + param.pss.current_prio = param.pss.normal_prio; + param.pss.init_budget = ts2ns(&par->sched_ss_init_budget); + param.pss.repl_period = ts2ns(&par->sched_ss_repl_period); + param.pss.max_repl = par->sched_ss_max_repl; + ret = xnpod_set_thread_schedparam(&tid->threadbase, + &xnsched_class_sporadic, ¶m); + break; +#else + (void)param; +#endif + } + + tid->sched_policy = pol; + + xnpod_schedule(); + + xnlock_put_irqrestore(&nklock, s); + + return -ret; } int cobalt_thread_setschedparam(unsigned long tid, @@ -651,7 +869,7 @@ int cobalt_thread_setschedparam(unsigned long tid, promoted = 1; } if (k_tid) - err = -pthread_setschedparam(k_tid, policy, ¶m); + err = pthread_setschedparam(k_tid, policy, ¶m); else /* * target thread is not a real-time thread, and is not current, @@ -693,7 +911,7 @@ int cobalt_thread_setschedparam_ex(unsigned long tid, promoted = 1; } if (k_tid) - err = -pthread_setschedparam_ex(k_tid, policy, ¶m); + err = pthread_setschedparam_ex(k_tid, policy, ¶m); else err = -EPERM; @@ -704,68 +922,117 @@ int cobalt_thread_setschedparam_ex(unsigned long tid, return err; } -int cobalt_thread_getschedparam(unsigned long tid, - int __user *u_policy, - struct sched_param __user *u_param) + +/* + * We want to keep the native pthread_t token unmodified for Xenomai + * mapped threads, and keep it pointing at a genuine NPTL/LinuxThreads + * descriptor, so that portions of the POSIX interface which are not + * overriden by Xenomai fall back to the original Linux services. + * + * If the latter invoke Linux system calls, the associated shadow + * thread will simply switch to secondary exec mode to perform + * them. For this reason, we need an external index to map regular + * pthread_t values to Xenomai's internal thread ids used in + * syscalling the POSIX skin, so that the outer interface can keep on + * using the former transparently. + * + * Semaphores and mutexes do not have this constraint, since we fully + * override their respective interfaces with Xenomai-based + * replacements. + */ + +int cobalt_thread_create(unsigned long tid, int policy, + struct sched_param_ex __user *u_param, + unsigned long __user *u_mode) { - struct sched_param param; + struct task_struct *p = current; + struct sched_param_ex param; struct cobalt_hkey hkey; + pthread_attr_t attr; pthread_t k_tid; - int policy, err; + pid_t h_tid; + int ret; + if (__xn_safe_copy_from_user(¶m, u_param, sizeof(param))) + return -EFAULT; + /* + * We have been passed the pthread_t identifier the user-space + * POSIX library has assigned to our caller; we'll index our + * internal pthread_t descriptor in kernel space on it. + */ hkey.u_tid = tid; - hkey.mm = current->mm; - k_tid = cobalt_thread_find(&hkey); + hkey.mm = p->mm; - if (!k_tid) - return -ESRCH; + /* + * Build a default thread attribute, then make sure that a few + * critical fields are set in a compatible fashion wrt to the + * calling context. + */ + pthread_attr_init(&attr); + attr.policy = policy; + attr.detachstate = PTHREAD_CREATE_DETACHED; + attr.schedparam_ex = param; + attr.fp = 1; + attr.name = p->comm; - err = -pthread_getschedparam(k_tid, &policy, ¶m); - if (err) - return err; + ret = pthread_create(&k_tid, &attr); + if (ret) + return ret; - if (__xn_safe_copy_to_user(u_policy, &policy, sizeof(int))) - return -EFAULT; + h_tid = task_pid_vnr(p); + ret = xnshadow_map(&k_tid->threadbase, NULL, u_mode); + if (ret) + goto fail; - return __xn_safe_copy_to_user(u_param, ¶m, sizeof(param)); + if (!cobalt_thread_hash(&hkey, k_tid, h_tid)) { + ret = -ENOMEM; + goto fail; + } + + k_tid->hkey = hkey; + + return 0; + +fail: + xnpod_delete_thread(&k_tid->threadbase); + + return ret; } -int cobalt_thread_getschedparam_ex(unsigned long tid, - int __user *u_policy, - struct sched_param __user *u_param) +pthread_t cobalt_thread_shadow(struct task_struct *p, + struct cobalt_hkey *hkey, + unsigned long __user *u_mode_offset) { - struct sched_param_ex param; - struct cobalt_hkey hkey; + pthread_attr_t attr; pthread_t k_tid; - int policy, err; + pid_t h_tid; + int err; - hkey.u_tid = tid; - hkey.mm = current->mm; - k_tid = cobalt_thread_find(&hkey); + pthread_attr_init(&attr); + attr.detachstate = PTHREAD_CREATE_DETACHED; + attr.name = p->comm; - if (!k_tid) - return -ESRCH; + err = pthread_create(&k_tid, &attr); - err = -pthread_getschedparam_ex(k_tid, &policy, ¶m); if (err) - return err; - - if (__xn_safe_copy_to_user(u_policy, &policy, sizeof(int))) - return -EFAULT; - - return __xn_safe_copy_to_user(u_param, ¶m, sizeof(param)); -} + return ERR_PTR(-err); -int cobalt_sched_yield(void) -{ - pthread_t thread = thread2pthread(xnshadow_thread(current)); - struct sched_param_ex param; - int policy; + h_tid = task_pid_vnr(p); + err = xnshadow_map(&k_tid->threadbase, NULL, u_mode_offset); + /* + * From now on, we run in primary mode, so we refrain from + * calling regular kernel services (e.g. like + * task_pid_vnr()). + */ + if (err == 0 && !cobalt_thread_hash(hkey, k_tid, h_tid)) + err = -EAGAIN; - pthread_getschedparam_ex(thread, &policy, ¶m); - sched_yield(); + if (err) + xnpod_delete_thread(&k_tid->threadbase); + else + k_tid->hkey = *hkey; - return policy == SCHED_OTHER; + return err ? ERR_PTR(err) : k_tid; } int cobalt_thread_make_periodic_np(unsigned long tid, @@ -968,6 +1235,106 @@ int cobalt_thread_stat(unsigned long tid, return __xn_safe_copy_to_user(u_stat, &stat, sizeof(stat)); } +int cobalt_thread_getschedparam(unsigned long tid, + int __user *u_policy, + struct sched_param __user *u_param) +{ + struct sched_param param; + struct cobalt_hkey hkey; + pthread_t k_tid; + int policy, err; + + hkey.u_tid = tid; + hkey.mm = current->mm; + k_tid = cobalt_thread_find(&hkey); + + if (!k_tid) + return -ESRCH; + + err = pthread_getschedparam(k_tid, &policy, ¶m); + if (err) + return err; + + if (__xn_safe_copy_to_user(u_policy, &policy, sizeof(int))) + return -EFAULT; + + return __xn_safe_copy_to_user(u_param, ¶m, sizeof(param)); +} + +int cobalt_thread_getschedparam_ex(unsigned long tid, + int __user *u_policy, + struct sched_param __user *u_param) +{ + struct sched_param_ex param; + struct cobalt_hkey hkey; + pthread_t k_tid; + int policy, err; + + hkey.u_tid = tid; + hkey.mm = current->mm; + k_tid = cobalt_thread_find(&hkey); + + if (!k_tid) + return -ESRCH; + + err = pthread_getschedparam_ex(k_tid, &policy, ¶m); + if (err) + return err; + + if (__xn_safe_copy_to_user(u_policy, &policy, sizeof(int))) + return -EFAULT; + + return __xn_safe_copy_to_user(u_param, ¶m, sizeof(param)); +} + +int cobalt_sched_min_prio(int policy) +{ + switch (policy) { + case SCHED_FIFO: + case SCHED_RR: + case SCHED_SPORADIC: + case SCHED_COBALT: + return COBALT_MIN_PRIORITY; + + case SCHED_OTHER: + return 0; + + default: + return -EINVAL; + } +} + +int cobalt_sched_max_prio(int policy) +{ + switch (policy) { + case SCHED_FIFO: + case SCHED_RR: + case SCHED_SPORADIC: + return COBALT_MAX_PRIORITY; + + case SCHED_COBALT: + return XNSCHED_RT_MAX_PRIO; + + case SCHED_OTHER: + return 0; + + default: + return -EINVAL; + } +} + +int cobalt_sched_yield(void) +{ + pthread_t thread = thread2pthread(xnshadow_thread(current)); + struct sched_param_ex param; + int policy = SCHED_OTHER; + + pthread_getschedparam_ex(thread, &policy, ¶m); + xnpod_yield(); + + return policy == SCHED_OTHER; +} + void cobalt_threadq_cleanup(cobalt_kqueues_t *q) { xnholder_t *holder; diff --git a/kernel/cobalt/thread.h b/kernel/cobalt/thread.h index 8dfa141..b7752b2 100644 --- a/kernel/cobalt/thread.h +++ b/kernel/cobalt/thread.h @@ -47,15 +47,15 @@ struct cobalt_thread { unsigned magic; xnthread_t threadbase; -#define thread2pthread(taddr) ({ \ - xnthread_t *_taddr = (taddr); \ - (_taddr \ - ? ((xnthread_get_magic(_taddr) == COBALT_SKIN_MAGIC) \ - ? ((pthread_t)(((char *)_taddr)- offsetof(struct cobalt_thread, \ - threadbase))) \ - : NULL) \ - : NULL); \ - }) +#define thread2pthread(taddr) \ + ({ \ + xnthread_t *_taddr = (taddr); \ + (_taddr \ + ? ((xnthread_get_magic(_taddr) == COBALT_SKIN_MAGIC) \ + ? (container_of(_taddr, struct cobalt_thread, threadbase)) \ + : NULL) \ + : NULL); \ + }) xnholder_t link; /* Link in cobalt_threadq */ @@ -65,9 +65,6 @@ struct cobalt_thread { pthread_attr_t attr; /* creation attributes */ - /* errno value for this thread. */ - int err; - /* For timers. */ xnqueue_t timersq; @@ -83,22 +80,22 @@ struct cobalt_thread { #endif }; -#define COBALT_JOINED_DETACHED XNTHREAD_INFO_SPARE0 - #define cobalt_current_thread() thread2pthread(xnpod_current_thread()) -static inline void thread_set_errno (int err) +static inline void thread_set_errno(int err) { *xnthread_get_errno_location(xnpod_current_thread()) = err; } -static inline int thread_get_errno (void) +static inline int thread_get_errno(void) { return *xnthread_get_errno_location(xnpod_current_thread()); } #define thread_name(thread) ((thread)->attr.name) +pthread_t cobalt_thread_find(const struct cobalt_hkey *hkey); + int cobalt_thread_create(unsigned long tid, int policy, struct sched_param_ex __user *u_param, unsigned long __user *u_mode); @@ -107,6 +104,24 @@ pthread_t cobalt_thread_shadow(struct task_struct *p, struct cobalt_hkey *hkey, unsigned long __user *u_mode_offset); +int cobalt_thread_make_periodic_np(unsigned long tid, + clockid_t clk_id, + struct timespec __user *u_startt, + struct timespec __user *u_periodt); + +int cobalt_thread_wait_np(unsigned long __user *u_overruns); + +int cobalt_thread_set_mode_np(int clrmask, int setmask, int __user *u_mode_r); + +int cobalt_thread_set_name_np(unsigned long tid, const char __user *u_name); + +int cobalt_thread_probe_np(pid_t h_tid); + +int cobalt_thread_kill(unsigned long tid, int sig); + +int cobalt_thread_stat(unsigned long tid, + struct cobalt_threadstat __user *u_stat); + int cobalt_thread_setschedparam(unsigned long tid, int policy, struct sched_param __user *u_param, @@ -127,26 +142,11 @@ int cobalt_thread_getschedparam_ex(unsigned long tid, int __user *u_policy, struct sched_param __user *u_param); - int cobalt_sched_yield(void); -int cobalt_thread_make_periodic_np(unsigned long tid, - clockid_t clk_id, - struct timespec __user *u_startt, - struct timespec __user *u_periodt); - -int cobalt_thread_wait_np(unsigned long __user *u_overruns); +int cobalt_sched_min_prio(int policy); -int cobalt_thread_set_mode_np(int clrmask, int setmask, int __user *u_mode_r); - -int cobalt_thread_set_name_np(unsigned long tid, const char __user *u_name); - -int cobalt_thread_probe_np(pid_t h_tid); - -int cobalt_thread_kill(unsigned long tid, int sig); - -int cobalt_thread_stat(unsigned long tid, - struct cobalt_threadstat __user *u_stat); +int cobalt_sched_max_prio(int policy); void cobalt_threadq_cleanup(cobalt_kqueues_t *q); _______________________________________________ Xenomai-git mailing list [email protected] https://mail.gna.org/listinfo/xenomai-git
