aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorDavide Libenzi <davidel@xmailserver.org>2007-05-11 01:23:13 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-11 11:29:36 -0400
commitfba2afaaec790dc5ab4ae8827972f342211bbb86 (patch)
tree2694d4cd8c6b7d69a5569b92151d61a3d4af39b7 /kernel
parent5dc8bf8132d59c03fe2562bce165c2f03f021687 (diff)
signal/timer/event: signalfd core
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. If the size of the buffer passed to read(2) is lower than sizeof(struct signalfd_siginfo), -EINVAL is returned. A read from the signalfd can also return -ERESTARTSYS in case a signal hits the process. 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 */ }; [akpm@linux-foundation.org: fix signalfd_copyinfo() on i386] Signed-off-by: Davide Libenzi <davidel@xmailserver.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/exit.c9
-rw-r--r--kernel/fork.c8
-rw-r--r--kernel/signal.c22
-rw-r--r--kernel/sys_ni.c3
4 files changed, 37 insertions, 5 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index e93691e9b325..c6d14b8008dd 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -24,6 +24,7 @@
24#include <linux/pid_namespace.h> 24#include <linux/pid_namespace.h>
25#include <linux/ptrace.h> 25#include <linux/ptrace.h>
26#include <linux/profile.h> 26#include <linux/profile.h>
27#include <linux/signalfd.h>
27#include <linux/mount.h> 28#include <linux/mount.h>
28#include <linux/proc_fs.h> 29#include <linux/proc_fs.h>
29#include <linux/kthread.h> 30#include <linux/kthread.h>
@@ -83,6 +84,14 @@ static void __exit_signal(struct task_struct *tsk)
83 sighand = rcu_dereference(tsk->sighand); 84 sighand = rcu_dereference(tsk->sighand);
84 spin_lock(&sighand->siglock); 85 spin_lock(&sighand->siglock);
85 86
87 /*
88 * Notify that this sighand has been detached. This must
89 * be called with the tsk->sighand lock held. Also, this
90 * access tsk->sighand internally, so it must be called
91 * before tsk->sighand is reset.
92 */
93 signalfd_detach_locked(tsk);
94
86 posix_cpu_timers_exit(tsk); 95 posix_cpu_timers_exit(tsk);
87 if (atomic_dec_and_test(&sig->count)) 96 if (atomic_dec_and_test(&sig->count))
88 posix_cpu_timers_exit_group(tsk); 97 posix_cpu_timers_exit_group(tsk);
diff --git a/kernel/fork.c b/kernel/fork.c
index 083bf8953ce8..49530e40ea8b 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1422,12 +1422,15 @@ long do_fork(unsigned long clone_flags,
1422#define ARCH_MIN_MMSTRUCT_ALIGN 0 1422#define ARCH_MIN_MMSTRUCT_ALIGN 0
1423#endif 1423#endif
1424 1424
1425static void sighand_ctor(void *data, struct kmem_cache *cachep, unsigned long flags) 1425static void sighand_ctor(void *data, struct kmem_cache *cachep,
1426 unsigned long flags)
1426{ 1427{
1427 struct sighand_struct *sighand = data; 1428 struct sighand_struct *sighand = data;
1428 1429
1429 if (flags & SLAB_CTOR_CONSTRUCTOR) 1430 if (flags & SLAB_CTOR_CONSTRUCTOR) {
1430 spin_lock_init(&sighand->siglock); 1431 spin_lock_init(&sighand->siglock);
1432 INIT_LIST_HEAD(&sighand->signalfd_list);
1433 }
1431} 1434}
1432 1435
1433void __init proc_caches_init(void) 1436void __init proc_caches_init(void)
@@ -1453,7 +1456,6 @@ void __init proc_caches_init(void)
1453 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); 1456 SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
1454} 1457}
1455 1458
1456
1457/* 1459/*
1458 * Check constraints on flags passed to the unshare system call and 1460 * Check constraints on flags passed to the unshare system call and
1459 * force unsharing of additional process context as appropriate. 1461 * force unsharing of additional process context as appropriate.
diff --git a/kernel/signal.c b/kernel/signal.c
index 2ac3a668d9dd..34b7d6abce8f 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -21,6 +21,7 @@
21#include <linux/syscalls.h> 21#include <linux/syscalls.h>
22#include <linux/ptrace.h> 22#include <linux/ptrace.h>
23#include <linux/signal.h> 23#include <linux/signal.h>
24#include <linux/signalfd.h>
24#include <linux/capability.h> 25#include <linux/capability.h>
25#include <linux/freezer.h> 26#include <linux/freezer.h>
26#include <linux/pid_namespace.h> 27#include <linux/pid_namespace.h>
@@ -113,8 +114,7 @@ void recalc_sigpending(void)
113 114
114/* Given the mask, find the first available signal that should be serviced. */ 115/* Given the mask, find the first available signal that should be serviced. */
115 116
116static int 117int next_signal(struct sigpending *pending, sigset_t *mask)
117next_signal(struct sigpending *pending, sigset_t *mask)
118{ 118{
119 unsigned long i, *s, *m, x; 119 unsigned long i, *s, *m, x;
120 int sig = 0; 120 int sig = 0;
@@ -630,6 +630,12 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,
630 int ret = 0; 630 int ret = 0;
631 631
632 /* 632 /*
633 * Deliver the signal to listening signalfds. This must be called
634 * with the sighand lock held.
635 */
636 signalfd_notify(t, sig);
637
638 /*
633 * fast-pathed signals for kernel-internal things like SIGSTOP 639 * fast-pathed signals for kernel-internal things like SIGSTOP
634 * or SIGKILL. 640 * or SIGKILL.
635 */ 641 */
@@ -1280,6 +1286,11 @@ int send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
1280 ret = 1; 1286 ret = 1;
1281 goto out; 1287 goto out;
1282 } 1288 }
1289 /*
1290 * Deliver the signal to listening signalfds. This must be called
1291 * with the sighand lock held.
1292 */
1293 signalfd_notify(p, sig);
1283 1294
1284 list_add_tail(&q->list, &p->pending.list); 1295 list_add_tail(&q->list, &p->pending.list);
1285 sigaddset(&p->pending.signal, sig); 1296 sigaddset(&p->pending.signal, sig);
@@ -1323,6 +1334,11 @@ send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p)
1323 q->info.si_overrun++; 1334 q->info.si_overrun++;
1324 goto out; 1335 goto out;
1325 } 1336 }
1337 /*
1338 * Deliver the signal to listening signalfds. This must be called
1339 * with the sighand lock held.
1340 */
1341 signalfd_notify(p, sig);
1326 1342
1327 /* 1343 /*
1328 * Put this signal on the shared-pending queue. 1344 * Put this signal on the shared-pending queue.
@@ -1983,6 +1999,8 @@ int copy_siginfo_to_user(siginfo_t __user *to, siginfo_t *from)
1983 /* 1999 /*
1984 * If you change siginfo_t structure, please be sure 2000 * If you change siginfo_t structure, please be sure
1985 * this code is fixed accordingly. 2001 * this code is fixed accordingly.
2002 * Please remember to update the signalfd_copyinfo() function
2003 * inside fs/signalfd.c too, in case siginfo_t changes.
1986 * It should never copy any pad contained in the structure 2004 * It should never copy any pad contained in the structure
1987 * to avoid security leaks, but must copy the generic 2005 * to avoid security leaks, but must copy the generic
1988 * 3 ints plus the relevant union member. 2006 * 3 ints plus the relevant union member.
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index d7306d0f3dfc..807e9bb8fcdb 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -141,3 +141,6 @@ cond_syscall(compat_sys_migrate_pages);
141cond_syscall(sys_bdflush); 141cond_syscall(sys_bdflush);
142cond_syscall(sys_ioprio_set); 142cond_syscall(sys_ioprio_set);
143cond_syscall(sys_ioprio_get); 143cond_syscall(sys_ioprio_get);
144
145/* New file descriptors */
146cond_syscall(sys_signalfd);