Module: xenomai-3
Branch: wip/dovetail
Commit: 79c3ba8f3432cf20f40741b2d3ace0a6180f94f8
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=79c3ba8f3432cf20f40741b2d3ace0a6180f94f8

Author: Philippe Gerum <r...@xenomai.org>
Date:   Thu Jul  7 17:05:16 2016 +0200

cobalt/syscalls: allow for handing over mode selection to syscall handlers

Specific system calls may benefit from dealing with the caller's
runtime mode by themselves, depending on internal information which
the generic syscall dispatcher does not have access to.

To this end, a new syscall mode called "handover" is
introduced. Syscalls bearing this mode bit are always entered from the
current calling domain. The syscall handler may return -ENOSYS to
trigger a switch to the converse domain until all domains have been
visited once, at which point the syscall fails with -ENOSYS
automatically.

---

 include/cobalt/uapi/kernel/thread.h |    1 +
 kernel/cobalt/posix/syscall.c       |   63 +++++++++++++++++++++--------------
 2 files changed, 39 insertions(+), 25 deletions(-)

diff --git a/include/cobalt/uapi/kernel/thread.h 
b/include/cobalt/uapi/kernel/thread.h
index 8d26f16..e534471 100644
--- a/include/cobalt/uapi/kernel/thread.h
+++ b/include/cobalt/uapi/kernel/thread.h
@@ -77,6 +77,7 @@
 
 #define XNMOVED   0x00000001 /**< CPU migration in primary mode occurred */
 #define XNLBALERT 0x00000002 /**< Scheduler lock break alert (SIGDEBUG sent) */
+#define XNDESCENT 0x00000004 /**< Adaptive transitioning to secondary mode */
 
 /** @} */
 
diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
index 9893b30..6282cc4 100644
--- a/kernel/cobalt/posix/syscall.c
+++ b/kernel/cobalt/posix/syscall.c
@@ -70,8 +70,10 @@
 #define __xn_exec_downup    (__xn_exec_lostage|__xn_exec_switchback)
 /* Shorthand for non-restartable primary syscall. */
 #define __xn_exec_nonrestartable (__xn_exec_primary|__xn_exec_norestart)
-/* Shorthand for domain probing syscall */
+/* Domain probing syscall starting in conforming mode. */
 #define __xn_exec_probing   (__xn_exec_conforming|__xn_exec_adaptive)
+/* Hand over mode selection to syscall.  */
+#define __xn_exec_handover  (__xn_exec_current|__xn_exec_adaptive)
 
 typedef long (*cobalt_syshand)(unsigned long arg1, unsigned long arg2,
                               unsigned long arg3, unsigned long arg4,
@@ -477,7 +479,7 @@ static inline int allowed_syscall(struct cobalt_process 
*process,
        if (process == NULL)
                return 0;
 
-       if (thread == NULL && (sysflags & __xn_exec_shadow) != 0)
+       if (thread == NULL && (sysflags & __xn_exec_shadow))
                return 0;
 
        return cap_raised(current_cap(), CAP_SYS_NICE);
@@ -550,12 +552,13 @@ static int handle_head_syscall(struct ipipe_domain *ipd, 
struct pt_regs *regs)
         * o Whether the caller currently runs in the Linux or Xenomai
         * domain.
         */
-       switched = 0;
 restart:
        /*
         * Process adaptive syscalls by restarting them in the
-        * opposite domain.
+        * opposite domain upon receiving -ENOSYS from the syscall
+        * handler.
         */
+       switched = 0;
        if (sysflags & __xn_exec_lostage) {
                /*
                 * The syscall must run from the Linux domain.
@@ -589,15 +592,22 @@ restart:
                        return KEVENT_PROPAGATE;
        }
 
+       /*
+        * 'thread' has to be valid from that point: all syscalls
+        * regular threads may call have been pipelined to the root
+        * handler (lostage ones), or rejected by allowed_syscall().
+        */
+
        ret = handler(__xn_reg_arglist(regs));
-       if (ret == -ENOSYS && (sysflags & __xn_exec_adaptive) != 0) {
+       if (ret == -ENOSYS && (sysflags & __xn_exec_adaptive)) {
                if (switched) {
-                       switched = 0;
                        ret = xnthread_harden();
-                       if (ret)
+                       if (ret) {
+                               switched = 0;
                                goto done;
-               }
-
+                       }
+               } else /* Mark the primary -> secondary transition. */
+                       xnthread_set_localinfo(thread, XNDESCENT);
                sysflags ^=
                    (__xn_exec_lostage | __xn_exec_histage |
                     __xn_exec_adaptive);
@@ -620,12 +630,14 @@ done:
                                xnthread_relax(0, 0);
                }
        }
-       if (!sigs && (sysflags & __xn_exec_switchback) != 0 && switched)
-               xnthread_harden(); /* -EPERM will be trapped later if needed. */
+       if (!sigs && (sysflags & __xn_exec_switchback) && switched)
+               /* -EPERM will be trapped later if needed. */
+               xnthread_harden();
 
 ret_handled:
        /* Update the stats and userland-visible state. */
        if (thread) {
+               xnthread_clear_localinfo(thread, XNDESCENT);
                xnstat_counter_inc(&thread->stat.xsc);
                xnthread_sync_window(thread);
        }
@@ -698,18 +710,20 @@ static int handle_root_syscall(struct ipipe_domain *ipd, 
struct pt_regs *regs)
        handler = cobalt_syscalls[code];
        sysflags = cobalt_sysmodes[nr];
 
-       if ((sysflags & __xn_exec_conforming) != 0)
-               sysflags |= (thread ? __xn_exec_histage : __xn_exec_lostage);
+       if (thread && (sysflags & __xn_exec_conforming))
+               sysflags |= __xn_exec_histage;
 restart:
        /*
         * Process adaptive syscalls by restarting them in the
-        * opposite domain.
+        * opposite domain upon receiving -ENOSYS from the syscall
+        * handler.
         */
+       switched = 0;
        if (sysflags & __xn_exec_histage) {
                /*
-                * This request originates from the Linux domain and
-                * must be run into the Xenomai domain: harden the
-                * caller and execute the syscall.
+                * This request originates from the Linux domain but
+                * should run into the Xenomai domain: harden the
+                * caller before invoking the syscall handler.
                 */
                ret = xnthread_harden();
                if (ret) {
@@ -723,21 +737,19 @@ restart:
                 * 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));
-       if (ret == -ENOSYS && (sysflags & __xn_exec_adaptive) != 0) {
+       if (ret == -ENOSYS && (sysflags & __xn_exec_adaptive)) {
+               sysflags ^= __xn_exec_histage;
                if (switched) {
-                       switched = 0;
                        xnthread_relax(1, SIGDEBUG_MIGRATE_SYSCALL);
+                       sysflags &= ~__xn_exec_adaptive;
+                        /* Mark the primary -> secondary transition. */
+                       xnthread_set_localinfo(thread, XNDESCENT);
                }
-
-               sysflags ^=
-                   (__xn_exec_lostage | __xn_exec_histage |
-                    __xn_exec_adaptive);
                goto restart;
        }
 
@@ -758,13 +770,14 @@ restart:
                           thread->res_count == 0)
                        sysflags |= __xn_exec_switchback;
        }
-       if (!sigs && (sysflags & __xn_exec_switchback) != 0
+       if (!sigs && (sysflags & __xn_exec_switchback)
            && (switched || xnsched_primary_p()))
                xnthread_relax(0, 0);
 
 ret_handled:
        /* Update the stats and userland-visible state. */
        if (thread) {
+               xnthread_clear_localinfo(thread, XNDESCENT);
                xnstat_counter_inc(&thread->stat.xsc);
                xnthread_sync_window(thread);
        }


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
https://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to