Module: xenomai-3 Branch: next Commit: 08fde44697b24c0be0c40ea33a6d19d4e6049922 URL: http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=08fde44697b24c0be0c40ea33a6d19d4e6049922
Author: Philippe Gerum <[email protected]> Date: Thu Sep 17 01:30:52 2015 +0200 lib/cobalt: wrap sched_setscheduler(2) --- include/cobalt/sched.h | 12 +++- lib/cobalt/cobalt.wrappers | 1 + lib/cobalt/init.c | 4 +- lib/cobalt/internal.h | 3 + lib/cobalt/sched.c | 157 ++++++++++++++++++++++++++++++++++++++++++++ lib/cobalt/thread.c | 45 ++++++++----- lib/cobalt/wrappers.c | 7 ++ 7 files changed, 206 insertions(+), 23 deletions(-) diff --git a/include/cobalt/sched.h b/include/cobalt/sched.h index d7c72ca..12c33e6 100644 --- a/include/cobalt/sched.h +++ b/include/cobalt/sched.h @@ -25,20 +25,26 @@ #include <cobalt/wrappers.h> #include <cobalt/uapi/sched.h> +#ifdef __cplusplus +extern "C" { +#endif + COBALT_DECL(int, sched_yield(void)); COBALT_DECL(int, sched_get_priority_min(int policy)); COBALT_DECL(int, sched_get_priority_max(int policy)); -#ifdef __cplusplus -extern "C" { -#endif +COBALT_DECL(int, sched_setscheduler(pid_t pid, int policy, + const struct sched_param *param)); int sched_get_priority_min_ex(int policy); int sched_get_priority_max_ex(int policy); +int sched_setscheduler_ex(pid_t pid, int policy, + const struct sched_param_ex *param_ex); + int sched_setconfig_np(int cpu, int policy, const union sched_config *config, size_t len); diff --git a/lib/cobalt/cobalt.wrappers b/lib/cobalt/cobalt.wrappers index 4968340..c8e24cb 100644 --- a/lib/cobalt/cobalt.wrappers +++ b/lib/cobalt/cobalt.wrappers @@ -6,6 +6,7 @@ --wrap sched_yield --wrap sched_get_priority_min --wrap sched_get_priority_max +--wrap sched_setscheduler --wrap pthread_kill --wrap pthread_join --wrap pthread_setname_np diff --git a/lib/cobalt/init.c b/lib/cobalt/init.c index acad534..8a48428 100644 --- a/lib/cobalt/init.c +++ b/lib/cobalt/init.c @@ -199,7 +199,7 @@ int cobalt_init(void) ret = __STD(pthread_getschedparam(ptid, &policy, &parm)); if (ret) { early_warning("pthread_getschedparam failed"); - return ret; + return -ret; } /* @@ -224,7 +224,7 @@ int cobalt_init(void) if (ret) { early_warning("pthread_setschedparam failed (prio=%d)", __cobalt_main_prio); - return ret; + return -ret; } return 0; diff --git a/lib/cobalt/internal.h b/lib/cobalt/internal.h index df7d416..540c286 100644 --- a/lib/cobalt/internal.h +++ b/lib/cobalt/internal.h @@ -55,6 +55,9 @@ void cobalt_default_mutexattr_init(void); void cobalt_default_condattr_init(void); +int cobalt_xlate_schedparam(int policy, + const struct sched_param_ex *param_ex, + struct sched_param *param); int cobalt_init(void); struct cobalt_featinfo; diff --git a/lib/cobalt/sched.c b/lib/cobalt/sched.c index b0be725..d1abed8 100644 --- a/lib/cobalt/sched.c +++ b/lib/cobalt/sched.c @@ -172,6 +172,163 @@ COBALT_IMPL(int, sched_get_priority_max, (int policy)) } /** + * Set the scheduling policy and parameters of the specified process. + * + * This service set the scheduling policy of the Xenomai process + * identified by @a pid to the value @a pol, and its scheduling + * parameters (i.e. its priority) to the value pointed to by @a par. + * + * If the current Linux thread ID is passed (see gettid(2)), this + * service turns the current thread into a Xenomai thread. If @a pid + * is neither the identifier of the current thread nor the identifier + * of an existing Xenomai thread, this service falls back to the + * regular sched_setscheduler() service, causing a transition to + * secondary mode if the caller is a Xenomai thread. + * + * @param pid target process/thread; + * + * @param policy scheduling policy, one of SCHED_FIFO, SCHED_RR, or + * SCHED_OTHER; + * + * @param param scheduling parameters address. + * + * @return 0 on success; + * @return an error number if: + * - ESRCH, @a pid is invalid; + * - EINVAL, @a pol or @a par->sched_priority is invalid; + * - EFAULT, @a par is an invalid address; + * + * @see + * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/sched_setscheduler.html"> + * Specification.</a> + * + * @note + * + * When creating or shadowing a Xenomai thread for the first time, + * libcobalt installs an internal handler for the SIGSHADOW signal. If + * you had previously installed a handler for such signal before that + * point, such handler will be exclusively called for any SIGSHADOW + * occurrence Xenomai did not send. + * + * If, however, an application-defined handler for SIGSHADOW is + * installed afterwards, overriding the libcobalt handler, the new + * handler is required to call cobalt_sigshadow_handler() on + * entry. This routine returns a non-zero value for every occurrence + * of SIGSHADOW issued by the Cobalt core. If zero instead, the + * application-defined handler should process the signal. + * + * <b>int cobalt_sigshadow_handler(int sig, siginfo_t *si, void *ctxt);</b> + * + * You should register your handler with sigaction(2), setting the + * SA_SIGINFO flag. + */ +COBALT_IMPL(int, sched_setscheduler, (pid_t pid, int policy, + const struct sched_param *param)) +{ + int ret; + + struct sched_param_ex param_ex = { + .sched_priority = param->sched_priority, + }; + + ret = sched_setscheduler_ex(pid, policy, ¶m_ex); + if (ret) { + errno = -ret; + return -1; + } + + return 0; +} + +/** + * Set extended scheduling policy of a process + * + * This service is an extended version of the sched_setscheduler() + * service, which supports Xenomai-specific and/or additional + * scheduling policies, not available with the host Linux environment. + * It sets the scheduling policy of the Xenomai process/thread + * identified by @a pid to the value @a pol, and the scheduling + * parameters (e.g. its priority) to the value pointed to by @a par. + * + * If the current Linux thread ID or zero is passed (see gettid(2)), + * this service may turn the current thread into a Xenomai thread. + * + * @param pid target process/thread. If zero, the current thread is + * assumed. + * + * @param policy scheduling policy, one of SCHED_WEAK, SCHED_FIFO, + * SCHED_COBALT, SCHED_RR, SCHED_SPORADIC, SCHED_TP, SCHED_QUOTA or + * SCHED_NORMAL; + * + * @param param_ex scheduling parameters address. As a special + * exception, a negative sched_priority value is interpreted as if + * SCHED_WEAK was given in @a policy, using the absolute value of this + * parameter as the weak priority level. + * + * When CONFIG_XENO_OPT_SCHED_WEAK is enabled, SCHED_WEAK exhibits + * priority levels in the [0..99] range (inclusive). Otherwise, + * sched_priority must be zero for the SCHED_WEAK policy. + * + * @return 0 on success; + * @return an error number if: + * - ESRCH, @a pid is not found; + * - EINVAL, @a pid is negative, @a param_ex is NULL, any of @a policy or + * @a param_ex->sched_priority is invalid; + * - EFAULT, @a param_ex is an invalid address; + * + * @note + * + * When creating or shadowing a Xenomai thread for the first time, + * libcobalt installs an internal handler for the SIGSHADOW signal. If + * you had previously installed a handler for such signal before that + * point, such handler will be exclusively called for any SIGSHADOW + * occurrence Xenomai did not send. + * + * If, however, an application-defined handler for SIGSHADOW is + * installed afterwards, overriding the libcobalt handler, the new + * handler is required to call cobalt_sigshadow_handler() on + * entry. This routine returns a non-zero value for every occurrence + * of SIGSHADOW issued by the Cobalt core. If zero instead, the + * application-defined handler should process the signal. + * + * <b>int cobalt_sigshadow_handler(int sig, siginfo_t *si, void *ctxt);</b> + * + * You should register your handler with sigaction(2), setting the + * SA_SIGINFO flag. + * + * sched_setscheduler_ex() may switch the caller to secondary mode. + */ +int sched_setscheduler_ex(pid_t pid, + int policy, const struct sched_param_ex *param_ex) +{ + int ret, promoted, std_policy; + struct sched_param std_param; + __u32 u_winoff; + + if (pid < 0 || param_ex == NULL) + return EINVAL; + + /* See pthread_setschedparam_ex(). */ + + std_policy = cobalt_xlate_schedparam(policy, param_ex, &std_param); + ret = __STD(sched_setscheduler(pid, std_policy, &std_param)); + if (ret) + return errno; + + ret = -XENOMAI_SYSCALL5(sc_cobalt_sched_setscheduler_ex, + pid, policy, param_ex, + &u_winoff, &promoted); + + if (ret == 0 && promoted) { + cobalt_sigshadow_install_once(); + cobalt_set_tsd(u_winoff); + cobalt_thread_harden(); + } + + return ret; +} + +/** * Get extended maximum priority of the specified scheduling policy. * * This service returns the maximum priority of the scheduling policy diff --git a/lib/cobalt/thread.c b/lib/cobalt/thread.c index 75107ec..8a4307c 100644 --- a/lib/cobalt/thread.c +++ b/lib/cobalt/thread.c @@ -46,22 +46,26 @@ static pthread_attr_ex_t default_attr_ex; static int linuxthreads; -static int std_maxpri; - -static int libc_setschedparam(pthread_t thread, - int policy, const struct sched_param_ex *param_ex) +int cobalt_xlate_schedparam(int policy, + const struct sched_param_ex *param_ex, + struct sched_param *param) { - struct sched_param param; - int priority; + int std_policy, priority, std_maxpri; + /* + * Translates Cobalt scheduling parameters to native ones, + * based on a best approximation for Cobalt policies which are + * not available from the host kernel. + */ + std_policy = policy; priority = param_ex->sched_priority; switch (policy) { case SCHED_WEAK: - policy = priority ? SCHED_FIFO : SCHED_OTHER; + std_policy = priority ? SCHED_FIFO : SCHED_OTHER; break; default: - policy = SCHED_FIFO; + std_policy = SCHED_FIFO; /* falldown wanted. */ case SCHED_OTHER: case SCHED_FIFO: @@ -73,16 +77,18 @@ static int libc_setschedparam(pthread_t thread, * "weak" (negative) priorities - which are only * meaningful for the Cobalt core - to regular values. */ + std_maxpri = __STD(sched_get_priority_max(SCHED_FIFO)); if (priority > std_maxpri) priority = std_maxpri; - else if (priority < 0) - priority = -priority; } - memset(¶m, 0, sizeof(param)); - param.sched_priority = priority; + if (priority < 0) + priority = -priority; + + memset(param, 0, sizeof(*param)); + param->sched_priority = priority; - return __STD(pthread_setschedparam(thread, policy, ¶m)); + return std_policy; } struct pthread_iargs { @@ -102,11 +108,12 @@ static void *cobalt_thread_trampoline(void *p) * Volatile is to prevent (too) smart gcc releases from * trashing the syscall registers (see later comment). */ + int personality, parent_prio, policy, std_policy; volatile pthread_t ptid = pthread_self(); void *(*start)(void *), *arg, *retval; - int personality, parent_prio, policy; struct pthread_iargs *iargs = p; struct sched_param_ex param_ex; + struct sched_param std_param; __u32 u_winoff; long ret; @@ -120,7 +127,8 @@ static void *cobalt_thread_trampoline(void *p) arg = iargs->arg; /* Set our scheduling parameters for the host kernel first. */ - ret = libc_setschedparam(ptid, policy, ¶m_ex); + std_policy = cobalt_xlate_schedparam(policy, ¶m_ex, &std_param); + ret = __STD(pthread_setschedparam(ptid, std_policy, &std_param)); if (ret) goto sync_with_creator; @@ -677,14 +685,16 @@ COBALT_IMPL(int, pthread_setschedparam, (pthread_t thread, int pthread_setschedparam_ex(pthread_t thread, int policy, const struct sched_param_ex *param_ex) { - int ret, promoted; + int ret, promoted, std_policy; + struct sched_param std_param; __u32 u_winoff; /* * First we tell the libc and the regular kernel about the * policy/param change, then we tell Xenomai. */ - ret = libc_setschedparam(thread, policy, param_ex); + std_policy = cobalt_xlate_schedparam(policy, param_ex, &std_param); + ret = __STD(pthread_setschedparam(thread, std_policy, &std_param)); if (ret) return ret; @@ -815,5 +825,4 @@ void cobalt_thread_init(void) linuxthreads = 1; #endif /* !_CS_GNU_LIBPTHREAD_VERSION */ pthread_attr_init_ex(&default_attr_ex); - std_maxpri = __STD(sched_get_priority_max(SCHED_FIFO)); } diff --git a/lib/cobalt/wrappers.c b/lib/cobalt/wrappers.c index 4656e6e..e5c9d2f 100644 --- a/lib/cobalt/wrappers.c +++ b/lib/cobalt/wrappers.c @@ -77,6 +77,13 @@ int __real_sched_get_priority_max(int policy) return sched_get_priority_max(policy); } +__weak +int __real_sched_setscheduler(pid_t pid, int policy, + const struct sched_param *param) +{ + return sched_setscheduler(pid, policy, param); +} + /* pthread */ __weak int __real_pthread_create(pthread_t *ptid_r, _______________________________________________ Xenomai-git mailing list [email protected] http://xenomai.org/mailman/listinfo/xenomai-git
