eventfs: pseudo fs which allows to bind events to file descriptors.
Subsystems (5)
PATCH 1/1 eventfs: pseudo fs which allows to bind events to file descriptors.
Hello.
This pseudo fs allows to bind a file descriptor to different kinds of events, which allows to poll them using epoll().
This particular morning hack supports signals only.
If idea is supposed to be right, I can cook up POSIX timers support.
Signal delivery note.
If special flag is set in signalfd(signo, flag), then signals are _not_ delivered through pending mask update but only through epoll queue. (Copied from kevent).
Userspace signal code and patch itself can be found at:
http://tservice.net.ru/~s0mbre/archive/eventfs/
signal.c is also attached for interested reader.
arch/i386/kernel/syscall_table.S +1 -0
@@ -319,3 +319,4 @@ ENTRY(sys_call_table) .long sys_move_pages .long sys_getcpu .long sys_epoll_pwait + .long sys_signalfd /* 320 */
arch/x86_64/ia32/ia32entry.S +1 -0
@@ -719,4 +719,5 @@ ia32_sys_call_table: .quad compat_sys_move_pages .quad sys_getcpu .quad sys_epoll_pwait + .quad sys_signalfd ia32_syscall_end:
fs/Kconfig +9 -0
@@ -1032,6 +1032,15 @@ config CONFIGFS_FS Both sysfs and configfs can and should exist together on the same system. One is not a replacement for the other. +config EVENTFS + bool "Enable eventpoll filesystem support" if EMBEDDED + depends on EPOLL + default y + help + Allows to bind file descriptors to different kinds of objects + like signals and timers and work with them using epoll + family of system calls. + endmenu menu "Miscellaneous filesystems"
fs/Makefile +1 -0
@@ -22,6 +22,7 @@ endif obj-$(CONFIG_INOTIFY) += inotify.o obj-$(CONFIG_INOTIFY_USER) += inotify_user.o obj-$(CONFIG_EPOLL) += eventpoll.o +obj-$(CONFIG_EVENTFS) += eventfs.o obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o nfsd-$(CONFIG_NFSD) := nfsctl.o
fs/eventfs.c new file +221 -0
221 lines not on this page · raw message
include/asm-i386/unistd.h +2 -1
@@ -325,10 +325,11 @@#define __NR_move_pages 317#define __NR_getcpu 318#define __NR_epoll_pwait 319 +#define __NR_signalfd 320#ifdef __KERNEL__ -#define NR_syscalls 320 +#define NR_syscalls 321#define __ARCH_WANT_IPC_PARSE_VERSION#define __ARCH_WANT_OLD_READDIR
include/asm-x86_64/unistd.h +3 -1
@@ -619,8 +619,10 @@ __SYSCALL(__NR_sync_file_range, sys_sync_file_range) __SYSCALL(__NR_vmsplice, sys_vmsplice)#define __NR_move_pages 279 __SYSCALL(__NR_move_pages, sys_move_pages) +#define __NR_signalfd 280 +__SYSCALL(__NR_signalfd, sys_signalfd) -#define __NR_syscall_max __NR_move_pages +#define __NR_syscall_max __NR_signalfd#ifndef __NO_STUBS#define __ARCH_WANT_OLD_READDIR
include/linux/sched.h +4 -0
@@ -935,6 +935,10 @@ struct task_struct {/* signal handlers */ struct signal_struct *signal;struct sighand_struct *sighand; +#ifdef CONFIG_EVENTFS +struct file *signal_file[_NSIG]; +wait_queue_head_t signal_wait; +#endif sigset_t blocked, real_blocked;sigset_t saved_sigmask;/* To be restored with TIF_RESTORE_SIGMASK */
include/linux/syscalls.h +2 -0
@@ -605,4 +605,6 @@ asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct gint kernel_execve (const char *filename,char *const argv[],char *const envp[]); +asmlinkage long sys_signalfd (int sig,int flags); +#endif
kernel/fork.c +5 -0
@@ -1128,6 +1128,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,if (retval) goto bad_fork_cleanup_namespaces; +#ifdef CONFIG_EVENTFS +memset (p->signal_file,0 ,ARRAY_SIZE (p->signal_file)); +init_waitqueue_head (&p->signal_wait); +#endif + p->set_child_tid = (clone_flags &CLONE_CHILD_SETTID ) ? child_tidptr :NULL ;/* * Clear TID on mm_release()?
kernel/signal.c +34 -0
@@ -739,6 +739,16 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t,struct sigqueue * q =NULL ;int ret =0 ; +#ifdef CONFIG_EVENTFS +if (t->signal_file[sig-1 ]) { +struct file *file = t->signal_file[sig-1 ]; + file->private_data = (void *)(((unsigned long )(file->private_data)) |0x40000000 ); +wake_up (&t->signal_wait); +if (((unsigned long )(file->private_data)) &0x80000000 ) +return 1 ; + } +#endif +/* * fast-pathed signals for kernel-internal things like SIGSTOP * or SIGKILL.
@@ -817,6 +827,18 @@ specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t) ret =send_signal (sig, info, t, &t->pending);if (!ret && !sigismember (&t->blocked, sig))signal_wake_up (t, sig ==SIGKILL ); +#ifdef CONFIG_EVENTFS +/* +* Eventfs allows to deliver signals through epoll queue, +* it is possible to setup epoll to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through epoll queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; + +#endif out:return ret; }
@@ -1006,6 +1028,18 @@ __group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)* to avoid several races. */ ret =send_signal (sig, info, p, &p->signal->shared_pending); +#ifdef CONFIG_EVENTFS +/* +* Eventfs allows to deliver signals through epoll queue, +* it is possible to setup epoll to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through epoll queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; + +#endif if (unlikely (ret))return ret;
kernel/sys_ni.c +2 -0
@@ -113,6 +113,8 @@ cond_syscall(sys_vm86);cond_syscall (compat_sys_ipc);cond_syscall (compat_sys_sysctl); +cond_syscall (sys_signalfd); +/* arch-specific weak syscall entries */ cond_syscall (sys_pciconfig_read);cond_syscall (sys_pciconfig_write);
Signature · 1 line
Evgeniy Polyakov
#include <sys/epoll.h>
#include <signal.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <linux/unistd.h>
#include <linux/types.h>
#define _syscall2(type,name,type1,arg1,type2,arg2) \
type name (type1 arg1, type2 arg2) \
{\
return syscall(__NR_##name, arg1, arg2);\
}_syscall2(int, signalfd, int, sig, int, flags);
#if 1
#define ulog(f, a...) fprintf(stderr, f, ##a)
#else
#define ulog(f, a...)
#endif
#define ulog_err(f, a...) ulog(f ": %s [%d].\n", ##a, strerror(errno), errno)
static void sig_handler(int signo)
{
printf("%s, signo: %d.\n", __func__, signo);
}static int epoll_signal_init(int ctl_fd, int sig, int flags)
{
int fd;
struct epoll_event event;
fd = signalfd(sig, flags);
if (fd < 0) {
ulog_err("Failed to bind signal: %d, flags: %d", sig, flags);
return fd;
}
event.events = EPOLLIN;
event.data.fd = fd;
if (epoll_ctl(ctl_fd, EPOLL_CTL_ADD, fd, &event) < 0) {
ulog_err("Failed to perform control ADD operation: fd: %d", fd);
return -1;
}
return 0;
}int main()
{
int err, ctl_fd, i;
struct epoll_event event[256];
ctl_fd = epoll_create(10);
if (ctl_fd < 0) {
ulog_err("Failed to create epoll control file descriptor");
return -1;
}
signal(SIGUSR1, sig_handler);
signal(SIGUSR2, sig_handler);
err = epoll_signal_init(ctl_fd, SIGUSR1, 1);
if (err)
return err;
err = epoll_signal_init(ctl_fd, SIGUSR2, 0);
if (err)
return err;
ulog("%s: pid: %d\n", __func__, getpid());
kill(getpid(), SIGUSR1);
kill(getpid(), SIGUSR2);
while (1) {
err = epoll_wait(ctl_fd, event, 256, 10000);
if (err < 0) {
ulog_err("Failed to wait for events");
continue;
}
if (err == 0)
continue;
for (i=0; i<err; ++i)
printf("Dequeued signal, fd: %u.\n", event[i].data.fd);
}
return 0;
}