aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
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 /include/linux
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 'include/linux')
-rw-r--r--include/linux/Kbuild1
-rw-r--r--include/linux/init_task.h1
-rw-r--r--include/linux/sched.h1
-rw-r--r--include/linux/signal.h1
-rw-r--r--include/linux/signalfd.h97
-rw-r--r--include/linux/syscalls.h1
6 files changed, 102 insertions, 0 deletions
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 645b3b528150..bcd01f269f60 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -190,6 +190,7 @@ unifdef-y += errno.h
190unifdef-y += errqueue.h 190unifdef-y += errqueue.h
191unifdef-y += ethtool.h 191unifdef-y += ethtool.h
192unifdef-y += eventpoll.h 192unifdef-y += eventpoll.h
193unifdef-y += signalfd.h
193unifdef-y += ext2_fs.h 194unifdef-y += ext2_fs.h
194unifdef-y += ext3_fs.h 195unifdef-y += ext3_fs.h
195unifdef-y += fb.h 196unifdef-y += fb.h
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 66e2f0a70814..276ccaa2670c 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -84,6 +84,7 @@ extern struct nsproxy init_nsproxy;
84 .count = ATOMIC_INIT(1), \ 84 .count = ATOMIC_INIT(1), \
85 .action = { { { .sa_handler = NULL, } }, }, \ 85 .action = { { { .sa_handler = NULL, } }, }, \
86 .siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \ 86 .siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \
87 .signalfd_list = LIST_HEAD_INIT(sighand.signalfd_list), \
87} 88}
88 89
89extern struct group_info init_groups; 90extern struct group_info init_groups;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 75f44379b7e9..97c0c7da58ef 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -391,6 +391,7 @@ struct sighand_struct {
391 atomic_t count; 391 atomic_t count;
392 struct k_sigaction action[_NSIG]; 392 struct k_sigaction action[_NSIG];
393 spinlock_t siglock; 393 spinlock_t siglock;
394 struct list_head signalfd_list;
394}; 395};
395 396
396struct pacct_struct { 397struct pacct_struct {
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 3fa0fab4a04b..9a5eac508e5e 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -233,6 +233,7 @@ static inline int valid_signal(unsigned long sig)
233 return sig <= _NSIG ? 1 : 0; 233 return sig <= _NSIG ? 1 : 0;
234} 234}
235 235
236extern int next_signal(struct sigpending *pending, sigset_t *mask);
236extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p); 237extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p);
237extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); 238extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
238extern long do_sigpending(void __user *, unsigned long); 239extern long do_sigpending(void __user *, unsigned long);
diff --git a/include/linux/signalfd.h b/include/linux/signalfd.h
new file mode 100644
index 000000000000..510429495690
--- /dev/null
+++ b/include/linux/signalfd.h
@@ -0,0 +1,97 @@
1/*
2 * include/linux/signalfd.h
3 *
4 * Copyright (C) 2007 Davide Libenzi <davidel@xmailserver.org>
5 *
6 */
7
8#ifndef _LINUX_SIGNALFD_H
9#define _LINUX_SIGNALFD_H
10
11
12struct signalfd_siginfo {
13 __u32 signo;
14 __s32 err;
15 __s32 code;
16 __u32 pid;
17 __u32 uid;
18 __s32 fd;
19 __u32 tid;
20 __u32 band;
21 __u32 overrun;
22 __u32 trapno;
23 __s32 status;
24 __s32 svint;
25 __u64 svptr;
26 __u64 utime;
27 __u64 stime;
28 __u64 addr;
29
30 /*
31 * Pad strcture to 128 bytes. Remember to update the
32 * pad size when you add new memebers. We use a fixed
33 * size structure to avoid compatibility problems with
34 * future versions, and we leave extra space for additional
35 * members. We use fixed size members because this strcture
36 * comes out of a read(2) and we really don't want to have
37 * a compat on read(2).
38 */
39 __u8 __pad[48];
40};
41
42
43#ifdef __KERNEL__
44
45#ifdef CONFIG_SIGNALFD
46
47/*
48 * Deliver the signal to listening signalfd. This must be called
49 * with the sighand lock held. Same are the following that end up
50 * calling signalfd_deliver().
51 */
52void signalfd_deliver(struct task_struct *tsk, int sig);
53
54/*
55 * No need to fall inside signalfd_deliver() if no signal listeners
56 * are available.
57 */
58static inline void signalfd_notify(struct task_struct *tsk, int sig)
59{
60 if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
61 signalfd_deliver(tsk, sig);
62}
63
64/*
65 * The signal -1 is used to notify the signalfd that the sighand
66 * is on its way to be detached.
67 */
68static inline void signalfd_detach_locked(struct task_struct *tsk)
69{
70 if (unlikely(!list_empty(&tsk->sighand->signalfd_list)))
71 signalfd_deliver(tsk, -1);
72}
73
74static inline void signalfd_detach(struct task_struct *tsk)
75{
76 struct sighand_struct *sighand = tsk->sighand;
77
78 if (unlikely(!list_empty(&sighand->signalfd_list))) {
79 spin_lock_irq(&sighand->siglock);
80 signalfd_deliver(tsk, -1);
81 spin_unlock_irq(&sighand->siglock);
82 }
83}
84
85#else /* CONFIG_SIGNALFD */
86
87#define signalfd_deliver(t, s) do { } while (0)
88#define signalfd_notify(t, s) do { } while (0)
89#define signalfd_detach_locked(t) do { } while (0)
90#define signalfd_detach(t) do { } while (0)
91
92#endif /* CONFIG_SIGNALFD */
93
94#endif /* __KERNEL__ */
95
96#endif /* _LINUX_SIGNALFD_H */
97
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 3139f4412297..e049f14a75b7 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -604,6 +604,7 @@ asmlinkage long sys_get_robust_list(int pid,
604asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, 604asmlinkage long sys_set_robust_list(struct robust_list_head __user *head,
605 size_t len); 605 size_t len);
606asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); 606asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
607asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask);
607 608
608int kernel_execve(const char *filename, char *const argv[], char *const envp[]); 609int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
609 610