Re: [patch 6/13] signal/timer/event fds v6 - timerfd core ...

2007-03-17 Thread Arnd Bergmann
On Friday 16 March 2007 01:22:15 Davide Libenzi wrote:
> This patch introduces a new system call for timers events delivered
> though file descriptors. This allows timer event to be used with
> standard POSIX poll(2), select(2) and read(2). As a consequence of
> supporting the Linux f_op->poll subsystem, they can be used with
> epoll(2) too.

Half of my comments about signalfd also apply to the code in here.

Arnd <><
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [patch 6/13] signal/timer/event fds v6 - timerfd core ...

2007-03-17 Thread Arnd Bergmann
On Friday 16 March 2007 01:22:15 Davide Libenzi wrote:
 This patch introduces a new system call for timers events delivered
 though file descriptors. This allows timer event to be used with
 standard POSIX poll(2), select(2) and read(2). As a consequence of
 supporting the Linux f_op-poll subsystem, they can be used with
 epoll(2) too.

Half of my comments about signalfd also apply to the code in here.

Arnd 
-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [patch 6/13] signal/timer/event fds v6 - timerfd core ...

2007-03-16 Thread Davide Libenzi
On Fri, 16 Mar 2007, Thomas Gleixner wrote:

> On Thu, 2007-03-15 at 17:22 -0700, Davide Libenzi wrote:
> > +static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
> > + const struct itimerspec *ktmr)
> > +{
> > +   enum hrtimer_mode htmode;
> > +
> > +   htmode = (flags & TFD_TIMER_ABSTIME) ? HRTIMER_MODE_ABS: 
> > HRTIMER_MODE_REL;
> > +
> > +   ctx->ticks = 0;
> > +   ctx->texp = timespec_to_ktime(ktmr->it_value);
> 
> I know, I'm racking your nerves. texp is only used for setup. No need to
> carry it in the ctx data structure. :)

Heh, I had that feeling, that I had forgot one of those :)


- Davide


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [patch 6/13] signal/timer/event fds v6 - timerfd core ...

2007-03-16 Thread Thomas Gleixner
On Thu, 2007-03-15 at 17:22 -0700, Davide Libenzi wrote:
> +static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
> +   const struct itimerspec *ktmr)
> +{
> + enum hrtimer_mode htmode;
> +
> + htmode = (flags & TFD_TIMER_ABSTIME) ? HRTIMER_MODE_ABS: 
> HRTIMER_MODE_REL;
> +
> + ctx->ticks = 0;
> + ctx->texp = timespec_to_ktime(ktmr->it_value);

I know, I'm racking your nerves. texp is only used for setup. No need to
carry it in the ctx data structure. :)

> + ctx->tintv = timespec_to_ktime(ktmr->it_interval);
> + hrtimer_init(>tmr, clockid, htmode);
> + ctx->tmr.expires = ctx->texp;
> + ctx->tmr.function = timerfd_tmrproc;
> + if (ctx->texp.tv64 != 0)
> + hrtimer_start(>tmr, ctx->texp, htmode);
> +}

Thanks,

tglx


-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [patch 6/13] signal/timer/event fds v6 - timerfd core ...

2007-03-16 Thread Thomas Gleixner
On Thu, 2007-03-15 at 17:22 -0700, Davide Libenzi wrote:
 +static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
 +   const struct itimerspec *ktmr)
 +{
 + enum hrtimer_mode htmode;
 +
 + htmode = (flags  TFD_TIMER_ABSTIME) ? HRTIMER_MODE_ABS: 
 HRTIMER_MODE_REL;
 +
 + ctx-ticks = 0;
 + ctx-texp = timespec_to_ktime(ktmr-it_value);

I know, I'm racking your nerves. texp is only used for setup. No need to
carry it in the ctx data structure. :)

 + ctx-tintv = timespec_to_ktime(ktmr-it_interval);
 + hrtimer_init(ctx-tmr, clockid, htmode);
 + ctx-tmr.expires = ctx-texp;
 + ctx-tmr.function = timerfd_tmrproc;
 + if (ctx-texp.tv64 != 0)
 + hrtimer_start(ctx-tmr, ctx-texp, htmode);
 +}

Thanks,

tglx


-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [patch 6/13] signal/timer/event fds v6 - timerfd core ...

2007-03-16 Thread Davide Libenzi
On Fri, 16 Mar 2007, Thomas Gleixner wrote:

 On Thu, 2007-03-15 at 17:22 -0700, Davide Libenzi wrote:
  +static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
  + const struct itimerspec *ktmr)
  +{
  +   enum hrtimer_mode htmode;
  +
  +   htmode = (flags  TFD_TIMER_ABSTIME) ? HRTIMER_MODE_ABS: 
  HRTIMER_MODE_REL;
  +
  +   ctx-ticks = 0;
  +   ctx-texp = timespec_to_ktime(ktmr-it_value);
 
 I know, I'm racking your nerves. texp is only used for setup. No need to
 carry it in the ctx data structure. :)

Heh, I had that feeling, that I had forgot one of those :)


- Davide


-
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[patch 6/13] signal/timer/event fds v6 - timerfd core ...

2007-03-15 Thread Davide Libenzi
This patch introduces a new system call for timers events delivered
though file descriptors. This allows timer event to be used with
standard POSIX poll(2), select(2) and read(2). As a consequence of
supporting the Linux f_op->poll subsystem, they can be used with
epoll(2) too.
The system call is defined as:

int timerfd(int ufd, int clockid, int flags, const struct itimerspec *utmr);

The "ufd" parameter allows for re-use (re-programming) of an existing
timerfd w/out going through the close/open cycle (same as signalfd).
If "ufd" is -1, s new file descriptor will be created, otherwise the
existing "ufd" will be re-programmed.
The "clockid" parameter is either CLOCK_MONOTONIC or CLOCK_REALTIME.
The time specified in the "utmr->it_value" parameter is the expiry
time for the timer.
If the TFD_TIMER_ABSTIME flag is set in "flags", this is an absolute
time, otherwise it's a relative time.
If the time specified in the "utmr->it_interval" is not zero (.tv_sec == 0,
tv_nsec == 0), this is the period at which the following ticks should
be generated.
The "utmr->it_interval" should be set to zero if only one tick is requested.
Setting the "utmr->it_value" to zero will disable the timer, or will create
a timerfd without the timer enabled.
The function returns the new (or same, in case "ufd" is a valid timerfd
descriptor) file, or -1 in case of error.
As stated before, the timerfd file descriptor supports poll(2), select(2)
and epoll(2). When a timer event happened on the timerfd, a POLLIN mask
will be returned.
The read(2) call can be used, and it will return a u32 variable holding
the number of "ticks" that happened on the interface since the last call
to read(2). The read(2) call supportes the O_NONBLOCK flag too, and EAGAIN
will be returned if no ticks happened.
A quick test program, shows timerfd working correctly on my amd64 box:

http://www.xmailserver.org/timerfd-test.c




Signed-off-by: Davide Libenzi 



- Davide



Index: linux-2.6.21-rc3.quilt/fs/timerfd.c
===
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6.21-rc3.quilt/fs/timerfd.c 2007-03-15 16:08:05.0 -0700
@@ -0,0 +1,257 @@
+/*
+ *  fs/timerfd.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi 
+ *
+ *
+ *  Thanks to Thomas Gleixner for code reviews and useful comments.
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+
+
+struct timerfd_ctx {
+   struct hrtimer tmr;
+   ktime_t texp, tintv;
+   spinlock_t lock;
+   wait_queue_head_t wqh;
+   unsigned long ticks;
+};
+
+
+static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr);
+static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+ const struct itimerspec *ktmr);
+static int timerfd_close(struct inode *inode, struct file *file);
+static unsigned int timerfd_poll(struct file *file, poll_table *wait);
+static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
+   loff_t *ppos);
+
+
+
+static const struct file_operations timerfd_fops = {
+   .release= timerfd_close,
+   .poll   = timerfd_poll,
+   .read   = timerfd_read,
+};
+static struct kmem_cache *timerfd_ctx_cachep;
+
+
+
+static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
+{
+   struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
+   enum hrtimer_restart rval = HRTIMER_NORESTART;
+   unsigned long flags;
+
+   spin_lock_irqsave(>lock, flags);
+   ctx->ticks++;
+   wake_up_locked(>wqh);
+   if (ctx->tintv.tv64 != 0) {
+   hrtimer_forward(htmr, hrtimer_cb_get_time(htmr), ctx->tintv);
+   rval = HRTIMER_RESTART;
+   }
+   spin_unlock_irqrestore(>lock, flags);
+
+   return rval;
+}
+
+
+static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+ const struct itimerspec *ktmr)
+{
+   enum hrtimer_mode htmode;
+
+   htmode = (flags & TFD_TIMER_ABSTIME) ? HRTIMER_MODE_ABS: 
HRTIMER_MODE_REL;
+
+   ctx->ticks = 0;
+   ctx->texp = timespec_to_ktime(ktmr->it_value);
+   ctx->tintv = timespec_to_ktime(ktmr->it_interval);
+   hrtimer_init(>tmr, clockid, htmode);
+   ctx->tmr.expires = ctx->texp;
+   ctx->tmr.function = timerfd_tmrproc;
+   if (ctx->texp.tv64 != 0)
+   hrtimer_start(>tmr, ctx->texp, htmode);
+}
+
+
+asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
+   const struct itimerspec __user *utmr)
+{
+   int error;
+   struct timerfd_ctx *ctx;
+   struct file *file;
+   struct inode *inode;
+   struct itimerspec ktmr;
+
+   if (copy_from_user(, utmr, sizeof(ktmr)))
+   return -EFAULT;
+
+   if (clockid != 

[patch 6/13] signal/timer/event fds v6 - timerfd core ...

2007-03-15 Thread Davide Libenzi
This patch introduces a new system call for timers events delivered
though file descriptors. This allows timer event to be used with
standard POSIX poll(2), select(2) and read(2). As a consequence of
supporting the Linux f_op-poll subsystem, they can be used with
epoll(2) too.
The system call is defined as:

int timerfd(int ufd, int clockid, int flags, const struct itimerspec *utmr);

The ufd parameter allows for re-use (re-programming) of an existing
timerfd w/out going through the close/open cycle (same as signalfd).
If ufd is -1, s new file descriptor will be created, otherwise the
existing ufd will be re-programmed.
The clockid parameter is either CLOCK_MONOTONIC or CLOCK_REALTIME.
The time specified in the utmr-it_value parameter is the expiry
time for the timer.
If the TFD_TIMER_ABSTIME flag is set in flags, this is an absolute
time, otherwise it's a relative time.
If the time specified in the utmr-it_interval is not zero (.tv_sec == 0,
tv_nsec == 0), this is the period at which the following ticks should
be generated.
The utmr-it_interval should be set to zero if only one tick is requested.
Setting the utmr-it_value to zero will disable the timer, or will create
a timerfd without the timer enabled.
The function returns the new (or same, in case ufd is a valid timerfd
descriptor) file, or -1 in case of error.
As stated before, the timerfd file descriptor supports poll(2), select(2)
and epoll(2). When a timer event happened on the timerfd, a POLLIN mask
will be returned.
The read(2) call can be used, and it will return a u32 variable holding
the number of ticks that happened on the interface since the last call
to read(2). The read(2) call supportes the O_NONBLOCK flag too, and EAGAIN
will be returned if no ticks happened.
A quick test program, shows timerfd working correctly on my amd64 box:

http://www.xmailserver.org/timerfd-test.c




Signed-off-by: Davide Libenzi davidel@xmailserver.org



- Davide



Index: linux-2.6.21-rc3.quilt/fs/timerfd.c
===
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6.21-rc3.quilt/fs/timerfd.c 2007-03-15 16:08:05.0 -0700
@@ -0,0 +1,257 @@
+/*
+ *  fs/timerfd.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi davidel@xmailserver.org
+ *
+ *
+ *  Thanks to Thomas Gleixner for code reviews and useful comments.
+ *
+ */
+
+#include linux/file.h
+#include linux/poll.h
+#include linux/slab.h
+#include linux/init.h
+#include linux/fs.h
+#include linux/mount.h
+#include linux/module.h
+#include linux/kernel.h
+#include linux/signal.h
+#include linux/list.h
+#include linux/spinlock.h
+#include linux/time.h
+#include linux/hrtimer.h
+#include linux/jiffies.h
+#include linux/anon_inodes.h
+#include linux/timerfd.h
+
+#include asm/uaccess.h
+
+
+
+struct timerfd_ctx {
+   struct hrtimer tmr;
+   ktime_t texp, tintv;
+   spinlock_t lock;
+   wait_queue_head_t wqh;
+   unsigned long ticks;
+};
+
+
+static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr);
+static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+ const struct itimerspec *ktmr);
+static int timerfd_close(struct inode *inode, struct file *file);
+static unsigned int timerfd_poll(struct file *file, poll_table *wait);
+static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
+   loff_t *ppos);
+
+
+
+static const struct file_operations timerfd_fops = {
+   .release= timerfd_close,
+   .poll   = timerfd_poll,
+   .read   = timerfd_read,
+};
+static struct kmem_cache *timerfd_ctx_cachep;
+
+
+
+static enum hrtimer_restart timerfd_tmrproc(struct hrtimer *htmr)
+{
+   struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
+   enum hrtimer_restart rval = HRTIMER_NORESTART;
+   unsigned long flags;
+
+   spin_lock_irqsave(ctx-lock, flags);
+   ctx-ticks++;
+   wake_up_locked(ctx-wqh);
+   if (ctx-tintv.tv64 != 0) {
+   hrtimer_forward(htmr, hrtimer_cb_get_time(htmr), ctx-tintv);
+   rval = HRTIMER_RESTART;
+   }
+   spin_unlock_irqrestore(ctx-lock, flags);
+
+   return rval;
+}
+
+
+static void timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+ const struct itimerspec *ktmr)
+{
+   enum hrtimer_mode htmode;
+
+   htmode = (flags  TFD_TIMER_ABSTIME) ? HRTIMER_MODE_ABS: 
HRTIMER_MODE_REL;
+
+   ctx-ticks = 0;
+   ctx-texp = timespec_to_ktime(ktmr-it_value);
+   ctx-tintv = timespec_to_ktime(ktmr-it_interval);
+   hrtimer_init(ctx-tmr, clockid, htmode);
+   ctx-tmr.expires = ctx-texp;
+   ctx-tmr.function = timerfd_tmrproc;
+   if (ctx-texp.tv64 != 0)
+   hrtimer_start(ctx-tmr, ctx-texp, htmode);
+}
+
+
+asmlinkage long sys_timerfd(int ufd, int clockid, int flags,
+   const struct itimerspec __user *utmr)
+{