Re: [patch 6/13] signalfd/timerfd/asyncfd v5 - timerfd core ...

2007-03-16 Thread Thomas Gleixner
On Thu, 2007-03-15 at 16:02 -0700, Davide Libenzi wrote:
> > > + /*
> > > +  * When we call this, the initialization must be complete, since
> > > +  * aino_getfd() will install the fd.
> > > +  */
> > > + error = aino_getfd(, , , "[timerfd]",
> > > +_fops, ctx);
> > > + if (error)
> > > + goto err_ctxfree;
> > 
> > Again: Please turn this around. No need to start the timer before we
> > know, that everything works. 
> 
> The timerfd_setup() is not locked, so we need to make sure everything is 
> setup, before advertising the fd (and aino_getfd does that).

Right. Did not think about the bad boys peeking at file descriptors :)

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] signalfd/timerfd/asyncfd v5 - timerfd core ...

2007-03-16 Thread Thomas Gleixner
On Thu, 2007-03-15 at 16:02 -0700, Davide Libenzi wrote:
   + /*
   +  * When we call this, the initialization must be complete, since
   +  * aino_getfd() will install the fd.
   +  */
   + error = aino_getfd(ufd, inode, file, [timerfd],
   +timerfd_fops, ctx);
   + if (error)
   + goto err_ctxfree;
  
  Again: Please turn this around. No need to start the timer before we
  know, that everything works. 
 
 The timerfd_setup() is not locked, so we need to make sure everything is 
 setup, before advertising the fd (and aino_getfd does that).

Right. Did not think about the bad boys peeking at file descriptors :)

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] signalfd/timerfd/asyncfd v5 - timerfd core ...

2007-03-15 Thread Davide Libenzi
On Thu, 15 Mar 2007, Thomas Gleixner wrote:

> Davide,
> 
> On Wed, 2007-03-14 at 15:19 -0700, Davide Libenzi wrote:
> 
> > +static int timerfd_tmrproc(struct hrtimer *htmr)
> > +{
> > +   struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
> > +   int 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, htmr->base->softirq_time, ctx->tintv);
> 
> Sorry, I missed that in the first reviews. Please use
> hrtimer_cb_get_time(htmr) instead of htmr->base->softirq_time, so this
> is high res timer safe.

Heh, I was actually looking for a function instead of peeking over the 
tiemr strcture, but 2.6.20 did not have. Rebased over 2.6.21-rc3 now, so I 
can use it.




> > +   rval = HRTIMER_RESTART;
> > +   }
> > +   spin_unlock_irqrestore(>lock, flags);
> > +
> > +   return rval;
> > +}
> > +
> > +
> > +static int timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
> > +const struct itimerspec *ktmr)
> > +{
> 
> Make this void, returns 0 anyway

Ack



> > +   enum hrtimer_mode htmode;
> > +
> > +   htmode = (flags & TFD_TIMER_ABSTIME) ? HRTIMER_ABS: HRTIMER_REL;
> > +
> > +   ctx->ticks = 0;
> > +   ctx->clockid = clockid;
> > +   ctx->flags = flags;
> > +   ctx->texp = timespec_to_ktime(ktmr->it_value);
> 
> clockid is stored in the timer on setup, so no need to store it again.
> expiry time and flags are not used after setup.
> 
> Please remove those fields.

Ack



> > +   if (ufd == -1) {
> > +   ctx = kmem_cache_alloc(timerfd_ctx_cachep, GFP_KERNEL);
> > +   if (!ctx)
> > +   return -ENOMEM;
> > +
> > +   init_waitqueue_head(>wqh);
> > +   spin_lock_init(>lock);
> > +   ctx->clockid = -1;
> > +
> > +   error = timerfd_setup(ctx, clockid, flags, );
> > +   if (error)
> > +   goto err_ctxfree;
> 
> Timer setup can not fail

Ack, the new version can't.



> > +   /*
> > +* When we call this, the initialization must be complete, since
> > +* aino_getfd() will install the fd.
> > +*/
> > +   error = aino_getfd(, , , "[timerfd]",
> > +  _fops, ctx);
> > +   if (error)
> > +   goto err_ctxfree;
> 
> Again: Please turn this around. No need to start the timer before we
> know, that everything works. 

The timerfd_setup() is not locked, so we need to make sure everything is 
setup, before advertising the fd (and aino_getfd does that).



> > +   kmem_cache_free(timerfd_ctx_cachep, ctx);
> > +}
> > +
> > +
> > +static int timerfd_close(struct inode *inode, struct file *file)
> > +{
> > +   timerfd_cleanup(file->private_data);
> > +   return 0;
> > +}
> > +
> 
> Please move the timerfd_cleanup code into close(). 

I usually prefer to have a cleanup function that works on the file's data, 
but I moved the code in the release function now.
Thx for the review! I'll repost a new version based on 2.6.21-rc3 ...




- 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] signalfd/timerfd/asyncfd v5 - timerfd core ...

2007-03-15 Thread Thomas Gleixner
Davide,

On Wed, 2007-03-14 at 15:19 -0700, Davide Libenzi wrote:

> +static int timerfd_tmrproc(struct hrtimer *htmr)
> +{
> + struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
> + int 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, htmr->base->softirq_time, ctx->tintv);

Sorry, I missed that in the first reviews. Please use
hrtimer_cb_get_time(htmr) instead of htmr->base->softirq_time, so this
is high res timer safe.

> + rval = HRTIMER_RESTART;
> + }
> + spin_unlock_irqrestore(>lock, flags);
> +
> + return rval;
> +}
> +
> +
> +static int timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
> +  const struct itimerspec *ktmr)
> +{

Make this void, returns 0 anyway

> + enum hrtimer_mode htmode;
> +
> + htmode = (flags & TFD_TIMER_ABSTIME) ? HRTIMER_ABS: HRTIMER_REL;
> +
> + ctx->ticks = 0;
> + ctx->clockid = clockid;
> + ctx->flags = flags;
> + ctx->texp = timespec_to_ktime(ktmr->it_value);

clockid is stored in the timer on setup, so no need to store it again.
expiry time and flags are not used after setup.

Please remove those fields.

> + ctx->tintv = timespec_to_ktime(ktmr->it_interval);
> + hrtimer_init(>tmr, ctx->clockid, htmode);
> + ctx->tmr.expires = ctx->texp;
> + ctx->tmr.function = timerfd_tmrproc;
> + if (ctx->texp.tv64 != 0)
> + hrtimer_start(>tmr, ctx->texp, htmode);
> +
> + return 0;
> +}
> +
> + if (ufd == -1) {
> + ctx = kmem_cache_alloc(timerfd_ctx_cachep, GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
> +
> + init_waitqueue_head(>wqh);
> + spin_lock_init(>lock);
> + ctx->clockid = -1;
> +
> + error = timerfd_setup(ctx, clockid, flags, );
> + if (error)
> + goto err_ctxfree;

Timer setup can not fail

> + /*
> +  * When we call this, the initialization must be complete, since
> +  * aino_getfd() will install the fd.
> +  */
> + error = aino_getfd(, , , "[timerfd]",
> +_fops, ctx);
> + if (error)
> + goto err_ctxfree;

Again: Please turn this around. No need to start the timer before we
know, that everything works. 

> + } else {
> + file = fget(ufd);
> + if (!file)
> + return -EBADF;
> + ctx = file->private_data;
> + if (file->f_op != _fops) {
> + fput(file);
> + return -EINVAL;
> + }
> + /*
> +  * We need to stop the existing timer before reprogramming
> +  * it to the new values.
> +  */
> + for (;;) {
> + spin_lock_irq(>lock);
> + if (hrtimer_try_to_cancel(>tmr) >= 0)
> + break;
> + spin_unlock_irq(>lock);
> + cpu_relax();
> + }
> + /*
> +  * Re-program the timer to the new value ...
> +  */
> + error = timerfd_setup(ctx, clockid, flags, );

Timer setup can not fail

> + spin_unlock_irq(>lock);
> + fput(file);
> + if (error)
> + return error;
> + }
> +
> + return ufd;
> +
> +err_ctxfree:
> + timerfd_cleanup(ctx);
> + return error;
> +}
> +
> +
> +static void timerfd_cleanup(struct timerfd_ctx *ctx)
> +{
> + if (ctx->clockid >= 0)
> + hrtimer_cancel(>tmr);

You don't have a file descriptor, when the setup failed. So the timer is
always initialized.

> + kmem_cache_free(timerfd_ctx_cachep, ctx);
> +}
> +
> +
> +static int timerfd_close(struct inode *inode, struct file *file)
> +{
> + timerfd_cleanup(file->private_data);
> + return 0;
> +}
> +

Please move the timerfd_cleanup code into close(). 

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] signalfd/timerfd/asyncfd v5 - timerfd core ...

2007-03-15 Thread Thomas Gleixner
Davide,

On Wed, 2007-03-14 at 15:19 -0700, Davide Libenzi wrote:

 +static int timerfd_tmrproc(struct hrtimer *htmr)
 +{
 + struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
 + int 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, htmr-base-softirq_time, ctx-tintv);

Sorry, I missed that in the first reviews. Please use
hrtimer_cb_get_time(htmr) instead of htmr-base-softirq_time, so this
is high res timer safe.

 + rval = HRTIMER_RESTART;
 + }
 + spin_unlock_irqrestore(ctx-lock, flags);
 +
 + return rval;
 +}
 +
 +
 +static int timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
 +  const struct itimerspec *ktmr)
 +{

Make this void, returns 0 anyway

 + enum hrtimer_mode htmode;
 +
 + htmode = (flags  TFD_TIMER_ABSTIME) ? HRTIMER_ABS: HRTIMER_REL;
 +
 + ctx-ticks = 0;
 + ctx-clockid = clockid;
 + ctx-flags = flags;
 + ctx-texp = timespec_to_ktime(ktmr-it_value);

clockid is stored in the timer on setup, so no need to store it again.
expiry time and flags are not used after setup.

Please remove those fields.

 + ctx-tintv = timespec_to_ktime(ktmr-it_interval);
 + hrtimer_init(ctx-tmr, ctx-clockid, htmode);
 + ctx-tmr.expires = ctx-texp;
 + ctx-tmr.function = timerfd_tmrproc;
 + if (ctx-texp.tv64 != 0)
 + hrtimer_start(ctx-tmr, ctx-texp, htmode);
 +
 + return 0;
 +}
 +
 + if (ufd == -1) {
 + ctx = kmem_cache_alloc(timerfd_ctx_cachep, GFP_KERNEL);
 + if (!ctx)
 + return -ENOMEM;
 +
 + init_waitqueue_head(ctx-wqh);
 + spin_lock_init(ctx-lock);
 + ctx-clockid = -1;
 +
 + error = timerfd_setup(ctx, clockid, flags, ktmr);
 + if (error)
 + goto err_ctxfree;

Timer setup can not fail

 + /*
 +  * When we call this, the initialization must be complete, since
 +  * aino_getfd() will install the fd.
 +  */
 + error = aino_getfd(ufd, inode, file, [timerfd],
 +timerfd_fops, ctx);
 + if (error)
 + goto err_ctxfree;

Again: Please turn this around. No need to start the timer before we
know, that everything works. 

 + } else {
 + file = fget(ufd);
 + if (!file)
 + return -EBADF;
 + ctx = file-private_data;
 + if (file-f_op != timerfd_fops) {
 + fput(file);
 + return -EINVAL;
 + }
 + /*
 +  * We need to stop the existing timer before reprogramming
 +  * it to the new values.
 +  */
 + for (;;) {
 + spin_lock_irq(ctx-lock);
 + if (hrtimer_try_to_cancel(ctx-tmr) = 0)
 + break;
 + spin_unlock_irq(ctx-lock);
 + cpu_relax();
 + }
 + /*
 +  * Re-program the timer to the new value ...
 +  */
 + error = timerfd_setup(ctx, clockid, flags, ktmr);

Timer setup can not fail

 + spin_unlock_irq(ctx-lock);
 + fput(file);
 + if (error)
 + return error;
 + }
 +
 + return ufd;
 +
 +err_ctxfree:
 + timerfd_cleanup(ctx);
 + return error;
 +}
 +
 +
 +static void timerfd_cleanup(struct timerfd_ctx *ctx)
 +{
 + if (ctx-clockid = 0)
 + hrtimer_cancel(ctx-tmr);

You don't have a file descriptor, when the setup failed. So the timer is
always initialized.

 + kmem_cache_free(timerfd_ctx_cachep, ctx);
 +}
 +
 +
 +static int timerfd_close(struct inode *inode, struct file *file)
 +{
 + timerfd_cleanup(file-private_data);
 + return 0;
 +}
 +

Please move the timerfd_cleanup code into close(). 

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] signalfd/timerfd/asyncfd v5 - timerfd core ...

2007-03-15 Thread Davide Libenzi
On Thu, 15 Mar 2007, Thomas Gleixner wrote:

 Davide,
 
 On Wed, 2007-03-14 at 15:19 -0700, Davide Libenzi wrote:
 
  +static int timerfd_tmrproc(struct hrtimer *htmr)
  +{
  +   struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
  +   int 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, htmr-base-softirq_time, ctx-tintv);
 
 Sorry, I missed that in the first reviews. Please use
 hrtimer_cb_get_time(htmr) instead of htmr-base-softirq_time, so this
 is high res timer safe.

Heh, I was actually looking for a function instead of peeking over the 
tiemr strcture, but 2.6.20 did not have. Rebased over 2.6.21-rc3 now, so I 
can use it.




  +   rval = HRTIMER_RESTART;
  +   }
  +   spin_unlock_irqrestore(ctx-lock, flags);
  +
  +   return rval;
  +}
  +
  +
  +static int timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
  +const struct itimerspec *ktmr)
  +{
 
 Make this void, returns 0 anyway

Ack



  +   enum hrtimer_mode htmode;
  +
  +   htmode = (flags  TFD_TIMER_ABSTIME) ? HRTIMER_ABS: HRTIMER_REL;
  +
  +   ctx-ticks = 0;
  +   ctx-clockid = clockid;
  +   ctx-flags = flags;
  +   ctx-texp = timespec_to_ktime(ktmr-it_value);
 
 clockid is stored in the timer on setup, so no need to store it again.
 expiry time and flags are not used after setup.
 
 Please remove those fields.

Ack



  +   if (ufd == -1) {
  +   ctx = kmem_cache_alloc(timerfd_ctx_cachep, GFP_KERNEL);
  +   if (!ctx)
  +   return -ENOMEM;
  +
  +   init_waitqueue_head(ctx-wqh);
  +   spin_lock_init(ctx-lock);
  +   ctx-clockid = -1;
  +
  +   error = timerfd_setup(ctx, clockid, flags, ktmr);
  +   if (error)
  +   goto err_ctxfree;
 
 Timer setup can not fail

Ack, the new version can't.



  +   /*
  +* When we call this, the initialization must be complete, since
  +* aino_getfd() will install the fd.
  +*/
  +   error = aino_getfd(ufd, inode, file, [timerfd],
  +  timerfd_fops, ctx);
  +   if (error)
  +   goto err_ctxfree;
 
 Again: Please turn this around. No need to start the timer before we
 know, that everything works. 

The timerfd_setup() is not locked, so we need to make sure everything is 
setup, before advertising the fd (and aino_getfd does that).



  +   kmem_cache_free(timerfd_ctx_cachep, ctx);
  +}
  +
  +
  +static int timerfd_close(struct inode *inode, struct file *file)
  +{
  +   timerfd_cleanup(file-private_data);
  +   return 0;
  +}
  +
 
 Please move the timerfd_cleanup code into close(). 

I usually prefer to have a cleanup function that works on the file's data, 
but I moved the code in the release function now.
Thx for the review! I'll repost a new version based on 2.6.21-rc3 ...




- 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] signalfd/timerfd/asyncfd v5 - timerfd core ...

2007-03-14 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.20.ep2/fs/timerfd.c
===
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6.20.ep2/fs/timerfd.c   2007-03-12 11:47:01.0 -0700
@@ -0,0 +1,273 @@
+/*
+ *  fs/timerfd.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi 
+ *
+ *
+ *  Thanks to Thomas Gleixner for code review 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;
+   int clockid;
+   int flags;
+   ktime_t texp, tintv;
+   spinlock_t lock;
+   wait_queue_head_t wqh;
+   unsigned long ticks;
+};
+
+
+static int timerfd_tmrproc(struct hrtimer *htmr);
+static int timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+const struct itimerspec *ktmr);
+static void timerfd_cleanup(struct timerfd_ctx *ctx);
+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 int timerfd_tmrproc(struct hrtimer *htmr)
+{
+   struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
+   int 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, htmr->base->softirq_time, ctx->tintv);
+   rval = HRTIMER_RESTART;
+   }
+   spin_unlock_irqrestore(>lock, flags);
+
+   return rval;
+}
+
+
+static int timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+const struct itimerspec *ktmr)
+{
+   enum hrtimer_mode htmode;
+
+   htmode = (flags & TFD_TIMER_ABSTIME) ? HRTIMER_ABS: HRTIMER_REL;
+
+   ctx->ticks = 0;
+   ctx->clockid = clockid;
+   ctx->flags = flags;
+   ctx->texp = timespec_to_ktime(ktmr->it_value);
+   ctx->tintv = timespec_to_ktime(ktmr->it_interval);
+   hrtimer_init(>tmr, ctx->clockid, htmode);
+   ctx->tmr.expires = ctx->texp;
+   ctx->tmr.function = timerfd_tmrproc;
+   if (ctx->texp.tv64 != 0)
+   hrtimer_start(>tmr, ctx->texp, htmode);
+
+   return 0;
+}
+
+
+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;
+
+ 

[patch 6/13] signalfd/timerfd/asyncfd v5 - timerfd core ...

2007-03-14 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.20.ep2/fs/timerfd.c
===
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6.20.ep2/fs/timerfd.c   2007-03-12 11:47:01.0 -0700
@@ -0,0 +1,273 @@
+/*
+ *  fs/timerfd.c
+ *
+ *  Copyright (C) 2007  Davide Libenzi davidel@xmailserver.org
+ *
+ *
+ *  Thanks to Thomas Gleixner for code review 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;
+   int clockid;
+   int flags;
+   ktime_t texp, tintv;
+   spinlock_t lock;
+   wait_queue_head_t wqh;
+   unsigned long ticks;
+};
+
+
+static int timerfd_tmrproc(struct hrtimer *htmr);
+static int timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+const struct itimerspec *ktmr);
+static void timerfd_cleanup(struct timerfd_ctx *ctx);
+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 int timerfd_tmrproc(struct hrtimer *htmr)
+{
+   struct timerfd_ctx *ctx = container_of(htmr, struct timerfd_ctx, tmr);
+   int 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, htmr-base-softirq_time, ctx-tintv);
+   rval = HRTIMER_RESTART;
+   }
+   spin_unlock_irqrestore(ctx-lock, flags);
+
+   return rval;
+}
+
+
+static int timerfd_setup(struct timerfd_ctx *ctx, int clockid, int flags,
+const struct itimerspec *ktmr)
+{
+   enum hrtimer_mode htmode;
+
+   htmode = (flags  TFD_TIMER_ABSTIME) ? HRTIMER_ABS: HRTIMER_REL;
+
+   ctx-ticks = 0;
+   ctx-clockid = clockid;
+   ctx-flags = flags;
+   ctx-texp = timespec_to_ktime(ktmr-it_value);
+   ctx-tintv = timespec_to_ktime(ktmr-it_interval);
+   hrtimer_init(ctx-tmr, ctx-clockid, htmode);
+   ctx-tmr.expires = ctx-texp;
+   ctx-tmr.function = timerfd_tmrproc;
+   if (ctx-texp.tv64 != 0)
+   hrtimer_start(ctx-tmr, ctx-texp, htmode);
+
+   return 0;
+}
+
+
+asmlinkage long