Module: xenomai-jki
Branch: for-forge
Commit: f281400f984b881d15f9ae916d78e0f3641a5c05
URL:    
http://git.xenomai.org/?p=xenomai-jki.git;a=commit;h=f281400f984b881d15f9ae916d78e0f3641a5c05

Author: Jan Kiszka <jan.kis...@siemens.com>
Date:   Fri May 13 20:35:26 2016 +0200

cobalt/kernel: Allow to restart clock_nanosleep and select after signal 
processing

Only if a signal was actually delivered to a thread that was blocked on
sleep, [clock_]nanosleep or select, those calls should return -EINTR.
Otherwise, they should resume with the timeout, accordingly adjusted in
case of relative timeout. So far we returned -EINTR immediately which
particularly disturbed the debugging of applications (SIGSTOP/CONT
terminated those syscalls).

This approach reuses the Linux restart mechanism to find out if those
syscalls should be restarted or actually terminated after the signal
was handled: Linux sets current->restart_block.fn in case a termination
is required, unconditionally, thus also when the syscall did not return
ERESTART_RESTARTBLOCK. We also use the restart_block.nanosleep.expires
to transfer the remaining timeout to the restarted syscall.

We can't use the original restart mechanism of Linux because it directs
all ERESTART_RESTARTBLOCK through a special, Linux-only syscall. In our
case, we would have to migrate the caller in that context to primary in
order to resume the sleep, but this is not possible under Xenomai (we
need to migration from within the syscall hooks).

Signed-off-by: Jan Kiszka <jan.kis...@siemens.com>

---

 include/cobalt/uapi/kernel/thread.h                |    1 +
 .../include/asm-generic/xenomai/ancillaries.h      |   27 +++++++++++++
 .../cobalt/include/asm-generic/xenomai/wrappers.h  |    4 ++
 kernel/cobalt/posix/clock.c                        |   36 ++++++++++++++++--
 kernel/cobalt/posix/internal.h                     |    2 +
 kernel/cobalt/posix/io.c                           |   40 ++++++++++++++++----
 kernel/cobalt/posix/syscall.c                      |    5 +++
 7 files changed, 105 insertions(+), 10 deletions(-)

diff --git a/include/cobalt/uapi/kernel/thread.h 
b/include/cobalt/uapi/kernel/thread.h
index e534471..6f30fcd 100644
--- a/include/cobalt/uapi/kernel/thread.h
+++ b/include/cobalt/uapi/kernel/thread.h
@@ -78,6 +78,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 */
+#define XNSYSRST  0x00000008 /**< Thread awaiting syscall restart after signal 
*/
 
 /** @} */
 
diff --git a/kernel/cobalt/include/asm-generic/xenomai/ancillaries.h 
b/kernel/cobalt/include/asm-generic/xenomai/ancillaries.h
new file mode 100644
index 0000000..690ae05
--- /dev/null
+++ b/kernel/cobalt/include/asm-generic/xenomai/ancillaries.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) Siemens AG, 2016.
+ *
+ * Xenomai is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * Xenomai is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Xenomai; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+#ifndef _COBALT_ASM_GENERIC_ANCILLARIES_H
+
+#include <asm/xenomai/wrappers.h>
+
+#ifndef cobalt_get_restart_block
+#define cobalt_get_restart_block(p)    (&(p)->restart_block)
+#endif
+
+#endif /* !_COBALT_ASM_GENERIC_ANCILLARIES_H */
diff --git a/kernel/cobalt/include/asm-generic/xenomai/wrappers.h 
b/kernel/cobalt/include/asm-generic/xenomai/wrappers.h
index 060ce85..3860f71 100644
--- a/kernel/cobalt/include/asm-generic/xenomai/wrappers.h
+++ b/kernel/cobalt/include/asm-generic/xenomai/wrappers.h
@@ -133,4 +133,8 @@ devm_hwmon_device_register_with_groups(struct device *dev, 
const char *name,
 #error "Xenomai/cobalt requires Linux kernel 3.10 or above"
 #endif /* < 3.10 */
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,0,0)
+#define cobalt_get_restart_block(p)    (&task_thread_info(p)->restart_block)
+#endif
+
 #endif /* _COBALT_ASM_GENERIC_WRAPPERS_H */
diff --git a/kernel/cobalt/posix/clock.c b/kernel/cobalt/posix/clock.c
index b51cb4c..654247d 100644
--- a/kernel/cobalt/posix/clock.c
+++ b/kernel/cobalt/posix/clock.c
@@ -20,6 +20,7 @@
 #include <linux/bitmap.h>
 #include <cobalt/kernel/vdso.h>
 #include <cobalt/kernel/clock.h>
+#include <asm-generic/xenomai/ancillaries.h>
 #include "internal.h"
 #include "thread.h"
 #include "clock.h"
@@ -236,8 +237,9 @@ int __cobalt_clock_nanosleep(clockid_t clock_id, int flags,
                             const struct timespec *rqt,
                             struct timespec *rmt)
 {
+       struct restart_block *restart;
        struct xnthread *cur;
-       xnsticks_t rem;
+       xnsticks_t timeout, rem;
        int ret = 0;
        spl_t s;
 
@@ -259,12 +261,40 @@ int __cobalt_clock_nanosleep(clockid_t clock_id, int 
flags,
 
        cur = xnthread_current();
 
+       if (xnthread_test_localinfo(cur, XNSYSRST)) {
+               xnthread_clear_localinfo(cur, XNSYSRST);
+
+               restart = cobalt_get_restart_block(current);
+
+               if (restart->fn != cobalt_restart_syscall_placeholder) {
+                       if (rmt)
+                               ns2ts(rmt, rem > 1 ? rem : 0);
+                       return -EINTR;
+               }
+
+               timeout = restart->nanosleep.expires;
+       } else
+               timeout = ts2ns(rqt);
+
        xnlock_get_irqsave(&nklock, s);
 
-       xnthread_suspend(cur, XNDELAY, ts2ns(rqt) + 1,
+       xnthread_suspend(cur, XNDELAY, timeout + 1,
                         clock_flag(flags, clock_id), NULL);
 
        if (xnthread_test_info(cur, XNBREAK)) {
+               if (signal_pending(current)) {
+                       restart = cobalt_get_restart_block(current);
+                       restart->nanosleep.expires =
+                               (flags & TIMER_ABSTIME) ? timeout :
+                                   xntimer_get_timeout_stopped(&cur->rtimer);
+                       xnlock_put_irqrestore(&nklock, s);
+                       restart->fn = cobalt_restart_syscall_placeholder;
+
+                       xnthread_set_localinfo(cur, XNSYSRST);
+
+                       return -ERESTARTSYS;
+               }
+
                if (flags == 0 && rmt) {
                        rem = xntimer_get_timeout_stopped(&cur->rtimer);
                        xnlock_put_irqrestore(&nklock, s);
@@ -280,7 +310,7 @@ int __cobalt_clock_nanosleep(clockid_t clock_id, int flags,
        return ret;
 }
 
-COBALT_SYSCALL(clock_nanosleep, nonrestartable,
+COBALT_SYSCALL(clock_nanosleep, primary,
               (clockid_t clock_id, int flags,
                const struct timespec __user *u_rqt,
                struct timespec __user *u_rmt))
diff --git a/kernel/cobalt/posix/internal.h b/kernel/cobalt/posix/internal.h
index ba33ebe..15dfc34 100644
--- a/kernel/cobalt/posix/internal.h
+++ b/kernel/cobalt/posix/internal.h
@@ -55,4 +55,6 @@ static inline xnhandle_t 
cobalt_get_handle_from_user(xnhandle_t *u_h)
 
 int cobalt_init(void);
 
+long cobalt_restart_syscall_placeholder(struct restart_block *param);
+
 #endif /* !_COBALT_POSIX_INTERNAL_H */
diff --git a/kernel/cobalt/posix/io.c b/kernel/cobalt/posix/io.c
index 42b7b00..26318e0 100644
--- a/kernel/cobalt/posix/io.c
+++ b/kernel/cobalt/posix/io.c
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <cobalt/kernel/ppd.h>
 #include <xenomai/rtdm/internal.h>
+#include <asm-generic/xenomai/ancillaries.h>
 #include "process.h"
 #include "internal.h"
 #include "clock.h"
@@ -170,7 +171,7 @@ int __cobalt_select_bind_all(struct xnselector *selector,
 }
 
 /* int select(int, fd_set *, fd_set *, fd_set *, struct timeval *) */
-COBALT_SYSCALL(select, nonrestartable,
+COBALT_SYSCALL(select, primary,
               (int nfds,
                fd_set __user *u_rfds,
                fd_set __user *u_wfds,
@@ -187,6 +188,7 @@ COBALT_SYSCALL(select, nonrestartable,
        fd_set in_fds_storage[XNSELECT_MAX_TYPES],
                out_fds_storage[XNSELECT_MAX_TYPES];
        xnticks_t timeout = XN_INFINITE;
+       struct restart_block *restart;
        xntmode_t mode = XN_RELATIVE;
        struct xnselector *selector;
        struct xnthread *curr;
@@ -197,14 +199,27 @@ COBALT_SYSCALL(select, nonrestartable,
        curr = xnthread_current();
 
        if (u_tv) {
-               if (!access_wok(u_tv, sizeof(tv))
-                   || cobalt_copy_from_user(&tv, u_tv, sizeof(tv)))
-                       return -EFAULT;
+               if (xnthread_test_localinfo(curr, XNSYSRST)) {
+                       xnthread_clear_localinfo(curr, XNSYSRST);
+
+                       restart = cobalt_get_restart_block(current);
+                       timeout = restart->nanosleep.expires;
+
+                       if (restart->fn != cobalt_restart_syscall_placeholder) {
+                               err = -EINTR;
+                               goto out;
+                       }
+               } else {
+                       if (!access_wok(u_tv, sizeof(tv))
+                           || cobalt_copy_from_user(&tv, u_tv, sizeof(tv)))
+                               return -EFAULT;
 
-               if (tv.tv_usec > 1000000)
-                       return -EINVAL;
+                       if (tv.tv_usec > 1000000)
+                               return -EINVAL;
+
+                       timeout = clock_get_ticks(CLOCK_MONOTONIC) + tv2ns(&tv);
+               }
 
-               timeout = clock_get_ticks(CLOCK_MONOTONIC) + tv2ns(&tv);
                mode = XN_ABSOLUTE;
        }
 
@@ -253,6 +268,17 @@ COBALT_SYSCALL(select, nonrestartable,
                }
        } while (err == -ECHRNG);
 
+       if (err == -EINTR && signal_pending(current)) {
+               xnthread_set_localinfo(curr, XNSYSRST);
+
+               restart = cobalt_get_restart_block(current);
+               restart->fn = cobalt_restart_syscall_placeholder;
+               restart->nanosleep.expires = timeout;
+
+               return -ERESTARTSYS;
+       }
+
+out:
        if (u_tv && (err > 0 || err == -EINTR)) {
                xnsticks_t diff = timeout - clock_get_ticks(CLOCK_MONOTONIC);
                if (diff > 0)
diff --git a/kernel/cobalt/posix/syscall.c b/kernel/cobalt/posix/syscall.c
index 6282cc4..25d21ea 100644
--- a/kernel/cobalt/posix/syscall.c
+++ b/kernel/cobalt/posix/syscall.c
@@ -804,3 +804,8 @@ int ipipe_fastcall_hook(struct pt_regs *regs)
 
        return ret;
 }
+
+long cobalt_restart_syscall_placeholder(struct restart_block *param)
+{
+       return -EINVAL;
+}


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

Reply via email to