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

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, &param);
+               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

Reply via email to