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

Author: Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>
Date:   Thu Dec 26 22:29:04 2013 +0100

cobalt: add timerfd services

---

 include/cobalt/sys/timerfd.h           |   41 +++++
 include/cobalt/uapi/syscall.h          |    4 +-
 kernel/cobalt/posix/Makefile           |    3 +-
 kernel/cobalt/posix/internal.h         |    1 +
 kernel/cobalt/posix/timerfd.c          |  291 ++++++++++++++++++++++++++++++++
 kernel/cobalt/posix/timerfd.h          |   14 ++
 lib/cobalt/Makefile.am                 |    1 +
 lib/cobalt/cobalt.wrappers             |    3 +
 lib/cobalt/timerfd.c                   |   73 ++++++++
 testsuite/regression/posix/Makefile.am |    3 +-
 testsuite/regression/posix/timerfd.c   |  193 +++++++++++++++++++++
 11 files changed, 624 insertions(+), 3 deletions(-)

diff --git a/include/cobalt/sys/timerfd.h b/include/cobalt/sys/timerfd.h
new file mode 100644
index 0000000..82f08bb
--- /dev/null
+++ b/include/cobalt/sys/timerfd.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+ */
+#ifndef _COBALT_SYS_TIMERFD_H
+#define _COBALT_SYS_TIMERFD_H
+
+#pragma GCC system_header
+#include_next <sys/timerfd.h>
+#include <cobalt/wrappers.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+COBALT_DECL(int, timerfd_create(int clockid, int flags));
+
+COBALT_DECL(int, timerfd_settime(int fd, int flags,
+               const struct itimerspec *new_value,
+               struct itimerspec *old_value));
+
+COBALT_DECL(int, timerfd_gettime(int fd, struct itimerspec *curr_value));
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* TIMERFD_H */
diff --git a/include/cobalt/uapi/syscall.h b/include/cobalt/uapi/syscall.h
index c995895..08bfe12 100644
--- a/include/cobalt/uapi/syscall.h
+++ b/include/cobalt/uapi/syscall.h
@@ -78,7 +78,9 @@
 #define sc_cobalt_sigtimedwait         55
 #define sc_cobalt_sigpending           56
 #define sc_cobalt_kill                 57
-/* 58-60 unimplemented */
+#define sc_cobalt_timerfd_create       58
+#define sc_cobalt_timerfd_settime      59
+#define sc_cobalt_timerfd_gettime      60
 #define sc_cobalt_mutexattr_init        61
 #define sc_cobalt_mutexattr_destroy     62
 #define sc_cobalt_mutexattr_gettype     63
diff --git a/kernel/cobalt/posix/Makefile b/kernel/cobalt/posix/Makefile
index 595e737..358a35a 100644
--- a/kernel/cobalt/posix/Makefile
+++ b/kernel/cobalt/posix/Makefile
@@ -17,6 +17,7 @@ posix-y :=            \
        signal.o        \
        syscall.o       \
        thread.o        \
-       timer.o
+       timer.o         \
+       timerfd.o
 
 ccflags-y := -Iarch/$(SRCARCH)/xenomai/include -Iinclude/xenomai
diff --git a/kernel/cobalt/posix/internal.h b/kernel/cobalt/posix/internal.h
index 81d1efd..09546c7 100644
--- a/kernel/cobalt/posix/internal.h
+++ b/kernel/cobalt/posix/internal.h
@@ -43,6 +43,7 @@
 #define COBALT_TIMER_MAGIC       COBALT_MAGIC(0E)
 #define COBALT_EVENT_MAGIC       COBALT_MAGIC(0F)
 #define COBALT_MONITOR_MAGIC     COBALT_MAGIC(10)
+#define COBALT_TIMERFD_MAGIC    COBALT_MAGIC(11)
 
 #define cobalt_obj_active(h,m,t)                       \
        ((h) && ((t *)(h))->magic == (m))
diff --git a/kernel/cobalt/posix/timerfd.c b/kernel/cobalt/posix/timerfd.c
new file mode 100644
index 0000000..cf8156d
--- /dev/null
+++ b/kernel/cobalt/posix/timerfd.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2013 Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>.
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/timerfd.h>
+#include <cobalt/kernel/fd.h>
+#include <cobalt/kernel/timer.h>
+#include <cobalt/kernel/select.h>
+#include "internal.h"
+#include "clock.h"
+#include "timerfd.h"
+
+struct cobalt_tfd {
+       int flags;
+       clockid_t clockid;
+       struct xnfd xnfd;
+       struct xntimer timer;
+       DECLARE_XNSELECT(read_select);
+       struct itimerspec value;
+       struct xnsynch readers;
+};
+
+#define COBALT_TFD_TICKED      (1 << 2)
+
+static ssize_t timerfd_read(struct xnfd *xnfd, void __user *buf, size_t size)
+{
+       unsigned long long __user *u_ticks;
+       unsigned long long ticks;
+       struct cobalt_tfd *tfd;
+       bool aligned;
+       spl_t s;
+       int err;
+
+       if (size < sizeof(ticks))
+               return -EINVAL;
+
+       u_ticks = buf;
+       aligned = (((unsigned long)buf) & (sizeof(ticks) - 1)) == 0;
+
+       tfd = container_of(xnfd, struct cobalt_tfd, xnfd);
+
+       xnlock_get_irqsave(&nklock, s);
+       if (tfd->flags & COBALT_TFD_TICKED) {
+               err = 0;
+               goto out;
+       }
+       if (tfd->flags & TFD_NONBLOCK) {
+               err = -EAGAIN;
+               goto out;
+       }
+       
+       xntimer_set_sched(&tfd->timer, xnsched_current());
+       err = xnsynch_sleep_on(&tfd->readers, XN_INFINITE, XN_RELATIVE);
+
+  out:
+       if (err == 0) {
+               xnticks_t now;
+               
+               if (xntimer_interval(&tfd->timer)) {
+                       now = xnclock_read_raw(xntimer_clock(&tfd->timer));
+                       ticks = 1 + xntimer_get_overruns(&tfd->timer, now);
+               } else
+                       ticks = 1;
+               
+               tfd->flags &= ~COBALT_TFD_TICKED;
+               xnselect_signal(&tfd->read_select, 0);
+       }
+       xnlock_put_irqrestore(&nklock, s);
+
+       if (err == 0) {
+               if (aligned)
+                       err = __xn_put_user(ticks, u_ticks);
+               else
+                       err = __xn_copy_to_user(buf, &ticks, sizeof(ticks));
+               if (err)
+                       err = -EFAULT;
+       }
+       
+       return err ?: sizeof(ticks);
+}
+
+static int timerfd_select_bind(struct xnfd *xnfd, struct xnselector *selector,
+                       unsigned type, unsigned index)
+{
+       struct cobalt_tfd *tfd = container_of(xnfd, struct cobalt_tfd, xnfd);
+       struct xnselect_binding *binding;
+       spl_t s;
+       int err;
+       
+       if (type != XNSELECT_READ)
+               return -EBADF;
+       
+       binding = xnmalloc(sizeof(*binding));
+       if (binding == NULL)
+               return -ENOMEM;
+       
+       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));
+       xnlock_put_irqrestore(&nklock, s);
+       
+       return err;
+}
+
+static void timerfd_destroy(struct xnfd *xnfd)
+{
+       struct cobalt_tfd *tfd = container_of(xnfd, struct cobalt_tfd, xnfd);
+       int resched;
+       spl_t s;
+       
+       xnlock_get_irqsave(&nklock, s);
+       xntimer_destroy(&tfd->timer);
+       resched = xnsynch_destroy(&tfd->readers) == XNSYNCH_RESCHED;
+       xnlock_put_irqrestore(&nklock, s);
+       xnselect_destroy(&tfd->read_select);
+       xnfree(tfd);
+       
+       if (resched)
+               xnsched_run();
+}
+
+static struct xnfd_ops timerfd_ops = {
+       .read_rt = timerfd_read,
+       .select_bind = timerfd_select_bind,
+       .destroy = timerfd_destroy,
+};
+
+static void timerfd_handler(struct xntimer *xntimer)
+{
+       struct cobalt_tfd *tfd;
+
+       tfd = container_of(xntimer, struct cobalt_tfd, timer);
+       tfd->flags |= COBALT_TFD_TICKED;
+       xnselect_signal(&tfd->read_select, 1);
+       xnsynch_wakeup_one_sleeper(&tfd->readers);
+}
+
+int cobalt_timerfd_create(int ufd, int clockid, int flags)
+{
+       struct cobalt_tfd *tfd;
+       struct xnsys_ppd *p;
+
+       p = xnsys_ppd_get(0);
+       if (p == &__xnsys_global_ppd)
+               return -EPERM;
+
+       if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
+               return -EINVAL;
+       
+       if (flags & ~TFD_CREATE_FLAGS)
+               return -EINVAL;
+       
+       tfd = xnmalloc(sizeof(*tfd));
+       if (tfd == NULL)
+               return -ENOMEM;
+       
+       tfd->flags = flags;
+       tfd->clockid = clockid;
+       xntimer_init(&tfd->timer, &nkclock, timerfd_handler, NULL);
+       xnsynch_init(&tfd->readers, XNSYNCH_PRIO | XNSYNCH_NOPIP, NULL);
+       xnselect_init(&tfd->read_select);
+
+       return xnfd_enter(&tfd->xnfd, COBALT_TIMERFD_MAGIC, ufd, p, 
+                       &timerfd_ops);
+}
+
+static inline struct cobalt_tfd *tfd_get(int fd)
+{
+       struct xnfd *xnfd;
+       
+       xnfd = xnfd_get(fd, current->mm, COBALT_TIMERFD_MAGIC);
+       if (IS_ERR(xnfd)) {
+               int err = PTR_ERR(xnfd);
+               if (err == -EBADF && cobalt_process_context() == NULL)
+                       err = -EPERM;
+               return ERR_PTR(err);
+       }
+       
+       return container_of(xnfd, struct cobalt_tfd, xnfd);
+}
+
+static inline void tfd_put(struct cobalt_tfd *tfd)
+{
+       xnfd_put(&tfd->xnfd);
+}
+
+static inline void 
+timerfd_gettime(struct cobalt_tfd *tfd, struct itimerspec *value)
+{
+       if (xntimer_running_p(&tfd->timer) == 0) {
+               value->it_value.tv_sec = 0;
+               value->it_value.tv_nsec = 0;
+               value->it_interval.tv_sec = 0;
+               value->it_interval.tv_nsec = 0;
+               return;
+       }
+       
+       ns2ts(&value->it_value, xntimer_get_timeout(&tfd->timer));
+       ns2ts(&value->it_interval, xntimer_interval(&tfd->timer));
+}
+
+int cobalt_timerfd_settime(int fd, int flags,
+                       const struct itimerspec __user *new_value,
+                       struct itimerspec __user *old_value)
+{
+       struct itimerspec ovalue, value;
+       struct cobalt_tfd *tfd;
+       xnticks_t start, period;
+       int err;
+       spl_t s;
+
+       tfd = tfd_get(fd);
+       if (IS_ERR(tfd))
+               return PTR_ERR(tfd);
+
+       if (!new_value ||
+               __xn_copy_from_user(&value, new_value, sizeof(value))) {
+               err = -EFAULT;
+               goto out;
+       }
+
+       start = ts2ns(&value.it_value) + 1;
+       period = ts2ns(&value.it_interval);
+       flags = (flags & TFD_TIMER_ABSTIME) ? TIMER_ABSTIME : 0;
+       
+       xnlock_get_irqsave(&nklock, s);
+       if (old_value)
+               timerfd_gettime(tfd, &ovalue);
+
+       if (start == 0) {
+               xntimer_stop(&tfd->timer);
+               err = 0;
+       } else {
+               xntimer_set_sched(&tfd->timer, xnsched_current());
+               err = xntimer_start(&tfd->timer, start, period, 
+                               clock_flag(flags, tfd->clockid));
+       }
+       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);
+               xnlock_put_irqrestore(&nklock, s);
+
+               err = -EFAULT;
+       }
+
+  out:
+       tfd_put(tfd);
+       
+       return err;
+}
+
+int cobalt_timerfd_gettime(int fd, struct itimerspec __user *curr_value)
+{
+       struct itimerspec value;
+       struct cobalt_tfd *tfd;
+       int err = 0;
+       spl_t s;
+
+       tfd = tfd_get(fd);
+       if (IS_ERR(tfd))
+               return PTR_ERR(tfd);
+
+       xnlock_get_irqsave(&nklock, s);
+       timerfd_gettime(tfd, &value);
+       xnlock_put_irqrestore(&nklock, s);
+       
+       if (!curr_value || __xn_copy_to_user(curr_value, &value, sizeof(value)))
+               err = -EFAULT;
+       
+       tfd_put(tfd);
+       
+       return err;
+}
diff --git a/kernel/cobalt/posix/timerfd.h b/kernel/cobalt/posix/timerfd.h
new file mode 100644
index 0000000..12535e4
--- /dev/null
+++ b/kernel/cobalt/posix/timerfd.h
@@ -0,0 +1,14 @@
+#ifndef TIMERFD_H
+#define TIMERFD_H
+
+#include <linux/time.h>
+
+int cobalt_timerfd_create(int fd, int clockid, int flags);
+
+int cobalt_timerfd_settime(int fd, int flags,
+                       const struct itimerspec __user *new_value,
+                       struct itimerspec __user *old_value);
+
+int cobalt_timerfd_gettime(int fd, struct itimerspec __user *curr_value);
+
+#endif /* TIMERFD_H */
diff --git a/lib/cobalt/Makefile.am b/lib/cobalt/Makefile.am
index 9f87929..9f3edec 100644
--- a/lib/cobalt/Makefile.am
+++ b/lib/cobalt/Makefile.am
@@ -34,6 +34,7 @@ libcobalt_la_SOURCES =                \
        thread.c                \
        ticks.c                 \
        timer.c                 \
+       timerfd.c               \
        trace.c                 \
        wrappers.c
 
diff --git a/lib/cobalt/cobalt.wrappers b/lib/cobalt/cobalt.wrappers
index 519973d..6783a68 100644
--- a/lib/cobalt/cobalt.wrappers
+++ b/lib/cobalt/cobalt.wrappers
@@ -84,6 +84,9 @@
 --wrap timer_settime
 --wrap timer_getoverrun
 --wrap timer_gettime
+--wrap timerfd_create
+--wrap timerfd_gettime
+--wrap timerfd_settime
 --wrap select
 --wrap vfprintf
 --wrap vprintf
diff --git a/lib/cobalt/timerfd.c b/lib/cobalt/timerfd.c
new file mode 100644
index 0000000..a975127
--- /dev/null
+++ b/lib/cobalt/timerfd.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 Gilles Chanteperdrix <gilles.chanteperd...@xenomai.org>.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
+ */
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/timerfd.h>
+#include <asm/xenomai/syscall.h>
+#include "internal.h"
+
+COBALT_IMPL(int, timerfd_create, (int clockid, int flags))
+{
+       int ret;
+       int fd;
+
+       fd = __STD(open("/dev/null", O_RDWR, 0));
+       if (fd == -1)
+               return fd;
+
+       ret = -XENOMAI_SKINCALL3(__cobalt_muxid, 
+                               sc_cobalt_timerfd_create,
+                               fd, clockid, flags);
+       if (ret == 0)
+               return fd;
+       
+       __STD(close(fd));
+       errno = ret;
+       return -1;
+}
+
+COBALT_IMPL(int, timerfd_settime, (int fd, int flags,
+               const struct itimerspec *new_value,
+               struct itimerspec *old_value))
+{
+       int ret;
+       
+       ret = -XENOMAI_SKINCALL4(__cobalt_muxid,
+                               sc_cobalt_timerfd_settime,
+                               fd, flags, new_value, old_value);
+       if (ret == 0)
+               return ret;
+       
+       errno = ret;
+       return -1;
+}
+
+COBALT_IMPL(int, timerfd_gettime, (int fd, struct itimerspec *curr_value))
+{
+       int ret;
+       
+       ret = -XENOMAI_SKINCALL2(__cobalt_muxid,
+                               sc_cobalt_timerfd_gettime,
+                               fd, curr_value);
+       if (ret == 0)
+               return ret;
+       
+       errno = ret;
+       return -1;
+}
diff --git a/testsuite/regression/posix/Makefile.am 
b/testsuite/regression/posix/Makefile.am
index af2c246..951db44 100644
--- a/testsuite/regression/posix/Makefile.am
+++ b/testsuite/regression/posix/Makefile.am
@@ -6,7 +6,8 @@ noinst_HEADERS = check.h
 
 test_PROGRAMS = \
        leaks \
-       mq_select
+       mq_select \
+       timerfd
 
 CPPFLAGS = $(XENO_USER_CFLAGS)                                 \
        -I$(top_srcdir)/include
diff --git a/testsuite/regression/posix/timerfd.c 
b/testsuite/regression/posix/timerfd.c
new file mode 100644
index 0000000..58c55b7
--- /dev/null
+++ b/testsuite/regression/posix/timerfd.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2013 Gilles Chanteperdrix <g...@xenomai.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *  
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/timerfd.h>
+#include "check.h"
+
+static void timerfd_basic_check(void)
+{
+       struct itimerspec its;
+       int fd, i;
+       
+       check_unix(fd = timerfd_create(CLOCK_MONOTONIC, 0));
+
+       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));
+       
+       for (i = 0; i < 10; i++) {
+               unsigned long long ticks;
+               
+               assert(check_unix(read(fd, &ticks, sizeof(ticks))) == 8);
+               fprintf(stderr, "%Ld direct read ticks\n", ticks);
+               assert(ticks >= 1);
+       }
+       
+       close(fd);
+}
+
+static void timerfd_select_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);
+       
+       for (i = 0; i < 10; 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 >= 1);
+       }
+       
+       close(fd);
+}
+
+static void timerfd_basic_overruns_check(void)
+{
+       struct itimerspec its;
+       int fd, i;
+       
+       check_unix(fd = timerfd_create(CLOCK_MONOTONIC, 0));
+
+       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));
+       
+       for (i = 0; i < 3; i++) {
+               unsigned long long ticks;
+               
+               sleep(1);
+               assert(check_unix(read(fd, &ticks, sizeof(ticks))) == 8);
+               fprintf(stderr, "%Ld direct read ticks\n", ticks);
+               assert(ticks >= 10);
+       }
+       
+       close(fd);
+}
+
+static void timerfd_select_overruns_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);
+       
+       for (i = 0; i < 3; i++) {
+               fd_set tmp_inset = inset;
+
+               sleep(1);
+               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);
+       }
+       
+       close(fd);
+}
+
+static void timerfd_select_overruns2_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);
+       
+       for (i = 0; i < 3; i++) {
+               fd_set tmp_inset = inset;
+
+               check_unix(select(fd + 1, &tmp_inset, NULL, NULL, NULL));
+
+               sleep(1);
+               
+               assert(check_unix(read(fd, &ticks, sizeof(ticks))) == 8);
+               fprintf(stderr, "%Ld select+read ticks\n", ticks);
+               assert(ticks >= 11);
+       }
+       
+       close(fd);
+}
+
+int main(void)
+{
+       timerfd_basic_check();
+       timerfd_select_check();
+       timerfd_basic_overruns_check();
+       timerfd_select_overruns_check();
+       timerfd_select_overruns2_check();
+
+       return 0;
+}


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

Reply via email to