Module: xenomai-3
Branch: arm64
Commit: 08fde44697b24c0be0c40ea33a6d19d4e6049922
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=08fde44697b24c0be0c40ea33a6d19d4e6049922

Author: Philippe Gerum <r...@xenomai.org>
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, &param_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(&param, 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, &param));
+       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, &param_ex);
+       std_policy = cobalt_xlate_schedparam(policy, &param_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
Xenomai-git@xenomai.org
http://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to