Re: [patch 2/9] signalfd/timerfd - signalfd core ...

2007-03-11 Thread Davide Libenzi
On Sun, 11 Mar 2007, Oleg Nesterov wrote:

> On 03/10, Davide Libenzi wrote:
> >
> > +static void signalfd_put_sighand(struct signalfd_ctx *ctx,
> > +struct sighand_struct *sighand,
> > +unsigned long *flags)
> > +{
> > +   unlock_task_sighand(ctx->tsk, flags);
> > +}
> 
> Note that signalfd_put_sighand() doesn't need "sighand" parameter, please
> see below.

I want it to return the sighand, and for simmetry I prefer the "put" to be 
passed the parameter back too. Even if not used.



> > +int signalfd_deliver(struct sighand_struct *sighand, int sig,
> > +struct siginfo *info)
> > +{
> > +   int nsig = 0;
> > +   struct signalfd_ctx *ctx, *tmp;
> > +
> > +   list_for_each_entry_safe(ctx, tmp, >sfdlist, lnk) {
> > +   /*
> > +* We use a negative signal value as a way to broadcast that the
> > +* sighand has been orphaned, so that we can notify all the
> > +* listeners about this. Remeber the ctx->sigmask is inverted,
> > +* so if the user is interested in a signal, that corresponding
> > +* bit will be zero.
> > +*/
> > +   if (sig < 0)
> > +   list_del_init(>lnk);
> 
> I'm afraid this is not right. This should be per-thread.
> 
> Suppose we have threads T1 and T2 from the same thread group. sighand->sfdlist
> contains ctx1 and ctx2 "linked" to T1 and T2. Now, T1 exits, __exit_signal()
> does signalfd_notify(sighand, -1), and "unlinks" all threads, not just T1.
> 
> IOW, we should do
> 
>   if (ctx->tsk == current) {
>   list_del_init(>lnk);
>   wake_up(>wqh);
>   }

Yes, of course. Dunno why the change got lost.



> Perhaps it makes sense to not re-use signalfd_deliver(), but introduce
> a new signalfd_xxx(sighand, tsk) helper for de_thread/exit_signal.
> 
> Btw, signalfd_deliver() doesn't use "info" parameter.
> 
> > +   if (sig < 0 || !sigismember(>sigmask, sig)) {
> > +   wake_up(>wqh);
> 
> Minor nit. Perhaps it makes sense to do
> 
>   void signalfd_deliver(struct task_struct *tsk, int sig, struct 
> sigpending *pending)
>   {
>   struct sighand_struct *sighand = tsk->sighand;
>   int private = (tsk->pending == pending);
> 
>   list_for_each_entry_safe(ctx, tmp, >sfdlist, lnk) {
>   if (private && ctx->tsk != tsk)
>   continue;
>   if (!sigismember(>sigmask, sig))
>   wake_up(>wqh);
>   }
>   }
> 
> Even better: signalfd_deliver(struct task_struct *tsk, int sig, int private).
> This way specific_send_sig_info/send_sigqueue won't do a "false" wakeup.

I agree in the latter.



> > +asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t 
> > sizemask)
> > +{
> > ...
> > +   if ((sighand = signalfd_get_sighand(ctx, )) != NULL) {
> > +   ctx->sigmask = sigmask;
> > +   signalfd_put_sighand(ctx, sighand, );
> > +   }
> 
> This looks like unneeded complication to me, I'd suggest
> 
>   if (signalfd_get_sighand(ctx, )) {
>   ctx->sigmask = sigmask;
>   signalfd_put_sighand(ctx, flags);
>   }
> 
> unlock_task_sighand() (and thus signalfd_put_sighand) doesn't need "sighand"
> parameter. signalfd_get_sighand() is in fact boolean. It makes sense to return
> sighand, it may be useful, but this patch only needs != NULL.
> 
> Every usage of signalfd_get_sighand() could be simplified accordingly.

As I said before, I prefer that way.


> > +* Tell all the sighand listeners that this sighand has
> > +* been detached. Needs to be called with the sighand lock
> > +* held.
> > +*/
> > +   if (unlikely(!list_empty(>sfdlist))) {
> > +   spin_lock_irq(>siglock);
> > +   signalfd_notify(oldsighand, -1, NULL);
> > +   spin_unlock_irq(>siglock);
> > +   }
> 
> Very minor nit. I'd suggest to make a new helper and put it in signalfd.h
> (like signalfd_notify()). This will help CONFIG_SIGNALFD.

Yes, makes sense.



- 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 2/9] signalfd/timerfd - signalfd core ...

2007-03-11 Thread Oleg Nesterov
On 03/10, Davide Libenzi wrote:
>
> +static void signalfd_put_sighand(struct signalfd_ctx *ctx,
> +  struct sighand_struct *sighand,
> +  unsigned long *flags)
> +{
> + unlock_task_sighand(ctx->tsk, flags);
> +}

Note that signalfd_put_sighand() doesn't need "sighand" parameter, please
see below.

> +int signalfd_deliver(struct sighand_struct *sighand, int sig,
> +  struct siginfo *info)
> +{
> + int nsig = 0;
> + struct signalfd_ctx *ctx, *tmp;
> +
> + list_for_each_entry_safe(ctx, tmp, >sfdlist, lnk) {
> + /*
> +  * We use a negative signal value as a way to broadcast that the
> +  * sighand has been orphaned, so that we can notify all the
> +  * listeners about this. Remeber the ctx->sigmask is inverted,
> +  * so if the user is interested in a signal, that corresponding
> +  * bit will be zero.
> +  */
> + if (sig < 0)
> + list_del_init(>lnk);

I'm afraid this is not right. This should be per-thread.

Suppose we have threads T1 and T2 from the same thread group. sighand->sfdlist
contains ctx1 and ctx2 "linked" to T1 and T2. Now, T1 exits, __exit_signal()
does signalfd_notify(sighand, -1), and "unlinks" all threads, not just T1.

IOW, we should do

if (ctx->tsk == current) {
list_del_init(>lnk);
wake_up(>wqh);
}

Perhaps it makes sense to not re-use signalfd_deliver(), but introduce
a new signalfd_xxx(sighand, tsk) helper for de_thread/exit_signal.

Btw, signalfd_deliver() doesn't use "info" parameter.

> + if (sig < 0 || !sigismember(>sigmask, sig)) {
> + wake_up(>wqh);

Minor nit. Perhaps it makes sense to do

void signalfd_deliver(struct task_struct *tsk, int sig, struct 
sigpending *pending)
{
struct sighand_struct *sighand = tsk->sighand;
int private = (tsk->pending == pending);

list_for_each_entry_safe(ctx, tmp, >sfdlist, lnk) {
if (private && ctx->tsk != tsk)
continue;
if (!sigismember(>sigmask, sig))
wake_up(>wqh);
}
}

Even better: signalfd_deliver(struct task_struct *tsk, int sig, int private).
This way specific_send_sig_info/send_sigqueue won't do a "false" wakeup.

> +asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t 
> sizemask)
> +{
> ...
> + if ((sighand = signalfd_get_sighand(ctx, )) != NULL) {
> + ctx->sigmask = sigmask;
> + signalfd_put_sighand(ctx, sighand, );
> + }

This looks like unneeded complication to me, I'd suggest

if (signalfd_get_sighand(ctx, )) {
ctx->sigmask = sigmask;
signalfd_put_sighand(ctx, flags);
}

unlock_task_sighand() (and thus signalfd_put_sighand) doesn't need "sighand"
parameter. signalfd_get_sighand() is in fact boolean. It makes sense to return
sighand, it may be useful, but this patch only needs != NULL.

Every usage of signalfd_get_sighand() could be simplified accordingly.

> --- linux-2.6.20.ep2.orig/fs/exec.c   2007-03-10 15:57:00.0 -0800
> +++ linux-2.6.20.ep2/fs/exec.c2007-03-10 15:57:51.0 -0800
> @@ -50,6 +50,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  
>  #include 
>  #include 
> @@ -583,6 +584,17 @@
>   int count;
>  
>   /*
> +  * Tell all the sighand listeners that this sighand has
> +  * been detached. Needs to be called with the sighand lock
> +  * held.
> +  */
> + if (unlikely(!list_empty(>sfdlist))) {
> + spin_lock_irq(>siglock);
> + signalfd_notify(oldsighand, -1, NULL);
> + spin_unlock_irq(>siglock);
> + }

Very minor nit. I'd suggest to make a new helper and put it in signalfd.h
(like signalfd_notify()). This will help CONFIG_SIGNALFD.

I still think that we should do this only for suid-exec. If application
passes a signalfd to another process with unix socket, it should know
what it does. But yes, I agree, we can change this later if needed.
(in that case the caller of the above helper should be flush_old_exec).

Oleg.

-
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 2/9] signalfd/timerfd - signalfd core ...

2007-03-11 Thread Oleg Nesterov
On 03/10, Davide Libenzi wrote:

 +static void signalfd_put_sighand(struct signalfd_ctx *ctx,
 +  struct sighand_struct *sighand,
 +  unsigned long *flags)
 +{
 + unlock_task_sighand(ctx-tsk, flags);
 +}

Note that signalfd_put_sighand() doesn't need sighand parameter, please
see below.

 +int signalfd_deliver(struct sighand_struct *sighand, int sig,
 +  struct siginfo *info)
 +{
 + int nsig = 0;
 + struct signalfd_ctx *ctx, *tmp;
 +
 + list_for_each_entry_safe(ctx, tmp, sighand-sfdlist, lnk) {
 + /*
 +  * We use a negative signal value as a way to broadcast that the
 +  * sighand has been orphaned, so that we can notify all the
 +  * listeners about this. Remeber the ctx-sigmask is inverted,
 +  * so if the user is interested in a signal, that corresponding
 +  * bit will be zero.
 +  */
 + if (sig  0)
 + list_del_init(ctx-lnk);

I'm afraid this is not right. This should be per-thread.

Suppose we have threads T1 and T2 from the same thread group. sighand-sfdlist
contains ctx1 and ctx2 linked to T1 and T2. Now, T1 exits, __exit_signal()
does signalfd_notify(sighand, -1), and unlinks all threads, not just T1.

IOW, we should do

if (ctx-tsk == current) {
list_del_init(ctx-lnk);
wake_up(ctx-wqh);
}

Perhaps it makes sense to not re-use signalfd_deliver(), but introduce
a new signalfd_xxx(sighand, tsk) helper for de_thread/exit_signal.

Btw, signalfd_deliver() doesn't use info parameter.

 + if (sig  0 || !sigismember(ctx-sigmask, sig)) {
 + wake_up(ctx-wqh);

Minor nit. Perhaps it makes sense to do

void signalfd_deliver(struct task_struct *tsk, int sig, struct 
sigpending *pending)
{
struct sighand_struct *sighand = tsk-sighand;
int private = (tsk-pending == pending);

list_for_each_entry_safe(ctx, tmp, sighand-sfdlist, lnk) {
if (private  ctx-tsk != tsk)
continue;
if (!sigismember(ctx-sigmask, sig))
wake_up(ctx-wqh);
}
}

Even better: signalfd_deliver(struct task_struct *tsk, int sig, int private).
This way specific_send_sig_info/send_sigqueue won't do a false wakeup.

 +asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t 
 sizemask)
 +{
 ...
 + if ((sighand = signalfd_get_sighand(ctx, flags)) != NULL) {
 + ctx-sigmask = sigmask;
 + signalfd_put_sighand(ctx, sighand, flags);
 + }

This looks like unneeded complication to me, I'd suggest

if (signalfd_get_sighand(ctx, flags)) {
ctx-sigmask = sigmask;
signalfd_put_sighand(ctx, flags);
}

unlock_task_sighand() (and thus signalfd_put_sighand) doesn't need sighand
parameter. signalfd_get_sighand() is in fact boolean. It makes sense to return
sighand, it may be useful, but this patch only needs != NULL.

Every usage of signalfd_get_sighand() could be simplified accordingly.

 --- linux-2.6.20.ep2.orig/fs/exec.c   2007-03-10 15:57:00.0 -0800
 +++ linux-2.6.20.ep2/fs/exec.c2007-03-10 15:57:51.0 -0800
 @@ -50,6 +50,7 @@
  #include linux/tsacct_kern.h
  #include linux/cn_proc.h
  #include linux/audit.h
 +#include linux/signalfd.h
  
  #include asm/uaccess.h
  #include asm/mmu_context.h
 @@ -583,6 +584,17 @@
   int count;
  
   /*
 +  * Tell all the sighand listeners that this sighand has
 +  * been detached. Needs to be called with the sighand lock
 +  * held.
 +  */
 + if (unlikely(!list_empty(oldsighand-sfdlist))) {
 + spin_lock_irq(oldsighand-siglock);
 + signalfd_notify(oldsighand, -1, NULL);
 + spin_unlock_irq(oldsighand-siglock);
 + }

Very minor nit. I'd suggest to make a new helper and put it in signalfd.h
(like signalfd_notify()). This will help CONFIG_SIGNALFD.

I still think that we should do this only for suid-exec. If application
passes a signalfd to another process with unix socket, it should know
what it does. But yes, I agree, we can change this later if needed.
(in that case the caller of the above helper should be flush_old_exec).

Oleg.

-
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 2/9] signalfd/timerfd - signalfd core ...

2007-03-11 Thread Davide Libenzi
On Sun, 11 Mar 2007, Oleg Nesterov wrote:

 On 03/10, Davide Libenzi wrote:
 
  +static void signalfd_put_sighand(struct signalfd_ctx *ctx,
  +struct sighand_struct *sighand,
  +unsigned long *flags)
  +{
  +   unlock_task_sighand(ctx-tsk, flags);
  +}
 
 Note that signalfd_put_sighand() doesn't need sighand parameter, please
 see below.

I want it to return the sighand, and for simmetry I prefer the put to be 
passed the parameter back too. Even if not used.



  +int signalfd_deliver(struct sighand_struct *sighand, int sig,
  +struct siginfo *info)
  +{
  +   int nsig = 0;
  +   struct signalfd_ctx *ctx, *tmp;
  +
  +   list_for_each_entry_safe(ctx, tmp, sighand-sfdlist, lnk) {
  +   /*
  +* We use a negative signal value as a way to broadcast that the
  +* sighand has been orphaned, so that we can notify all the
  +* listeners about this. Remeber the ctx-sigmask is inverted,
  +* so if the user is interested in a signal, that corresponding
  +* bit will be zero.
  +*/
  +   if (sig  0)
  +   list_del_init(ctx-lnk);
 
 I'm afraid this is not right. This should be per-thread.
 
 Suppose we have threads T1 and T2 from the same thread group. sighand-sfdlist
 contains ctx1 and ctx2 linked to T1 and T2. Now, T1 exits, __exit_signal()
 does signalfd_notify(sighand, -1), and unlinks all threads, not just T1.
 
 IOW, we should do
 
   if (ctx-tsk == current) {
   list_del_init(ctx-lnk);
   wake_up(ctx-wqh);
   }

Yes, of course. Dunno why the change got lost.



 Perhaps it makes sense to not re-use signalfd_deliver(), but introduce
 a new signalfd_xxx(sighand, tsk) helper for de_thread/exit_signal.
 
 Btw, signalfd_deliver() doesn't use info parameter.
 
  +   if (sig  0 || !sigismember(ctx-sigmask, sig)) {
  +   wake_up(ctx-wqh);
 
 Minor nit. Perhaps it makes sense to do
 
   void signalfd_deliver(struct task_struct *tsk, int sig, struct 
 sigpending *pending)
   {
   struct sighand_struct *sighand = tsk-sighand;
   int private = (tsk-pending == pending);
 
   list_for_each_entry_safe(ctx, tmp, sighand-sfdlist, lnk) {
   if (private  ctx-tsk != tsk)
   continue;
   if (!sigismember(ctx-sigmask, sig))
   wake_up(ctx-wqh);
   }
   }
 
 Even better: signalfd_deliver(struct task_struct *tsk, int sig, int private).
 This way specific_send_sig_info/send_sigqueue won't do a false wakeup.

I agree in the latter.



  +asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t 
  sizemask)
  +{
  ...
  +   if ((sighand = signalfd_get_sighand(ctx, flags)) != NULL) {
  +   ctx-sigmask = sigmask;
  +   signalfd_put_sighand(ctx, sighand, flags);
  +   }
 
 This looks like unneeded complication to me, I'd suggest
 
   if (signalfd_get_sighand(ctx, flags)) {
   ctx-sigmask = sigmask;
   signalfd_put_sighand(ctx, flags);
   }
 
 unlock_task_sighand() (and thus signalfd_put_sighand) doesn't need sighand
 parameter. signalfd_get_sighand() is in fact boolean. It makes sense to return
 sighand, it may be useful, but this patch only needs != NULL.
 
 Every usage of signalfd_get_sighand() could be simplified accordingly.

As I said before, I prefer that way.


  +* Tell all the sighand listeners that this sighand has
  +* been detached. Needs to be called with the sighand lock
  +* held.
  +*/
  +   if (unlikely(!list_empty(oldsighand-sfdlist))) {
  +   spin_lock_irq(oldsighand-siglock);
  +   signalfd_notify(oldsighand, -1, NULL);
  +   spin_unlock_irq(oldsighand-siglock);
  +   }
 
 Very minor nit. I'd suggest to make a new helper and put it in signalfd.h
 (like signalfd_notify()). This will help CONFIG_SIGNALFD.

Yes, makes sense.



- 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 2/9] signalfd/timerfd - signalfd core ...

2007-03-10 Thread Davide Libenzi
This patch series implements the new signalfd() system call.
I took part of the original Linus code (and you know how
badly it can be broken :), and I added even more breakage ;)
Signals are fetched from the same signal queue used by the process,
so signalfd will compete with standard kernel delivery in dequeue_signal().
If you want to reliably fetch signals on the signalfd file, you need to
block them with sigprocmask(SIG_BLOCK).
This seems to be working fine on my Dual Opteron machine. I made a quick 
test program for it:

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

The signalfd() system call implements signal delivery into a file 
descriptor receiver. The signalfd file descriptor if created with the 
following API:

int signalfd(int ufd, const sigset_t *mask, size_t masksize);

The "ufd" parameter allows to change an existing signalfd sigmask, w/out 
going to close/create cycle (Linus idea). Use "ufd" == -1 if you want a 
brand new signalfd file.
The "mask" allows to specify the signal mask of signals that we are 
interested in. The "masksize" parameter is the size of "mask".
The signalfd fd supports the poll(2) and read(2) system calls. The poll(2)
will return POLLIN when signals are available to be dequeued. As a direct
consequence of supporting the Linux poll subsystem, the signalfd fd can use
used together with epoll(2) too.
The read(2) system call will return a "struct signalfd_siginfo" structure
in the userspace supplied buffer. The return value is the number of bytes
copied in the supplied buffer, or -1 in case of error. The read(2) call
can also return 0, in case the sighand structure to which the signalfd
was attached, has been orphaned. The O_NONBLOCK flag is also supported, and
read(2) will return -EAGAIN in case no signal is available.
The format of the struct signalfd_siginfo is, and the valid fields depends
of the (->code & __SI_MASK) value, in the same way a struct siginfo would:

struct signalfd_siginfo {
__u32 signo;/* si_signo */
__s32 err;  /* si_errno */
__s32 code; /* si_code */
__u32 pid;  /* si_pid */
__u32 uid;  /* si_uid */
__s32 fd;   /* si_fd */
__u32 tid;  /* si_fd */
__u32 band; /* si_band */
__u32 overrun;  /* si_overrun */
__u32 trapno;   /* si_trapno */
__s32 status;   /* si_status */
__s32 svint;/* si_int */
__u64 svptr;/* si_ptr */
__u64 utime;/* si_utime */
__u64 stime;/* si_stime */
__u64 addr; /* si_addr */
};



Signed-off-by: Davide Libenzi 



- Davide



Index: linux-2.6.20.ep2/fs/signalfd.c
===
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6.20.ep2/fs/signalfd.c  2007-03-10 15:57:51.0 -0800
@@ -0,0 +1,381 @@
+/*
+ *  fs/signalfd.c
+ *
+ *  Copyright (C) 2003  Linus Torvalds
+ *
+ *  Mon Mar 5, 2007: Davide Libenzi 
+ *  Changed ->read() to return a siginfo strcture instead of signal number.
+ *  Fixed locking in ->poll().
+ *  Added sighand-detach notification.
+ *  Added fd re-use in sys_signalfd() syscall.
+ *  Now using anonymous inode source.
+ *  Thanks to Oleg Nesterov for useful code review and suggestions.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+
+
+struct signalfd_ctx {
+   struct list_head lnk;
+   wait_queue_head_t wqh;
+   sigset_t sigmask;
+   struct task_struct *tsk;
+};
+
+
+
+static struct sighand_struct *signalfd_get_sighand(struct signalfd_ctx *ctx,
+  unsigned long *flags);
+static void signalfd_put_sighand(struct signalfd_ctx *ctx,
+struct sighand_struct *sighand,
+unsigned long *flags);
+static void signalfd_cleanup(struct signalfd_ctx *ctx);
+static int signalfd_close(struct inode *inode, struct file *file);
+static unsigned int signalfd_poll(struct file *file, poll_table *wait);
+static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
+siginfo_t const *kinfo);
+static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
+loff_t *ppos);
+
+
+
+static const struct file_operations signalfd_fops = {
+   .release= signalfd_close,
+   .poll   = signalfd_poll,
+   .read   = signalfd_read,
+};
+static struct kmem_cache *signalfd_ctx_cachep;
+
+
+
+static struct sighand_struct *signalfd_get_sighand(struct signalfd_ctx *ctx,
+  unsigned long *flags)
+{
+   struct sighand_struct *sighand;
+
+   rcu_read_lock();
+   sighand = lock_task_sighand(ctx->tsk, flags);
+   rcu_read_unlock();
+
+   if (sighand && list_empty(>lnk)) {
+

[patch 2/9] signalfd/timerfd - signalfd core ...

2007-03-10 Thread Davide Libenzi
This patch series implements the new signalfd() system call.
I took part of the original Linus code (and you know how
badly it can be broken :), and I added even more breakage ;)
Signals are fetched from the same signal queue used by the process,
so signalfd will compete with standard kernel delivery in dequeue_signal().
If you want to reliably fetch signals on the signalfd file, you need to
block them with sigprocmask(SIG_BLOCK).
This seems to be working fine on my Dual Opteron machine. I made a quick 
test program for it:

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

The signalfd() system call implements signal delivery into a file 
descriptor receiver. The signalfd file descriptor if created with the 
following API:

int signalfd(int ufd, const sigset_t *mask, size_t masksize);

The ufd parameter allows to change an existing signalfd sigmask, w/out 
going to close/create cycle (Linus idea). Use ufd == -1 if you want a 
brand new signalfd file.
The mask allows to specify the signal mask of signals that we are 
interested in. The masksize parameter is the size of mask.
The signalfd fd supports the poll(2) and read(2) system calls. The poll(2)
will return POLLIN when signals are available to be dequeued. As a direct
consequence of supporting the Linux poll subsystem, the signalfd fd can use
used together with epoll(2) too.
The read(2) system call will return a struct signalfd_siginfo structure
in the userspace supplied buffer. The return value is the number of bytes
copied in the supplied buffer, or -1 in case of error. The read(2) call
can also return 0, in case the sighand structure to which the signalfd
was attached, has been orphaned. The O_NONBLOCK flag is also supported, and
read(2) will return -EAGAIN in case no signal is available.
The format of the struct signalfd_siginfo is, and the valid fields depends
of the (-code  __SI_MASK) value, in the same way a struct siginfo would:

struct signalfd_siginfo {
__u32 signo;/* si_signo */
__s32 err;  /* si_errno */
__s32 code; /* si_code */
__u32 pid;  /* si_pid */
__u32 uid;  /* si_uid */
__s32 fd;   /* si_fd */
__u32 tid;  /* si_fd */
__u32 band; /* si_band */
__u32 overrun;  /* si_overrun */
__u32 trapno;   /* si_trapno */
__s32 status;   /* si_status */
__s32 svint;/* si_int */
__u64 svptr;/* si_ptr */
__u64 utime;/* si_utime */
__u64 stime;/* si_stime */
__u64 addr; /* si_addr */
};



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



- Davide



Index: linux-2.6.20.ep2/fs/signalfd.c
===
--- /dev/null   1970-01-01 00:00:00.0 +
+++ linux-2.6.20.ep2/fs/signalfd.c  2007-03-10 15:57:51.0 -0800
@@ -0,0 +1,381 @@
+/*
+ *  fs/signalfd.c
+ *
+ *  Copyright (C) 2003  Linus Torvalds
+ *
+ *  Mon Mar 5, 2007: Davide Libenzi davidel@xmailserver.org
+ *  Changed -read() to return a siginfo strcture instead of signal number.
+ *  Fixed locking in -poll().
+ *  Added sighand-detach notification.
+ *  Added fd re-use in sys_signalfd() syscall.
+ *  Now using anonymous inode source.
+ *  Thanks to Oleg Nesterov for useful code review and suggestions.
+ */
+
+#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/anon_inodes.h
+#include linux/signalfd.h
+
+#include asm/uaccess.h
+
+
+
+struct signalfd_ctx {
+   struct list_head lnk;
+   wait_queue_head_t wqh;
+   sigset_t sigmask;
+   struct task_struct *tsk;
+};
+
+
+
+static struct sighand_struct *signalfd_get_sighand(struct signalfd_ctx *ctx,
+  unsigned long *flags);
+static void signalfd_put_sighand(struct signalfd_ctx *ctx,
+struct sighand_struct *sighand,
+unsigned long *flags);
+static void signalfd_cleanup(struct signalfd_ctx *ctx);
+static int signalfd_close(struct inode *inode, struct file *file);
+static unsigned int signalfd_poll(struct file *file, poll_table *wait);
+static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
+siginfo_t const *kinfo);
+static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
+loff_t *ppos);
+
+
+
+static const struct file_operations signalfd_fops = {
+   .release= signalfd_close,
+   .poll   = signalfd_poll,
+   .read   = signalfd_read,
+};
+static struct kmem_cache *signalfd_ctx_cachep;
+
+
+
+static struct sighand_struct *signalfd_get_sighand(struct signalfd_ctx *ctx,
+  unsigned long *flags)