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