Skip to contentSkip to conversation

eventfs: pseudo fs which allows to bind events to file descriptors.

PATCH New Evgeniy Polyakov 1 participant 1 message Mar 7, 2007

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

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
index 2697e92..b14ee54 100644
@@ -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
index eda7a0d..bc6336c 100644
@@ -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
index 3c4886b..09803ad 100644
@@ -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
index 9edf411..185bcb1 100644
@@ -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
index 833fa17..c72a568 100644
@@ -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
index c5f596e..62a21f3 100644
@@ -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
index 49fe299..22c1412 100644
@@ -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
index 1912c6c..b34f4e6 100644
@@ -605,4 +605,6 @@ asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct g
 
 int 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
index d154cc7..1b318da 100644
@@ -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
index 3670225..059977c 100644
@@ -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
index d7306d0..c131d20 100644
@@ -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;
}