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

Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>
Date:   Fri Dec 27 12:25:40 2013 +0100

cobalt/timerfd: implement a timerfd_settime TFD_UNBLOCK_ME flag

allowing to use timerfds as a general timeout mechanism

---

 include/cobalt/sys/timerfd.h           |    3 +-
 include/cobalt/uapi/time.h             |    8 ++++
 kernel/cobalt/posix/timerfd.c          |   32 +++++++++++++--
 testsuite/regression/posix/Makefile.am |    2 +-
 testsuite/regression/posix/timerfd.c   |   69 ++++++++++++++++++++++++++++++++
 5 files changed, 108 insertions(+), 6 deletions(-)

diff --git a/include/cobalt/sys/timerfd.h b/include/cobalt/sys/timerfd.h
index 82f08bb..a7df836 100644
--- a/include/cobalt/sys/timerfd.h
+++ b/include/cobalt/sys/timerfd.h
@@ -21,6 +21,7 @@
 #pragma GCC system_header
 #include_next <sys/timerfd.h>
 #include <cobalt/wrappers.h>
+#include <cobalt/uapi/time.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -38,4 +39,4 @@ COBALT_DECL(int, timerfd_gettime(int fd, struct itimerspec 
*curr_value));
 }
 #endif /* __cplusplus */
 
-#endif /* TIMERFD_H */
+#endif /* _COBALT_SYS_TIMERFD_H */
diff --git a/include/cobalt/uapi/time.h b/include/cobalt/uapi/time.h
index 349d659..9c9a803 100644
--- a/include/cobalt/uapi/time.h
+++ b/include/cobalt/uapi/time.h
@@ -39,4 +39,12 @@
 
 #define CLOCK_HOST_REALTIME  __COBALT_CLOCK_CODE(42)
 
+/*
+ * Additional timerfd defines
+ *
+ * when passing TFD_UNBLOCK_ME to timer_settime, any timer expiration
+ * unblocks the thread having issued timer_settime.
+ */
+#define TFD_UNBLOCK_ME (1 << 2)
+
 #endif /* !_COBALT_UAPI_TIME_H */
diff --git a/kernel/cobalt/posix/timerfd.c b/kernel/cobalt/posix/timerfd.c
index 292666c..290443c 100644
--- a/kernel/cobalt/posix/timerfd.c
+++ b/kernel/cobalt/posix/timerfd.c
@@ -33,10 +33,13 @@ struct cobalt_tfd {
        DECLARE_XNSELECT(read_select);
        struct itimerspec value;
        struct xnsynch readers;
+       struct xnthread *target;
 };
 
 #define COBALT_TFD_TICKED      (1 << 2)
 
+#define COBALT_TFD_SETTIME_FLAGS (TFD_TIMER_ABSTIME | TFD_UNBLOCK_ME)
+
 static ssize_t timerfd_read(struct xnfd *xnfd, void __user *buf, size_t size)
 {
        unsigned long long __user *u_ticks;
@@ -69,6 +72,8 @@ static ssize_t timerfd_read(struct xnfd *xnfd, void __user 
*buf, size_t size)
                err = xnsynch_sleep_on(&tfd->readers, XN_INFINITE, XN_RELATIVE);
        } while (err == 0 && (tfd->flags & COBALT_TFD_TICKED) == 0);
 
+       if (err & XNBREAK)
+               err = -EINTR;
   out:
        if (err == 0) {
                xnticks_t now;
@@ -114,7 +119,7 @@ static int timerfd_select_bind(struct xnfd *xnfd, struct 
xnselector *selector,
        xnlock_get_irqsave(&nklock, s);
        xntimer_set_sched(&tfd->timer, xnsched_current());
        err = xnselect_bind(&tfd->read_select, binding, selector, type, index,
-                       !!(tfd->flags & COBALT_TFD_TICKED));
+                       tfd->flags & COBALT_TFD_TICKED);
        xnlock_put_irqrestore(&nklock, s);
        
        return err;
@@ -151,6 +156,8 @@ static void timerfd_handler(struct xntimer *xntimer)
        tfd->flags |= COBALT_TFD_TICKED;
        xnselect_signal(&tfd->read_select, 1);
        xnsynch_wakeup_one_sleeper(&tfd->readers);
+       if (tfd->target)
+               xnthread_unblock(tfd->target);
 }
 
 int cobalt_timerfd_create(int ufd, int clockid, int flags)
@@ -177,6 +184,7 @@ int cobalt_timerfd_create(int ufd, int clockid, int flags)
        xntimer_init(&tfd->timer, &nkclock, timerfd_handler, NULL);
        xnsynch_init(&tfd->readers, XNSYNCH_PRIO | XNSYNCH_NOPIP, NULL);
        xnselect_init(&tfd->read_select);
+       tfd->target = NULL;
 
        return xnfd_enter(&tfd->xnfd, COBALT_TIMERFD_MAGIC, ufd, p, 
                        &timerfd_ops);
@@ -208,9 +216,13 @@ int cobalt_timerfd_settime(int fd, int flags,
 {
        struct itimerspec ovalue, value;
        struct cobalt_tfd *tfd;
+       int cflag;
        int err;
        spl_t s;
 
+       if (flags & ~COBALT_TFD_SETTIME_FLAGS)
+               return -EINVAL;
+
        tfd = tfd_get(fd);
        if (IS_ERR(tfd))
                return PTR_ERR(tfd);
@@ -221,20 +233,32 @@ int cobalt_timerfd_settime(int fd, int flags,
                goto out;
        }
 
-       flags = (flags & TFD_TIMER_ABSTIME) ? TIMER_ABSTIME : 0;
-       
+       cflag = (flags & TFD_TIMER_ABSTIME) ? TIMER_ABSTIME : 0;
+
        xnlock_get_irqsave(&nklock, s);
+
+       if (flags & TFD_UNBLOCK_ME) {
+               tfd->target = xnshadow_thread(current);
+               if (tfd->target == NULL) {
+                       err = -EPERM;
+                       goto out_unlock;
+               }
+       } else
+               tfd->target = NULL;
+
        if (old_value)
                cobalt_xntimer_gettime(&tfd->timer, &ovalue);
 
        err = cobalt_xntimer_settime(&tfd->timer, 
-                               clock_flag(flags, tfd->clockid), &value);
+                               clock_flag(cflag, tfd->clockid), &value);
+  out_unlock:
        xnlock_put_irqrestore(&nklock, s);
 
        if (err == 0 && old_value &&
                __xn_copy_to_user(old_value, &ovalue, sizeof(ovalue))) {
                xnlock_get_irqsave(&nklock, s);
                xntimer_stop(&tfd->timer);
+               tfd->target = NULL;
                xnlock_put_irqrestore(&nklock, s);
 
                err = -EFAULT;
diff --git a/testsuite/regression/posix/Makefile.am 
b/testsuite/regression/posix/Makefile.am
index 951db44..1a534a0 100644
--- a/testsuite/regression/posix/Makefile.am
+++ b/testsuite/regression/posix/Makefile.am
@@ -9,7 +9,7 @@ test_PROGRAMS = \
        mq_select \
        timerfd
 
-CPPFLAGS = $(XENO_USER_CFLAGS)                                 \
+CPPFLAGS = $(XENO_USER_CFLAGS)                 \
        -I$(top_srcdir)/include
 
 LDFLAGS = $(XENO_POSIX_WRAPPERS)
diff --git a/testsuite/regression/posix/timerfd.c 
b/testsuite/regression/posix/timerfd.c
index 58c55b7..4016aa7 100644
--- a/testsuite/regression/posix/timerfd.c
+++ b/testsuite/regression/posix/timerfd.c
@@ -21,6 +21,7 @@
  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
+#undef NDEBUG
 #include <stdio.h>
 #include <unistd.h>
 #include <errno.h>
@@ -181,6 +182,72 @@ static void timerfd_select_overruns2_check(void)
        close(fd);
 }
 
+static void timerfd_select_overruns_before_check(void)
+{
+       unsigned long long ticks;
+       struct itimerspec its;
+       fd_set inset;
+       int fd, i;
+       
+       check_unix(fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK));
+
+       FD_ZERO(&inset);
+       FD_SET(fd, &inset);
+
+       its.it_value.tv_sec = 0;
+       its.it_value.tv_nsec = 100000000;
+       its.it_interval.tv_sec = 0;
+       its.it_interval.tv_nsec = 100000000;
+
+       check_unix(timerfd_settime(fd, 0, &its, NULL));
+       assert(read(fd, &ticks, sizeof(ticks)) == -1 && errno == EAGAIN);
+
+       sleep(1);
+
+       for (i = 0; i < 3; i++) {
+               fd_set tmp_inset = inset;
+
+               check_unix(select(fd + 1, &tmp_inset, NULL, NULL, NULL));
+
+               assert(check_unix(read(fd, &ticks, sizeof(ticks))) == 8);
+               fprintf(stderr, "%Ld select+read ticks\n", ticks);
+               assert(ticks >= 10);
+               sleep(1);
+       }
+       
+       close(fd);
+}
+
+static void timerfd_unblock_check(void)
+{
+       unsigned long long ticks;
+       struct itimerspec its;
+       int fd1, fd2;
+       
+       check_unix(fd1 = timerfd_create(CLOCK_MONOTONIC, 0));
+       check_unix(fd2 = timerfd_create(CLOCK_MONOTONIC, 0));
+       
+       its.it_value.tv_sec = 5;
+       its.it_value.tv_nsec = 0;
+       its.it_interval.tv_sec = 0;
+       its.it_interval.tv_nsec = 0;
+       
+       check_unix(timerfd_settime(fd1, 0, &its, NULL));
+
+       its.it_value.tv_sec = 0;
+       its.it_value.tv_nsec = 100000000;
+       its.it_interval.tv_sec = 0;
+       its.it_interval.tv_nsec = 0;
+
+       check_unix(timerfd_settime(fd2, TFD_UNBLOCK_ME, &its, NULL));
+       
+       assert(read(fd1, &ticks, sizeof(ticks)) < 0 && errno == EINTR);
+
+       check_unix(close(fd1));
+       check_unix(close(fd2));
+}
+
+
 int main(void)
 {
        timerfd_basic_check();
@@ -188,6 +255,8 @@ int main(void)
        timerfd_basic_overruns_check();
        timerfd_select_overruns_check();
        timerfd_select_overruns2_check();
+       timerfd_select_overruns_before_check();
+       timerfd_unblock_check();
 
        return 0;
 }


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

Reply via email to