aboutsummaryrefslogtreecommitdiffstats
path: root/fs
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 /fs
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 'fs')
-rw-r--r--fs/Makefile1
-rw-r--r--fs/exec.c11
-rw-r--r--fs/signalfd.c349
3 files changed, 359 insertions, 2 deletions
diff --git a/fs/Makefile b/fs/Makefile
index b5cd46a88cb0..cd8a57aeac04 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_INOTIFY) += inotify.o
23obj-$(CONFIG_INOTIFY_USER) += inotify_user.o 23obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
24obj-$(CONFIG_EPOLL) += eventpoll.o 24obj-$(CONFIG_EPOLL) += eventpoll.o
25obj-$(CONFIG_ANON_INODES) += anon_inodes.o 25obj-$(CONFIG_ANON_INODES) += anon_inodes.o
26obj-$(CONFIG_SIGNALFD) += signalfd.o
26obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o 27obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o
27 28
28nfsd-$(CONFIG_NFSD) := nfsctl.o 29nfsd-$(CONFIG_NFSD) := nfsctl.o
diff --git a/fs/exec.c b/fs/exec.c
index 2255dc72deef..955a8eb66d70 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -50,6 +50,7 @@
50#include <linux/tsacct_kern.h> 50#include <linux/tsacct_kern.h>
51#include <linux/cn_proc.h> 51#include <linux/cn_proc.h>
52#include <linux/audit.h> 52#include <linux/audit.h>
53#include <linux/signalfd.h>
53 54
54#include <asm/uaccess.h> 55#include <asm/uaccess.h>
55#include <asm/mmu_context.h> 56#include <asm/mmu_context.h>
@@ -582,6 +583,13 @@ static int de_thread(struct task_struct *tsk)
582 int count; 583 int count;
583 584
584 /* 585 /*
586 * Tell all the sighand listeners that this sighand has
587 * been detached. The signalfd_detach() function grabs the
588 * sighand lock, if signal listeners are present on the sighand.
589 */
590 signalfd_detach(tsk);
591
592 /*
585 * If we don't share sighandlers, then we aren't sharing anything 593 * If we don't share sighandlers, then we aren't sharing anything
586 * and we can just re-use it all. 594 * and we can just re-use it all.
587 */ 595 */
@@ -757,8 +765,7 @@ no_thread_group:
757 spin_unlock(&oldsighand->siglock); 765 spin_unlock(&oldsighand->siglock);
758 write_unlock_irq(&tasklist_lock); 766 write_unlock_irq(&tasklist_lock);
759 767
760 if (atomic_dec_and_test(&oldsighand->count)) 768 __cleanup_sighand(oldsighand);
761 kmem_cache_free(sighand_cachep, oldsighand);
762 } 769 }
763 770
764 BUG_ON(!thread_group_leader(tsk)); 771 BUG_ON(!thread_group_leader(tsk));
diff --git a/fs/signalfd.c b/fs/signalfd.c
new file mode 100644
index 000000000000..7cfeab412b45
--- /dev/null
+++ b/fs/signalfd.c
@@ -0,0 +1,349 @@
1/*
2 * fs/signalfd.c
3 *
4 * Copyright (C) 2003 Linus Torvalds
5 *
6 * Mon Mar 5, 2007: Davide Libenzi <davidel@xmailserver.org>
7 * Changed ->read() to return a siginfo strcture instead of signal number.
8 * Fixed locking in ->poll().
9 * Added sighand-detach notification.
10 * Added fd re-use in sys_signalfd() syscall.
11 * Now using anonymous inode source.
12 * Thanks to Oleg Nesterov for useful code review and suggestions.
13 * More comments and suggestions from Arnd Bergmann.
14 */
15
16#include <linux/file.h>
17#include <linux/poll.h>
18#include <linux/init.h>
19#include <linux/fs.h>
20#include <linux/sched.h>
21#include <linux/kernel.h>
22#include <linux/signal.h>
23#include <linux/list.h>
24#include <linux/anon_inodes.h>
25#include <linux/signalfd.h>
26
27struct signalfd_ctx {
28 struct list_head lnk;
29 wait_queue_head_t wqh;
30 sigset_t sigmask;
31 struct task_struct *tsk;
32};
33
34struct signalfd_lockctx {
35 struct task_struct *tsk;
36 unsigned long flags;
37};
38
39/*
40 * Tries to acquire the sighand lock. We do not increment the sighand
41 * use count, and we do not even pin the task struct, so we need to
42 * do it inside an RCU read lock, and we must be prepared for the
43 * ctx->tsk going to NULL (in signalfd_deliver()), and for the sighand
44 * being detached. We return 0 if the sighand has been detached, or
45 * 1 if we were able to pin the sighand lock.
46 */
47static int signalfd_lock(struct signalfd_ctx *ctx, struct signalfd_lockctx *lk)
48{
49 struct sighand_struct *sighand = NULL;
50
51 rcu_read_lock();
52 lk->tsk = rcu_dereference(ctx->tsk);
53 if (likely(lk->tsk != NULL))
54 sighand = lock_task_sighand(lk->tsk, &lk->flags);
55 rcu_read_unlock();
56
57 if (sighand && !ctx->tsk) {
58 unlock_task_sighand(lk->tsk, &lk->flags);
59 sighand = NULL;
60 }
61
62 return sighand != NULL;
63}
64
65static void signalfd_unlock(struct signalfd_lockctx *lk)
66{
67 unlock_task_sighand(lk->tsk, &lk->flags);
68}
69
70/*
71 * This must be called with the sighand lock held.
72 */
73void signalfd_deliver(struct task_struct *tsk, int sig)
74{
75 struct sighand_struct *sighand = tsk->sighand;
76 struct signalfd_ctx *ctx, *tmp;
77
78 BUG_ON(!sig);
79 list_for_each_entry_safe(ctx, tmp, &sighand->signalfd_list, lnk) {
80 /*
81 * We use a negative signal value as a way to broadcast that the
82 * sighand has been orphaned, so that we can notify all the
83 * listeners about this. Remember the ctx->sigmask is inverted,
84 * so if the user is interested in a signal, that corresponding
85 * bit will be zero.
86 */
87 if (sig < 0) {
88 if (ctx->tsk == tsk) {
89 ctx->tsk = NULL;
90 list_del_init(&ctx->lnk);
91 wake_up(&ctx->wqh);
92 }
93 } else {
94 if (!sigismember(&ctx->sigmask, sig))
95 wake_up(&ctx->wqh);
96 }
97 }
98}
99
100static void signalfd_cleanup(struct signalfd_ctx *ctx)
101{
102 struct signalfd_lockctx lk;
103
104 /*
105 * This is tricky. If the sighand is gone, we do not need to remove
106 * context from the list, the list itself won't be there anymore.
107 */
108 if (signalfd_lock(ctx, &lk)) {
109 list_del(&ctx->lnk);
110 signalfd_unlock(&lk);
111 }
112 kfree(ctx);
113}
114
115static int signalfd_release(struct inode *inode, struct file *file)
116{
117 signalfd_cleanup(file->private_data);
118 return 0;
119}
120
121static unsigned int signalfd_poll(struct file *file, poll_table *wait)
122{
123 struct signalfd_ctx *ctx = file->private_data;
124 unsigned int events = 0;
125 struct signalfd_lockctx lk;
126
127 poll_wait(file, &ctx->wqh, wait);
128
129 /*
130 * Let the caller get a POLLIN in this case, ala socket recv() when
131 * the peer disconnects.
132 */
133 if (signalfd_lock(ctx, &lk)) {
134 if (next_signal(&lk.tsk->pending, &ctx->sigmask) > 0 ||
135 next_signal(&lk.tsk->signal->shared_pending,
136 &ctx->sigmask) > 0)
137 events |= POLLIN;
138 signalfd_unlock(&lk);
139 } else
140 events |= POLLIN;
141
142 return events;
143}
144
145/*
146 * Copied from copy_siginfo_to_user() in kernel/signal.c
147 */
148static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
149 siginfo_t const *kinfo)
150{
151 long err;
152
153 BUILD_BUG_ON(sizeof(struct signalfd_siginfo) != 128);
154
155 /*
156 * Unused memebers should be zero ...
157 */
158 err = __clear_user(uinfo, sizeof(*uinfo));
159
160 /*
161 * If you change siginfo_t structure, please be sure
162 * this code is fixed accordingly.
163 */
164 err |= __put_user(kinfo->si_signo, &uinfo->signo);
165 err |= __put_user(kinfo->si_errno, &uinfo->err);
166 err |= __put_user((short)kinfo->si_code, &uinfo->code);
167 switch (kinfo->si_code & __SI_MASK) {
168 case __SI_KILL:
169 err |= __put_user(kinfo->si_pid, &uinfo->pid);
170 err |= __put_user(kinfo->si_uid, &uinfo->uid);
171 break;
172 case __SI_TIMER:
173 err |= __put_user(kinfo->si_tid, &uinfo->tid);
174 err |= __put_user(kinfo->si_overrun, &uinfo->overrun);
175 err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr);
176 break;
177 case __SI_POLL:
178 err |= __put_user(kinfo->si_band, &uinfo->band);
179 err |= __put_user(kinfo->si_fd, &uinfo->fd);
180 break;
181 case __SI_FAULT:
182 err |= __put_user((long)kinfo->si_addr, &uinfo->addr);
183#ifdef __ARCH_SI_TRAPNO
184 err |= __put_user(kinfo->si_trapno, &uinfo->trapno);
185#endif
186 break;
187 case __SI_CHLD:
188 err |= __put_user(kinfo->si_pid, &uinfo->pid);
189 err |= __put_user(kinfo->si_uid, &uinfo->uid);
190 err |= __put_user(kinfo->si_status, &uinfo->status);
191 err |= __put_user(kinfo->si_utime, &uinfo->utime);
192 err |= __put_user(kinfo->si_stime, &uinfo->stime);
193 break;
194 case __SI_RT: /* This is not generated by the kernel as of now. */
195 case __SI_MESGQ: /* But this is */
196 err |= __put_user(kinfo->si_pid, &uinfo->pid);
197 err |= __put_user(kinfo->si_uid, &uinfo->uid);
198 err |= __put_user((long)kinfo->si_ptr, &uinfo->svptr);
199 break;
200 default: /* this is just in case for now ... */
201 err |= __put_user(kinfo->si_pid, &uinfo->pid);
202 err |= __put_user(kinfo->si_uid, &uinfo->uid);
203 break;
204 }
205
206 return err ? -EFAULT: sizeof(*uinfo);
207}
208
209/*
210 * Returns either the size of a "struct signalfd_siginfo", or zero if the
211 * sighand we are attached to, has been orphaned. The "count" parameter
212 * must be at least the size of a "struct signalfd_siginfo".
213 */
214static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
215 loff_t *ppos)
216{
217 struct signalfd_ctx *ctx = file->private_data;
218 ssize_t res = 0;
219 int locked, signo;
220 siginfo_t info;
221 struct signalfd_lockctx lk;
222 DECLARE_WAITQUEUE(wait, current);
223
224 if (count < sizeof(struct signalfd_siginfo))
225 return -EINVAL;
226 locked = signalfd_lock(ctx, &lk);
227 if (!locked)
228 return 0;
229 res = -EAGAIN;
230 signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
231 if (signo == 0 && !(file->f_flags & O_NONBLOCK)) {
232 add_wait_queue(&ctx->wqh, &wait);
233 for (;;) {
234 set_current_state(TASK_INTERRUPTIBLE);
235 signo = dequeue_signal(lk.tsk, &ctx->sigmask, &info);
236 if (signo != 0)
237 break;
238 if (signal_pending(current)) {
239 res = -ERESTARTSYS;
240 break;
241 }
242 signalfd_unlock(&lk);
243 schedule();
244 locked = signalfd_lock(ctx, &lk);
245 if (unlikely(!locked)) {
246 /*
247 * Let the caller read zero byte, ala socket
248 * recv() when the peer disconnect. This test
249 * must be done before doing a dequeue_signal(),
250 * because if the sighand has been orphaned,
251 * the dequeue_signal() call is going to crash.
252 */
253 res = 0;
254 break;
255 }
256 }
257 remove_wait_queue(&ctx->wqh, &wait);
258 __set_current_state(TASK_RUNNING);
259 }
260 if (likely(locked))
261 signalfd_unlock(&lk);
262 if (likely(signo))
263 res = signalfd_copyinfo((struct signalfd_siginfo __user *) buf,
264 &info);
265
266 return res;
267}
268
269static const struct file_operations signalfd_fops = {
270 .release = signalfd_release,
271 .poll = signalfd_poll,
272 .read = signalfd_read,
273};
274
275/*
276 * Create a file descriptor that is associated with our signal
277 * state. We can pass it around to others if we want to, but
278 * it will always be _our_ signal state.
279 */
280asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask)
281{
282 int error;
283 sigset_t sigmask;
284 struct signalfd_ctx *ctx;
285 struct sighand_struct *sighand;
286 struct file *file;
287 struct inode *inode;
288 struct signalfd_lockctx lk;
289
290 if (sizemask != sizeof(sigset_t) ||
291 copy_from_user(&sigmask, user_mask, sizeof(sigmask)))
292 return error = -EINVAL;
293 sigdelsetmask(&sigmask, sigmask(SIGKILL) | sigmask(SIGSTOP));
294 signotset(&sigmask);
295
296 if (ufd == -1) {
297 ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
298 if (!ctx)
299 return -ENOMEM;
300
301 init_waitqueue_head(&ctx->wqh);
302 ctx->sigmask = sigmask;
303 ctx->tsk = current;
304
305 sighand = current->sighand;
306 /*
307 * Add this fd to the list of signal listeners.
308 */
309 spin_lock_irq(&sighand->siglock);
310 list_add_tail(&ctx->lnk, &sighand->signalfd_list);
311 spin_unlock_irq(&sighand->siglock);
312
313 /*
314 * When we call this, the initialization must be complete, since
315 * anon_inode_getfd() will install the fd.
316 */
317 error = anon_inode_getfd(&ufd, &inode, &file, "[signalfd]",
318 &signalfd_fops, ctx);
319 if (error)
320 goto err_fdalloc;
321 } else {
322 file = fget(ufd);
323 if (!file)
324 return -EBADF;
325 ctx = file->private_data;
326 if (file->f_op != &signalfd_fops) {
327 fput(file);
328 return -EINVAL;
329 }
330 /*
331 * We need to be prepared of the fact that the sighand this fd
332 * is attached to, has been detched. In that case signalfd_lock()
333 * will return 0, and we'll just skip setting the new mask.
334 */
335 if (signalfd_lock(ctx, &lk)) {
336 ctx->sigmask = sigmask;
337 signalfd_unlock(&lk);
338 }
339 wake_up(&ctx->wqh);
340 fput(file);
341 }
342
343 return ufd;
344
345err_fdalloc:
346 signalfd_cleanup(ctx);
347 return error;
348}
349