kevent: Description.
Subsystems (12)
A message that is not in the archive (sent off-list or not yet received): [email protected]
cover kevent: Generic event handling mechanism.
Generic event handling mechanism.
Kevent is a generic subsytem which allows to handle event notifications. It supports both level and edge triggered events. It is similar to poll/epoll in some cases, but it is more scalable, it is faster and allows to work with essentially eny kind of events.
Events are provided into kernel through control syscall and can be read back through ring buffer or using usual syscalls.
Kevent update (i.e. readiness switching) happens directly from internals of the appropriate state machine of the underlying subsytem (like network, filesystem, timer or any other).
Homepage:
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
Documentation page:
http://linux-net.osdl.org/index.php/Kevent
Consider for inclusion.
New benchmark, which can be a hoax though, can be found at
http://tservice.net.ru/~s0mbre/blog/2006/11/30#2006_11_30
where kevent on amd64 with 1gb of ram can handle more than 7200 events per second with 8000 requests concurrency with 'ab' benchmark and lighttpd. Although I tought it should not be published due to possible errors, I decided to send it for review.
With this release I start 3 days resending timeout - i.e. each third day I will send either new version (if something new was requested and agreed to be implemented) or resending with back counter started from three. When back counter hits zero after three resending I consider there is no interest in subsystem and I will stop further sending.
Thanks for understanding and your time.
Changes from 'take27' patchset:
* made kevent default yes in non embedded case.
* added falgs to callback structures - currently used to check if kevent can be requested from kernelspace only (posix timers) or userspace (all others)
Changes from 'take26' patchset:
* made kevent visible in config only in case of embedded setup.
* added comment about KEVENT_MAX number.
* spell fix.
Changes from 'take25' patchset:
* use timespec as timeout parameter.
* added high-resolution timer to handle absolute timeouts.
* added flags to waiting and initialization syscalls.
* kevent_commit() has new_uidx parameter.
* kevent_wait() has old_uidx parameter, which, if not equal to u->uidx, results in immediate wakeup (usefull for the case when entries
are added asynchronously from kernel (not supported for now)).
* added interface to mark any event as ready.
* event POSIX timers support.
* return -ENOSYS if there is no registered event type.
* provided file descriptor must be checked for fifo type (spotted by Eric Dumazet).
* signal notifications.
* documentation update.
* lighttpd patch updated (the latest benchmarks with lighttpd patch can be found in blog).
Changes from 'take24' patchset:
* new (old (new)) ring buffer implementation with kernel and user indexes.
* added initialization syscall instead of opening /dev/kevent
* kevent_commit() syscall to commit ring buffer entries
* changed KEVENT_REQ_WAKEUP_ONE flag to KEVENT_REQ_WAKEUP_ALL, kevent wakes only first thread always if that flag is not set
* KEVENT_REQ_ALWAYS_QUEUE flag. If set, kevent will be queued into ready queue instead of copying back to userspace when kevent is ready immediately when it is added.
* lighttpd patch (Hail! Although nothing really outstanding compared to epoll)
Changes from 'take23' patchset:
* kevent PIPE notifications
* KEVENT_REQ_LAST_CHECK flag, which allows to perform last check at dequeueing time
* fixed poll/select notifications (were broken due to tree manipulations)
* made Documentation/kevent.txt look nice in 80-col terminal
* fix for copy_to_user() failure report for the first kevent (Andrew Morton)
* minor function renames
Changes from 'take22' patchset:
* new ring buffer implementation in process' memory
* wakeup-one-thread flag
* edge-triggered behaviour
Changes from 'take21' patchset:
* minor cleanups (different return values, removed unneded variables, whitespaces and so on)
* fixed bug in kevent removal in case when kevent being removed
is the same as overflow_kevent (spotted by Eric Dumazet)
Changes from 'take20' patchset:
* new ring buffer implementation
* removed artificial limit on possible number of kevents
Changes from 'take19' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take18' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take17' patchset:
* Use RB tree instead of hash table.
At least for a web sever, frequency of addition/deletion of new kevent is comparable with number of search access, i.e. most of the time events are added, accesed only couple of times and then removed, so it justifies RB tree usage over AVL tree, since the latter does have much slower deletion time (max O(log(N)) compared to 3 ops),
although faster search time (1.44*O(log(N)) vs. 2*O(log(N))).
So for kevents I use RB tree for now and later, when my AVL tree implementation is ready, it will be possible to compare them.
* Changed readiness check for socket notifications.
With both above changes it is possible to achieve more than 3380 req/second compared to 2200, sometimes 2500 req/second for epoll() for trivial web-server and httperf client on the same hardware.
It is possible that above kevent limit is due to maximum allowed kevents in a time limit, which is 4096 events.
Changes from 'take16' patchset:
* misc cleanups (__read_mostly, const ...)
* created special macro which is used for mmap size (number of pages) calculation
* export kevent_socket_notify(), since it is used in network protocols which can be built as modules (IPv6 for example)
Changes from 'take15' patchset:
* converted kevent_timer to high-resolution timers, this forces timer API update at
http://linux-net.osdl.org/index.php/Kevent
* use struct ukevent* instead of void * in syscalls (documentation has been updated)
* added warning in kevent_add_ukevent() if ring has broken index (for testing)
Changes from 'take14' patchset:
* added kevent_wait()
This syscall waits until either timeout expires or at least one event becomes ready. It also commits that @num events from @start are processed by userspace and thus can be be removed or rearmed (depending on it's flags). It can be used for commit events read by userspace through mmap interface. Example userspace code (evtest.c) can be found on project's homepage.
* added socket notifications (send/recv/accept)
Changes from 'take13' patchset:
* do not get lock aroung user data check in __kevent_search()
* fail early if there were no registered callbacks for given type of kevent
* trailing whitespace cleanup
Changes from 'take12' patchset:
* remove non-chardev interface for initialization
* use pointer to kevent_mring instead of unsigned longs
* use aligned 64bit type in raw user data (can be used by high-res timer if needed)
* simplified enqueue/dequeue callbacks and kevent initialization
* use nanoseconds for timeout
* put number of milliseconds into timer's return data
* move some definitions into user-visible header
* removed filenames from comments
Changes from 'take11' patchset:
* include missing headers into patchset
* some trivial code cleanups (use goto instead of if/else games and so on)
* some whitespace cleanups
* check for ready_callback() callback before main loop which should save us some ticks
Changes from 'take10' patchset:
* removed non-existent prototypes
* added helper function for kevent_registered_callbacks
* fixed 80 lines comments issues
* added shared between userspace and kernelspace header instead of embedd them in one
* core restructuring to remove forward declarations
* s o m e w h i t e s p a c e c o d y n g s t y l e c l e a n u p
* use vm_insert_page() instead of remap_pfn_range()
Changes from 'take9' patchset:
* fixed ->nopage method
Changes from 'take8' patchset:
* fixed mmap release bug
* use module_init() instead of late_initcall()
* use better structures for timer notifications
Changes from 'take7' patchset:
* new mmap interface (not tested, waiting for other changes to be acked)
- use nopage() method to dynamically substitue pages
- allocate new page for events only when new added kevent requres it
- do not use ugly index dereferencing, use structure instead
- reduced amount of data in the ring (id and flags), maximum 12 pages on x86 per kevent fd
Changes from 'take6' patchset:
* a lot of comments!
* do not use list poisoning for detection of the fact, that entry is in the list
* return number of ready kevents even if copy*user() fails
* strict check for number of kevents in syscall
* use ARRAY_SIZE for array size calculation
* changed superblock magic number
* use SLAB_PANIC instead of direct panic() call
* changed -E* return values
* a lot of small cleanups and indent fixes
Changes from 'take5' patchset:
* removed compilation warnings about unused wariables when lockdep is not turned on
* do not use internal socket structures, use appropriate (exported) wrappers instead
* removed default 1 second timeout
* removed AIO stuff from patchset
Changes from 'take4' patchset:
* use miscdevice instead of chardevice
* comments fixes
Changes from 'take3' patchset:
* removed serializing mutex from kevent_user_wait()
* moved storage list processing to RCU
* removed lockdep screaming - all storage locks are initialized in the same function, so it was
learned
to differentiate between various cases
* remove kevent from storage if is marked as broken after callback
* fixed a typo in mmaped buffer implementation which would end up in wrong index calcualtion
Changes from 'take2' patchset:
* split kevent_finish_user() to locked and unlocked variants
* do not use KEVENT_STAT ifdefs, use inline functions instead
* use array of callbacks of each type instead of each kevent callback initialization
* changed name of ukevent guarding lock
* use only one kevent lock in kevent_user for all hash buckets instead of per-bucket locks
* do not use kevent_user_ctl structure instead provide needed arguments as syscall parameters
* various indent cleanups
* added optimisation, which is aimed to help when a lot of kevents are being copied from
userspace
* mapped buffer (initial) implementation (no userspace yet)
Changes from 'take1' patchset:
- rebased against 2.6.18-git tree
- removed ioctl controlling
- added new syscall kevent_get_events(int fd, unsigned int min_nr, unsigned int max_nr, unsigned int timeout, void __user *buf, unsigned flags)
- use old syscall kevent_ctl for creation/removing, modification and initial kevent initialization
- use mutuxes instead of semaphores
- added file descriptor check and return error if provided descriptor does not match kevent file operations
- various indent fixes
- removed aio_sendfile() declarations.
Thank you.
PATCH 1/8 kevent: Description.
Description.
Documentation/kevent.txt new file +240 -0
@@ -0,0 +1,240 @@ +Description. + +int kevent_init(struct kevent_ring *ring, unsigned int ring_size, + unsigned int flags); + +num - size of the ring buffer in events +ring - pointer to allocated ring buffer +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: kevent control file descriptor or negative error value. + + struct kevent_ring + { + unsigned int ring_kidx, ring_over; + struct ukevent event[0]; + } + +ring_kidx - index in the ring buffer where kernel will put new events + when kevent_wait() or kevent_get_events() is called +ring_over - number of overflows of ring_uidx happend from the start. + Overflow counter is used to prevent situation when two threads + are going to free the same events, but one of them was scheduled + away for too long, so ring indexes were wrapped, so when that + thread will be awakened, it will free not those events, which + it suppose to free. + +Example userspace code (ring_buffer.c) can be found on project's homepage. + +Each kevent syscall can be so called cancellation point in glibc, i.e. when +thread has been cancelled in kevent syscall, thread can be safely removed +and no events will be lost, since each syscall (kevent_wait() or +kevent_get_events()) will copy event into special ring buffer, accessible +from other threads or even processes (if shared memory is used). + +When kevent is removed (not dequeued when it is ready, but just removed), +even if it was ready, it is not copied into ring buffer, since if it is +removed, no one cares about it (otherwise user would wait until it becomes +ready and got it through usual way using kevent_get_events() or kevent_wait()) +and thus no need to copy it to the ring buffer. + +------------------------------------------------------------------------------- + + +int kevent_ctl(int fd, unsigned int cmd, unsigned int num, struct ukevent *arg); + +fd - is the file descriptor referring to the kevent queue to manipulate. +It is created by opening "/dev/kevent" char device, which is created with +dynamic minor number and major number assigned for misc devices. + +cmd - is the requested operation. It can be one of the following: + KEVENT_CTL_ADD - add event notification + KEVENT_CTL_REMOVE - remove event notification + KEVENT_CTL_MODIFY - modify existing notification + KEVENT_CTL_READY - mark existing events as ready, if number of events is zero, + it just wakes up parked in syscall thread + +num - number of struct ukevent in the array pointed to by arg +arg - array of struct ukevent + +Return value: + number of events processed or negative error value. + +When called, kevent_ctl will carry out the operation specified in the +cmd parameter. +------------------------------------------------------------------------------- + + int kevent_get_events(int ctl_fd, unsigned int min_nr, unsigned int max_nr, + struct timespec timeout, struct ukevent *buf, unsigned flags); + +ctl_fd - file descriptor referring to the kevent queue +min_nr - minimum number of completed events that kevent_get_events will block + waiting for +max_nr - number of struct ukevent in buf +timeout - time to wait before returning less than min_nr + events. If this is -1, then wait forever. +buf - pointer to an array of struct ukevent. +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied or negative error value. + +kevent_get_events will wait timeout milliseconds for at least min_nr completed +events, copying completed struct ukevents to buf and deleting any +KEVENT_REQ_ONESHOT event requests. In nonblocking mode it returns as many +events as possible, but not more than max_nr. In blocking mode it waits until +timeout or if at least min_nr events are ready. + +This function copies event into ring buffer if it was initialized, if ring buffer +is full, KEVENT_RET_COPY_FAILED flag is set in ret_flags field. +------------------------------------------------------------------------------- + + int kevent_wait(int ctl_fd, unsigned int num, unsigned int old_uidx, + struct timespec timeout, unsigned int flags); + +ctl_fd - file descriptor referring to the kevent queue +num - number of processed kevents +old_uidx - the last index user is aware of +timeout - time to wait until there is free space in kevent queue +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied into ring buffer or negative error value. + +This syscall waits until either timeout expires or at least one event becomes +ready. It also copies events into special ring buffer. If ring buffer is full, +it waits until there are ready events and then return. +If kevent is one-shot kevent it is removed in this syscall. +If kevent is edge-triggered (KEVENT_REQ_ET flag is set in 'req_flags') it is +requeued in this syscall for performance reasons. +------------------------------------------------------------------------------- + + int kevent_commit(int ctl_fd, unsigned int new_idx, unsigned int over); + +ctl_fd - file descriptor referring to the kevent queue +new_uidx - the last committed kevent +over - overflow count for given $new_idx value + +Return value: + number of committed kevents or negative error value. + +This function commits, i.e. marks as empty, slots in the ring buffer, so +they can be reused when userspace completes that entries processing. + +Overflow counter is used to prevent situation when two threads are going +to free the same events, but one of them was scheduled away for too long, +so ring indexes were wrapped, so when that thread will be awakened, it +will free not those events, which it suppose to free. + +It is possible that returned number of committed events will be smaller than +requested number - it is possible when several threads try to commit the +same events. +------------------------------------------------------------------------------- + +The bulk of the interface is entirely done through the ukevent struct. +It is used to add event requests, modify existing event requests, +specify which event requests to remove, and return completed events. + +struct ukevent contains the following members: + +struct kevent_id id + Id of this request, e.g. socket number, file descriptor and so on +__u32 type + Event type, e.g. KEVENT_SOCK, KEVENT_INODE, KEVENT_TIMER and so on +__u32 event + Event itself, e.g. SOCK_ACCEPT, INODE_CREATED, TIMER_FIRED +__u32 req_flags + Per-event request flags, + + KEVENT_REQ_ONESHOT + event will be removed when it is ready + + KEVENT_REQ_WAKEUP_ALL + Kevent wakes up only first thread interested in given event, + or all threads if this flag is set. + + KEVENT_REQ_ET + Edge Triggered behaviour. It is an optimisation which allows to move + ready and dequeued (i.e. copied to userspace) event to move into set + of interest for given storage (socket, inode and so on) again. It is + very usefull for cases when the same event should be used many times + (like reading from pipe). It is similar to epoll()'s EPOLLET flag. + + KEVENT_REQ_LAST_CHECK + if set allows to perform the last check on kevent (call appropriate + callback) when kevent is marked as ready and has been removed from + ready queue. If it will be confirmed that kevent is ready + (k->callbacks.callback(k) returns true) then kevent will be copied + to userspace, otherwise it will be requeued back to storage. + Second (checking) call is performed with this bit cleared, so callback + can detect when it was called from kevent_storage_ready() - bit is set, + or kevent_dequeue_ready() - bit is cleared. If kevent will be requeued, + bit will be set again. + + KEVENT_REQ_ALWAYS_QUEUE + If this flag is set kevent will be queued into ready queue if it is + ready at enqueue time, otherwise it will be copied back to userspace + and will not be queued into the storage. + +__u32 ret_flags + Per-event return flags + + KEVENT_RET_BROKEN + Kevent is broken + + KEVENT_RET_DONE + Kevent processing was finished successfully + + KEVENT_RET_COPY_FAILED + Kevent was not copied into ring buffer due to some error conditions. + +__u32 ret_data + Event return data. Event originator fills it with anything it likes + (for example timer notifications put number of milliseconds when timer + has fired +union { __u32 user[2]; void *ptr; } + User's data. It is not used, just copied to/from user. The whole structure + is aligned to 8 bytes already, so the last union is aligned properly. + +------------------------------------------------------------------------------- + +Kevent waiting syscall flags. + +KEVENT_FLAGS_ABSTIME - provided timespec parameter contains absolute time, + for example Aug 27, 2194, or time(NULL) + 10. + +------------------------------------------------------------------------------- + +Usage + +For KEVENT_CTL_ADD, all fields relevant to the event type must be filled +(id, type, event, req_flags). +After kevent_ctl(..., KEVENT_CTL_ADD, ...) returns each struct's ret_flags +should be checked to see if the event is already broken or done. + +For KEVENT_CTL_MODIFY, the id, req_flags, and user and event fields must be +set and an existing kevent request must have matching id and user fields. If +match is found, req_flags and event are replaced with the newly supplied +values and requeueing is started, so modified kevent can be checked and +probably marked as ready immediately. If a match can't be found, the +passed in ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is +always set. + +For KEVENT_CTL_REMOVE, the id and user fields must be set and an existing +kevent request must have matching id and user fields. If a match is found, +the kevent request is removed. If a match can't be found, the passed in +ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is always set. + +For kevent_get_events, the entire structure is returned. + +------------------------------------------------------------------------------- + +Usage cases + +kevent_timer +struct ukevent should contain following fields: + type - KEVENT_TIMER + event - KEVENT_TIMER_FIRED + req_flags - KEVENT_REQ_ONESHOT if you want to fire that timer only once + id.raw[0] - number of seconds after commit when this timer shout expire + id.raw[0] - additional to number of seconds number of nanoseconds
PATCH 2/8 kevent: Core files.
Core files.
This patch includes core kevent files:
* userspace controlling
* kernelspace interfaces
* initialization
* notification state machines
Some bits of documentation can be found on project's homepage (and links from there):
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
arch/i386/kernel/syscall_table.S +5 -0
@@ -318,3 +318,8 @@ ENTRY(sys_call_table) .long sys_vmsplice .long sys_move_pages .long sys_getcpu + .long sys_kevent_get_events + .long sys_kevent_ctl /* 320 */ + .long sys_kevent_wait + .long sys_kevent_commit + .long sys_kevent_init
arch/x86_64/ia32/ia32entry.S +6 -1
@@ -714,8 +714,13 @@ ia32_sys_call_table: .quad compat_sys_get_robust_list .quad sys_splice .quad sys_sync_file_range - .quad sys_tee + .quad sys_tee /* 315 */ .quad compat_sys_vmsplice .quad compat_sys_move_pages .quad sys_getcpu + .quad sys_kevent_get_events + .quad sys_kevent_ctl /* 320 */ + .quad sys_kevent_wait + .quad sys_kevent_commit + .quad sys_kevent_init ia32_syscall_end:
include/asm-i386/unistd.h +6 -1
@@ -324,10 +324,15 @@#define __NR_vmsplice 316#define __NR_move_pages 317#define __NR_getcpu 318 +#define __NR_kevent_get_events 319 +#define __NR_kevent_ctl 320 +#define __NR_kevent_wait 321 +#define __NR_kevent_commit 322 +#define __NR_kevent_init 323#ifdef __KERNEL__ -#define NR_syscalls 319 +#define NR_syscalls 324#include <linux/err.h> /*
include/asm-x86_64/unistd.h +11 -1
@@ -619,10 +619,20 @@ __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_kevent_get_events 280 +__SYSCALL(__NR_kevent_get_events, sys_kevent_get_events) +#define __NR_kevent_ctl 281 +__SYSCALL(__NR_kevent_ctl, sys_kevent_ctl) +#define __NR_kevent_wait 282 +__SYSCALL(__NR_kevent_wait, sys_kevent_wait) +#define __NR_kevent_commit 283 +__SYSCALL(__NR_kevent_commit, sys_kevent_commit) +#define __NR_kevent_init 284 +__SYSCALL(__NR_kevent_init, sys_kevent_init)#ifdef __KERNEL__ -#define __NR_syscall_max __NR_move_pages +#define __NR_syscall_max __NR_kevent_init#include <linux/err.h> #ifndef __NO_STUBS
include/linux/kevent.h new file +244 -0
244 lines not on this page · raw message
include/linux/kevent_storage.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef __KEVENT_STORAGE_H +#define __KEVENT_STORAGE_H + +struct kevent_storage +{ +void *origin;/* Originator's pointer, e.g. struct sock or struct file. Can be NULL. */ +struct list_head list;/* List of queued kevents. */ +spinlock_t lock;/* Protects users queue. */ +}; + +#endif /* __KEVENT_STORAGE_H */
include/linux/syscalls.h +9 -0
@@ -54,6 +54,8 @@ struct compat_stat;struct compat_timeval ;struct robust_list_head ;struct getcpu_cache ; +struct ukevent ; +struct kevent_ring ;#include <linux/types.h> #include <linux/aio_abi.h>
@@ -599,4 +601,11 @@ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len);asmlinkage long sys_getcpu (unsigned __user *cpu,unsigned __user *node,struct getcpu_cache __user *cache); +asmlinkage long sys_kevent_get_events (int ctl_fd,unsigned int min,unsigned int max, +struct timespec timeout,struct ukevent __user *buf,unsigned flags); +asmlinkage long sys_kevent_ctl (int ctl_fd,unsigned int cmd,unsigned int num,struct ukevent __user *buf); +asmlinkage long sys_kevent_wait (int ctl_fd,unsigned int num,unsigned int old_uidx, +struct timespec timeout,unsigned int flags); +asmlinkage long sys_kevent_commit (int ctl_fd,unsigned int new_uidx,unsigned int over); +asmlinkage long sys_kevent_init (int ctl_fd,struct kevent_ring __user *ring,unsigned int num,unsigned int flags);#endif
include/linux/ukevent.h new file +185 -0
185 lines not on this page · raw message
init/Kconfig +2 -0
@@ -201,6 +201,8 @@ config AUDITSYSCALL such as SELinux. To use audit's filesystem watch feature, please ensure that INOTIFY is configured. +source "kernel/kevent/Kconfig" + config IKCONFIG bool "Kernel .config support" ---help---
kernel/Makefile +1 -0
@@ -47,6 +47,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o +obj-$(CONFIG_KEVENT) += kevent/ obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o
kernel/kevent/Kconfig new file +66 -0
66 lines not on this page · raw message
kernel/kevent/Makefile new file +6 -0
@@ -0,0 +1,6 @@ +obj-y := kevent.o kevent_user.o +obj-$(CONFIG_KEVENT_TIMER) += kevent_timer.o +obj-$(CONFIG_KEVENT_POLL) += kevent_poll.o +obj-$(CONFIG_KEVENT_SOCKET) += kevent_socket.o +obj-$(CONFIG_KEVENT_PIPE) += kevent_pipe.o +obj-$(CONFIG_KEVENT_SIGNAL) += kevent_signal.o
kernel/kevent/kevent.c new file +265 -0
265 lines not on this page · raw message
kernel/kevent/kevent_user.c new file +1360 -0
1,360 lines not on this page · raw message
kernel/sys_ni.c +6 -0
@@ -122,6 +122,12 @@ cond_syscall(ppc_rtas);cond_syscall (sys_spu_run);cond_syscall (sys_spu_create); +cond_syscall (sys_kevent_get_events); +cond_syscall (sys_kevent_ctl); +cond_syscall (sys_kevent_wait); +cond_syscall (sys_kevent_commit); +cond_syscall (sys_kevent_init); +/* mmu depending weak syscall entries */ cond_syscall (sys_mprotect);cond_syscall (sys_msync);
PATCH 3/8 kevent: poll/select() notifications.
poll/select() notifications.
This patch includes generic poll/select notifications. kevent_poll works simialr to epoll and has the same issues (callback is invoked not from internal state machine of the caller, but through process awake, a lot of allocations and so on).
fs/file_table.c +3 -0
@@ -20,6 +20,7 @@#include <linux/cdev.h> #include <linux/fsnotify.h> #include <linux/sysctl.h> +#include <linux/kevent.h> #include <linux/percpu_counter.h> #include <asm/atomic.h>
@@ -119,6 +120,7 @@ struct file *get_empty_filp(void) f->f_uid = tsk->fsuid; f->f_gid = tsk->fsgid;eventpoll_init_file (f); +kevent_init_file (f);/* f->f_version: 0 */ return f;
@@ -164,6 +166,7 @@ void fastcall __fput(struct file *file)* in the file cleanup chain. */ eventpoll_release (file); +kevent_cleanup_file (file);locks_remove_flock (file);if (file->f_op && file->f_op->release)
include/linux/fs.h +8 -0
@@ -276,6 +276,7 @@ extern int dir_notify_enable;#include <linux/init.h> #include <linux/sched.h> #include <linux/mutex.h> +#include <linux/kevent_storage.h> #include <asm/atomic.h> #include <asm/semaphore.h>
@@ -586,6 +587,10 @@ struct inode {struct mutex inotify_mutex;/* protects the watches list */ #endif +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +struct kevent_storage st; +#endif +unsigned long i_state;unsigned long dirtied_when;/* jiffies of first dirtying */
@@ -739,6 +744,9 @@ struct file {struct list_head f_ep_links;spinlock_t f_ep_lock;#endif /* #ifdef CONFIG_EPOLL */ +#ifdef CONFIG_KEVENT_POLL +struct kevent_storage st; +#endif struct address_space *f_mapping; };extern spinlock_t files_lock;
kernel/kevent/kevent_poll.c new file +234 -0
234 lines not on this page · raw message
PATCH 4/8 kevent: Socket notifications.
Socket notifications.
This patch includes socket send/recv/accept notifications. Using trivial web server based on kevent and this features instead of epoll it's performance increased more than noticebly. More details about various benchmarks and server itself (evserver_kevent.c) can be found on project's homepage.
fs/inode.c +7 -0
@@ -21,6 +21,7 @@#include <linux/cdev.h> #include <linux/bootmem.h> #include <linux/inotify.h> +#include <linux/kevent.h> #include <linux/mount.h> /*
@@ -164,12 +165,18 @@ static struct inode *alloc_inode(struct super_block *sb) } inode->i_private =0 ; inode->i_mapping = mapping; +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_init (inode, &inode->st); +#endif }return inode; }void destroy_inode (struct inode *inode) { +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_fini (&inode->st); +#endif BUG_ON (inode_has_buffers (inode));security_inode_free (inode);if (inode->i_sb->s_op->destroy_inode)
include/net/sock.h +17 -15
@@ -48,6 +48,7 @@#include <linux/netdevice.h> #include <linux/skbuff.h> /* struct sk_buff */ #include <linux/security.h> +#include <linux/kevent.h> #include <linux/filter.h>
@@ -450,6 +451,21 @@ static inline int sk_stream_memory_free(struct sock *sk)extern void sk_stream_rfree (struct sk_buff *skb); +struct socket_alloc { +struct socket socket; +struct inode vfs_inode; +}; + +static inline struct socket *SOCKET_I (struct inode *inode) +{ + return &container_of(inode, struct socket_alloc, vfs_inode)->socket; +} + +static inline struct inode *SOCK_INODE (struct socket *socket) +{ + return &container_of(socket, struct socket_alloc, socket)->vfs_inode; +} +static inline void sk_stream_set_owner_r (struct sk_buff *skb,struct sock *sk) { skb->sk = sk;
@@ -477,6 +493,7 @@ static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb) sk->sk_backlog.tail = skb; } skb->next =NULL ; +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); }#define sk_wait_event (__sk, __timeo, __condition) \
@@ -679,21 +696,6 @@ static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si)return si->kiocb; } -struct socket_alloc { -struct socket socket; -struct inode vfs_inode; -}; - -static inline struct socket *SOCKET_I (struct inode *inode) -{ - return &container_of(inode, struct socket_alloc, vfs_inode)->socket; -} - -static inline struct inode *SOCK_INODE (struct socket *socket) -{ - return &container_of(socket, struct socket_alloc, socket)->vfs_inode; -} -extern void __sk_stream_mem_reclaim (struct sock *sk);extern int sk_stream_mem_schedule (struct sock *sk,int size,int kind);
include/net/tcp.h +1 -0
@@ -857,6 +857,7 @@ static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb) tp->ucopy.memory =0 ; }else if (skb_queue_len (&tp->ucopy.prequeue) ==1 ) {wake_up_interruptible (sk->sk_sleep); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND );if (!inet_csk_ack_scheduled (sk)) inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, (3 * TCP_RTO_MIN) / 4,
kernel/kevent/kevent_socket.c new file +144 -0
144 lines not on this page · raw message
net/core/sock.c +9 -1
@@ -1402,6 +1402,7 @@ static void sock_def_wakeup(struct sock *sk)if (sk->sk_sleep &&waitqueue_active (sk->sk_sleep))wake_up_interruptible_all (sk->sk_sleep);read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_error_report (struct sock *sk)
@@ -1411,6 +1412,7 @@ static void sock_def_error_report(struct sock *sk)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,0 ,POLL_ERR );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_readable (struct sock *sk,int len)
@@ -1420,6 +1422,7 @@ static void sock_def_readable(struct sock *sk, int len)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,1 ,POLL_IN );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_write_space (struct sock *sk)
@@ -1439,6 +1442,7 @@ static void sock_def_write_space(struct sock *sk) }read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); }static void sock_def_destruct (struct sock *sk)
@@ -1489,6 +1493,8 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_state =TCP_CLOSE ; sk->sk_socket = sock; +kevent_sk_reinit (sk); +sock_set_flag (sk,SOCK_ZAPPED );if (sock)
@@ -1555,8 +1561,10 @@ void fastcall release_sock(struct sock *sk)if (sk->sk_backlog.tail)__release_sock (sk); sk->sk_lock.owner =NULL ; -if (waitqueue_active (&sk->sk_lock.wq)) +if (waitqueue_active (&sk->sk_lock.wq)) {wake_up (&sk->sk_lock.wq); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); + }spin_unlock_bh (&sk->sk_lock.slock); }EXPORT_SYMBOL (release_sock);
net/core/stream.c +1 -0
@@ -36,6 +36,7 @@ void sk_stream_write_space(struct sock *sk)wake_up_interruptible (sk->sk_sleep);if (sock->fasync_list && !(sk->sk_shutdown &SEND_SHUTDOWN ))sock_wake_async (sock,2 ,POLL_OUT ); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); } }
net/ipv4/tcp_input.c +1 -0
@@ -3119,6 +3119,7 @@ static void tcp_ofo_queue(struct sock *sk)__skb_unlink (skb, &tp->out_of_order_queue);__skb_queue_tail (&sk->sk_receive_queue, skb); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); tp->rcv_nxt =TCP_SKB_CB (skb)->end_seq;if (skb->h.th->fin)tcp_fin (skb, sk, skb->h.th);
net/ipv4/tcp_ipv4.c +2 -0
@@ -61,6 +61,7 @@#include <linux/jhash.h> #include <linux/init.h> #include <linux/times.h> +#include <linux/kevent.h> #include <net/icmp.h> #include <net/inet_hashtables.h>
@@ -870,6 +871,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)reqsk_free (req); }else {inet_csk_reqsk_queue_hash_add (sk, req,TCP_TIMEOUT_INIT ); +kevent_socket_notify (sk,KEVENT_SOCKET_ACCEPT ); }return 0 ;
net/socket.c +3 -0
@@ -85,6 +85,7 @@#include <linux/kmod.h> #include <linux/audit.h> #include <linux/wireless.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -490,6 +491,8 @@ static struct socket *sock_alloc(void) inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; +kevent_socket_reinit (sock); +get_cpu_var (sockets_in_use)++;put_cpu_var (sockets_in_use);return sock;
PATCH 5/8 kevent: Timer notifications.
Timer notifications.
Timer notifications can be used for fine grained per-process time management, since interval timers are very inconvenient to use, and they are limited.
This subsystem uses high-resolution timers.
id.raw[0] is used as number of seconds
id.raw[1] is used as number of nanoseconds
kernel/kevent/kevent_timer.c new file +114 -0
@@ -0,0 +1,114 @@ +/* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/jiffies.h> +#include <linux/kevent.h> + +struct kevent_timer +{ +struct hrtimer ktimer; +struct kevent_storage ktimer_storage; +struct kevent *ktimer_event; +}; + +static int kevent_timer_func (struct hrtimer *timer) +{ + struct kevent_timer *t = container_of(timer, struct kevent_timer, ktimer); +struct kevent *k = t->ktimer_event; + +kevent_storage_ready (&t->ktimer_storage,NULL ,KEVENT_MASK_ALL ); +hrtimer_forward (timer, timer->base->softirq_time, +ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ])); +return HRTIMER_RESTART ; +} + +static struct lock_class_key kevent_timer_key; + +static int kevent_timer_enqueue (struct kevent *k) +{ +int err; +struct kevent_timer *t; + + t =kmalloc (sizeof (struct kevent_timer ),GFP_KERNEL ); +if (!t) +return -ENOMEM ; + +hrtimer_init (&t->ktimer,CLOCK_MONOTONIC ,HRTIMER_REL ); + t->ktimer.expires =ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ]); + t->ktimer.function = kevent_timer_func; + t->ktimer_event = k; + + err =kevent_storage_init (&t->ktimer, &t->ktimer_storage); +if (err) + goto err_out_free; +lockdep_set_class (&t->ktimer_storage.lock, &kevent_timer_key); + + err =kevent_storage_enqueue (&t->ktimer_storage, k); +if (err) + goto err_out_st_fini; + +hrtimer_start (&t->ktimer, t->ktimer.expires,HRTIMER_REL ); + +return 0 ; + +err_out_st_fini: +kevent_storage_fini (&t->ktimer_storage); +err_out_free: +kfree (t); + +return err; +} + +static int kevent_timer_dequeue (struct kevent *k) +{ +struct kevent_storage *st = k->st; + struct kevent_timer *t = container_of(st, struct kevent_timer, ktimer_storage); + +hrtimer_cancel (&t->ktimer); +kevent_storage_dequeue (st, k); +kfree (t); + +return 0 ; +} + +static int kevent_timer_callback (struct kevent *k) +{ + k->event.ret_data[0 ] =jiffies_to_msecs (jiffies); +return 1 ; +} + +static int __init kevent_init_timer (void ) +{ +struct kevent_callbacks tc = { + .callback = &kevent_timer_callback, + .enqueue = &kevent_timer_enqueue, + .dequeue = &kevent_timer_dequeue, + .flags =0 , + }; + +return kevent_add_callbacks (&tc,KEVENT_TIMER ); +} +module_init (kevent_init_timer); +
PATCH 6/8 kevent: Pipe notifications.
Pipe notifications.
fs/pipe.c +6 -0
@@ -16,6 +16,7 @@#include <linux/uio.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/ioctls.h>
@@ -312,6 +313,7 @@ redo:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -321,6 +323,7 @@ redo:/* Signal writers asynchronously that there is more room. */ if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -490,6 +493,7 @@ redo2:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); do_wakeup =0 ;
@@ -501,6 +505,7 @@ redo2: out:mutex_unlock (&inode->i_mutex);if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); }
@@ -605,6 +610,7 @@ pipe_release(struct inode *inode, int decr, int decw)free_pipe_info (inode); }else {wake_up_interruptible (&pipe->wait); +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV );kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN );kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
kernel/kevent/kevent_pipe.c new file +123 -0
123 lines not on this page · raw message
PATCH 7/8 kevent: Signal notifications.
Signal notifications.
This type of notifications allows to deliver signals through kevent queue. One can find example application signal.c on project homepage.
If KEVENT_SIGNAL_NOMASK bit is set in raw_u64 id then signal will be delivered only through queue, otherwise both delivery types are used - old through update of mask of pending signals and through queue.
If signal is delivered only through kevent queue mask of pending signals is not updated at all, which is equal to putting signal into blocked mask, but with delivery of that signal through kevent queue.
include/linux/sched.h +5 -0
@@ -80,6 +80,7 @@ struct sched_param {#include <linux/resource.h> #include <linux/timer.h> #include <linux/hrtimer.h> +#include <linux/kevent_storage.h> #include <asm/processor.h>
@@ -1013,6 +1014,10 @@ struct task_struct {#ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info *delays;#endif +#ifdef CONFIG_KEVENT_SIGNAL +struct kevent_storage st; +u32 kevent_signals; +#endif };static inline pid_t process_group (struct task_struct *tsk)
kernel/fork.c +8 -0
@@ -46,6 +46,7 @@#include <linux/delayacct.h> #include <linux/taskstats_kern.h> #include <linux/random.h> +#include <linux/kevent.h> #include <asm/pgtable.h> #include <asm/pgalloc.h>
@@ -115,6 +116,9 @@ void __put_task_struct(struct task_struct *tsk)WARN_ON (atomic_read (&tsk->usage));WARN_ON (tsk == current); +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_fini (&tsk->st); +#endif security_task_free (tsk);free_uid (tsk->user);put_group_info (tsk->group_info);
@@ -1121,6 +1125,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,if (retval) goto bad_fork_cleanup_namespace; +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_init (p, &p->st); +#endif + p->set_child_tid = (clone_flags &CLONE_CHILD_SETTID ) ? child_tidptr :NULL ;/* * Clear TID on mm_release()?
kernel/kevent/kevent_signal.c new file +94 -0
94 lines not on this page · raw message
kernel/signal.c +26 -0
@@ -23,6 +23,7 @@#include <linux/ptrace.h> #include <linux/signal.h> #include <linux/capability.h> +#include <linux/kevent.h> #include <asm/param.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -703,6 +704,9 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, {struct sigqueue * q =NULL ;int ret =0 ; + +if (kevent_signal_notify (t, sig)) +return 1 ;/* * fast-pathed signals for kernel-internal things like SIGSTOP
@@ -782,6 +786,17 @@ 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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif out:return ret; }
@@ -971,6 +986,17 @@ __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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif if (unlikely (ret))return ret;
PATCH 8/8 kevent: Kevent posix timer notifications.
Kevent posix timer notifications.
Simple extensions to POSIX timers which allows
to deliver notification of the timer expiration
through kevent queue.
Example application posix_timer.c can be found
in archive on project homepage.
include/asm-generic/siginfo.h +3 -0
@@ -235,6 +235,7 @@ typedef struct siginfo {#define SIGEV_NONE 1/* other notification: meaningless */ #define SIGEV_THREAD 2/* deliver via thread creation */ #define SIGEV_THREAD_ID 4/* deliver to thread */ +#define SIGEV_KEVENT 8/* deliver through kevent queue */ /* * This works because the alignment is ok on all current architectures
@@ -260,6 +261,8 @@ typedef struct sigevent {void (*_function)(sigval_t );void *_attribute;/* really pthread_attr_t */ } _sigev_thread; + +int kevent_fd; } _sigev_un; } sigevent_t;
include/linux/posix-timers.h +4 -0
@@ -4,6 +4,7 @@#include <linux/spinlock.h> #include <linux/list.h> #include <linux/sched.h> +#include <linux/kevent_storage.h> union cpu_time_count {cputime_t cpu;
@@ -49,6 +50,9 @@ struct k_itimer {sigval_t it_sigev_value;/* value word of sigevent struct */ struct task_struct *it_process;/* process to send signal to */ struct sigqueue *sigq;/* signal queue entry. */ +#ifdef CONFIG_KEVENT_TIMER +struct kevent_storage st; +#endif union { struct { struct hrtimer timer;
kernel/posix-timers.c +171 -48
264 lines not on this page · raw message
Re: [take28-resend_2->0 0/8] kevent: Generic event handling mechanism.
In reply to Evgeniy PolyakovIt would help if one could actually get hold of the changes.
Neither at home nor on my gmail account did I get them all. The gmane also only has 5 of the 9 mails or so. Your archive only has sources from a couple of versions back.
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Re: [take28-resend_2->0 0/8] kevent: Generic event handling mechanism.
Quoted 5 lines · On Mon, 18 Dec 2006 19:47:21 -0800 Ulrich Drepper wrote:
It would help if one could actually get hold of the changes.
Neither at home nor on my gmail account did I get them all. The gmane also only has 5 of the 9 mails or so. Your archive only has sources from a couple of versions back.
It looks like they are all archived at marc.theaimsgroup.com. Try this:
http://marc.theaimsgroup.com/?l=linux-netdev&w=2&r=1&s=take28-resend_2&q=t
But it would be Good for them to have a home.
---
~Randy
Re: [take28-resend_2->0 0/8] kevent: Generic event handling mechanism.
In reply to Ulrich DrepperQuoted 5 lines · Ulrich Drepper
It would help if one could actually get hold of the changes.
Neither at home nor on my gmail account did I get them all. The gmane also only has 5 of the 9 mails or so. Your archive only has sources from a couple of versions back.
Kernel archive contains all changes as far as I can see at marc.theaimsgroup.com and lkml.org
I've uploaded the latest changes to the homepage.
Quoted 3 lines
Signature · 2 lines
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Signature · 1 line
Evgeniy Polyakov
Re: [take28-resend_2->0 0/8] kevent: Generic event handling mechanism.
Quoted 1 line · Evgeniy Polyakov
I've uploaded the latest changes to the homepage.
Thanks. But could you now update the patch so that it can be compiled with the current upstream kernel? At least <linux/kevent.h> has problems because of file->st accesses.
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Re: [take28-resend_2->0 0/8] kevent: Generic event handling mechanism.
Quoted 6 lines · Ulrich Drepper
Quoted 1 line · Evgeniy Polyakov
I've uploaded the latest changes to the homepage.
Thanks. But could you now update the patch so that it can be compiled with the current upstream kernel? At least <
linux/kevent.h> has problems because offile->staccesses.
file->st is only defined for poll/select events, if it is not specified at compile time, functions in linux/kevent.h becomes void:
#ifdef CONFIG_KEVENT_POLL
static inline void kevent_init_file(struct file *file)
{
kevent_storage_init(file, &file->st);
}static inline void kevent_cleanup_file(struct file *file)
{
kevent_storage_fini(&file->st);
}#else
static inline void kevent_init_file(struct file *file) {} static inline void kevent_cleanup_file(struct file *file) {} #endif
What error messages do you see and what are kevent related config changes?
Quoted 3 lines
Signature · 2 lines
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Signature · 1 line
Evgeniy Polyakov
Re: [take28-resend_2->0 0/8] kevent: Generic event handling mechanism.
Quoted 2 lines · Evgeniy Polyakov
What error messages do you see and what are kevent related config changes?
ARCH=um
#define CONFIG_KEVENT_USER_STAT 1
#define CONFIG_KEVENT_PIPE 1
#define CONFIG_KEVENT_POLL 1
#define CONFIG_KEVENT_TIMER 1
#define CONFIG_KEVENT 1
#define CONFIG_KEVENT_SIGNAL 1
#define CONFIG_KEVENT_SOCKET 1
In file included from kernel/kevent/kevent.c:28:include/linux/kevent.h: In function ‘kevent_init_file’:include/linux/kevent.h:220: error: ‘struct file’ has no member named ‘st’ include/linux/kevent.h: In function ‘kevent_cleanup_file’:include/linux/kevent.h:225: error: ‘struct file’ has no member named ‘st’
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Re: [take28-resend_2->0 0/8] kevent: Generic event handling mechanism.
Quoted 16 lines · Ulrich Drepper
Quoted 2 lines · Evgeniy Polyakov
What error messages do you see and what are kevent related config changes?
ARCH=um
#define
CONFIG_KEVENT_USER_STAT1
#defineCONFIG_KEVENT_PIPE1
#defineCONFIG_KEVENT_POLL1
#defineCONFIG_KEVENT_TIMER1
#defineCONFIG_KEVENT1
#defineCONFIG_KEVENT_SIGNAL1
#defineCONFIG_KEVENT_SOCKET1
Quoted 7 lines
In file included from
kernel/kevent/kevent.c:28:include/linux/kevent.h: In function ‘kevent_init_file’:include/linux/kevent.h:220: error: ‘struct file’ has no member named ‘st’include/linux/kevent.h: In function ‘kevent_cleanup_file’:include/linux/kevent.h:225: error: ‘struct file’ has no member named ‘st’
Can you send me your linux/fs.h file to chek if it is correct. Also does 'make prepare' fix the buid?
Quoted 3 lines
Signature · 2 lines
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Signature · 1 line
Evgeniy Polyakov
cover kevent: Generic event handling mechanism.
In reply to a message not in the archiveGeneric event handling mechanism.
Kevent is a generic subsytem which allows to handle event notifications. It supports both level and edge triggered events. It is similar to poll/epoll in some cases, but it is more scalable, it is faster and allows to work with essentially eny kind of events.
Events are provided into kernel through control syscall and can be read back through ring buffer or using usual syscalls.
Kevent update (i.e. readiness switching) happens directly from internals of the appropriate state machine of the underlying subsytem (like network, filesystem, timer or any other).
Homepage:
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
Documentation page:
http://linux-net.osdl.org/index.php/Kevent
Consider for inclusion.
New benchmark, which can be a hoax though, can be found at
http://tservice.net.ru/~s0mbre/blog/2006/11/30#2006_11_30
where kevent on amd64 with 1gb of ram can handle more than 7200 events per second with 8000 requests concurrency with 'ab' benchmark and lighttpd. Although I tought it should not be published due to possible errors, I decided to send it for review.
With this release I start 3 days resending timeout - i.e. each third day I will send either new version (if something new was requested and agreed to be implemented) or resending with back counter started from three. When back counter hits zero after three resending I consider there is no interest in subsystem and I will stop further sending.
Thanks for understanding and your time.
Changes from 'take27' patchset:
* made kevent default yes in non embedded case.
* added falgs to callback structures - currently used to check if kevent can be requested from kernelspace only (posix timers) or userspace (all others)
Changes from 'take26' patchset:
* made kevent visible in config only in case of embedded setup.
* added comment about KEVENT_MAX number.
* spell fix.
Changes from 'take25' patchset:
* use timespec as timeout parameter.
* added high-resolution timer to handle absolute timeouts.
* added flags to waiting and initialization syscalls.
* kevent_commit() has new_uidx parameter.
* kevent_wait() has old_uidx parameter, which, if not equal to u->uidx, results in immediate wakeup (usefull for the case when entries
are added asynchronously from kernel (not supported for now)).
* added interface to mark any event as ready.
* event POSIX timers support.
* return -ENOSYS if there is no registered event type.
* provided file descriptor must be checked for fifo type (spotted by Eric Dumazet).
* signal notifications.
* documentation update.
* lighttpd patch updated (the latest benchmarks with lighttpd patch can be found in blog).
Changes from 'take24' patchset:
* new (old (new)) ring buffer implementation with kernel and user indexes.
* added initialization syscall instead of opening /dev/kevent
* kevent_commit() syscall to commit ring buffer entries
* changed KEVENT_REQ_WAKEUP_ONE flag to KEVENT_REQ_WAKEUP_ALL, kevent wakes only first thread always if that flag is not set
* KEVENT_REQ_ALWAYS_QUEUE flag. If set, kevent will be queued into ready queue instead of copying back to userspace when kevent is ready immediately when it is added.
* lighttpd patch (Hail! Although nothing really outstanding compared to epoll)
Changes from 'take23' patchset:
* kevent PIPE notifications
* KEVENT_REQ_LAST_CHECK flag, which allows to perform last check at dequeueing time
* fixed poll/select notifications (were broken due to tree manipulations)
* made Documentation/kevent.txt look nice in 80-col terminal
* fix for copy_to_user() failure report for the first kevent (Andrew Morton)
* minor function renames
Changes from 'take22' patchset:
* new ring buffer implementation in process' memory
* wakeup-one-thread flag
* edge-triggered behaviour
Changes from 'take21' patchset:
* minor cleanups (different return values, removed unneded variables, whitespaces and so on)
* fixed bug in kevent removal in case when kevent being removed
is the same as overflow_kevent (spotted by Eric Dumazet)
Changes from 'take20' patchset:
* new ring buffer implementation
* removed artificial limit on possible number of kevents
Changes from 'take19' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take18' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take17' patchset:
* Use RB tree instead of hash table.
At least for a web sever, frequency of addition/deletion of new kevent is comparable with number of search access, i.e. most of the time events are added, accesed only couple of times and then removed, so it justifies RB tree usage over AVL tree, since the latter does have much slower deletion time (max O(log(N)) compared to 3 ops),
although faster search time (1.44*O(log(N)) vs. 2*O(log(N))).
So for kevents I use RB tree for now and later, when my AVL tree implementation is ready, it will be possible to compare them.
* Changed readiness check for socket notifications.
With both above changes it is possible to achieve more than 3380 req/second compared to 2200, sometimes 2500 req/second for epoll() for trivial web-server and httperf client on the same hardware.
It is possible that above kevent limit is due to maximum allowed kevents in a time limit, which is 4096 events.
Changes from 'take16' patchset:
* misc cleanups (__read_mostly, const ...)
* created special macro which is used for mmap size (number of pages) calculation
* export kevent_socket_notify(), since it is used in network protocols which can be built as modules (IPv6 for example)
Changes from 'take15' patchset:
* converted kevent_timer to high-resolution timers, this forces timer API update at
http://linux-net.osdl.org/index.php/Kevent
* use struct ukevent* instead of void * in syscalls (documentation has been updated)
* added warning in kevent_add_ukevent() if ring has broken index (for testing)
Changes from 'take14' patchset:
* added kevent_wait()
This syscall waits until either timeout expires or at least one event becomes ready. It also commits that @num events from @start are processed by userspace and thus can be be removed or rearmed (depending on it's flags). It can be used for commit events read by userspace through mmap interface. Example userspace code (evtest.c) can be found on project's homepage.
* added socket notifications (send/recv/accept)
Changes from 'take13' patchset:
* do not get lock aroung user data check in __kevent_search()
* fail early if there were no registered callbacks for given type of kevent
* trailing whitespace cleanup
Changes from 'take12' patchset:
* remove non-chardev interface for initialization
* use pointer to kevent_mring instead of unsigned longs
* use aligned 64bit type in raw user data (can be used by high-res timer if needed)
* simplified enqueue/dequeue callbacks and kevent initialization
* use nanoseconds for timeout
* put number of milliseconds into timer's return data
* move some definitions into user-visible header
* removed filenames from comments
Changes from 'take11' patchset:
* include missing headers into patchset
* some trivial code cleanups (use goto instead of if/else games and so on)
* some whitespace cleanups
* check for ready_callback() callback before main loop which should save us some ticks
Changes from 'take10' patchset:
* removed non-existent prototypes
* added helper function for kevent_registered_callbacks
* fixed 80 lines comments issues
* added shared between userspace and kernelspace header instead of embedd them in one
* core restructuring to remove forward declarations
* s o m e w h i t e s p a c e c o d y n g s t y l e c l e a n u p
* use vm_insert_page() instead of remap_pfn_range()
Changes from 'take9' patchset:
* fixed ->nopage method
Changes from 'take8' patchset:
* fixed mmap release bug
* use module_init() instead of late_initcall()
* use better structures for timer notifications
Changes from 'take7' patchset:
* new mmap interface (not tested, waiting for other changes to be acked)
- use nopage() method to dynamically substitue pages
- allocate new page for events only when new added kevent requres it
- do not use ugly index dereferencing, use structure instead
- reduced amount of data in the ring (id and flags), maximum 12 pages on x86 per kevent fd
Changes from 'take6' patchset:
* a lot of comments!
* do not use list poisoning for detection of the fact, that entry is in the list
* return number of ready kevents even if copy*user() fails
* strict check for number of kevents in syscall
* use ARRAY_SIZE for array size calculation
* changed superblock magic number
* use SLAB_PANIC instead of direct panic() call
* changed -E* return values
* a lot of small cleanups and indent fixes
Changes from 'take5' patchset:
* removed compilation warnings about unused wariables when lockdep is not turned on
* do not use internal socket structures, use appropriate (exported) wrappers instead
* removed default 1 second timeout
* removed AIO stuff from patchset
Changes from 'take4' patchset:
* use miscdevice instead of chardevice
* comments fixes
Changes from 'take3' patchset:
* removed serializing mutex from kevent_user_wait()
* moved storage list processing to RCU
* removed lockdep screaming - all storage locks are initialized in the same function, so it was
learned
to differentiate between various cases
* remove kevent from storage if is marked as broken after callback
* fixed a typo in mmaped buffer implementation which would end up in wrong index calcualtion
Changes from 'take2' patchset:
* split kevent_finish_user() to locked and unlocked variants
* do not use KEVENT_STAT ifdefs, use inline functions instead
* use array of callbacks of each type instead of each kevent callback initialization
* changed name of ukevent guarding lock
* use only one kevent lock in kevent_user for all hash buckets instead of per-bucket locks
* do not use kevent_user_ctl structure instead provide needed arguments as syscall parameters
* various indent cleanups
* added optimisation, which is aimed to help when a lot of kevents are being copied from
userspace
* mapped buffer (initial) implementation (no userspace yet)
Changes from 'take1' patchset:
- rebased against 2.6.18-git tree
- removed ioctl controlling
- added new syscall kevent_get_events(int fd, unsigned int min_nr, unsigned int max_nr, unsigned int timeout, void __user *buf, unsigned flags)
- use old syscall kevent_ctl for creation/removing, modification and initial kevent initialization
- use mutuxes instead of semaphores
- added file descriptor check and return error if provided descriptor does not match kevent file operations
- various indent fixes
- removed aio_sendfile() declarations.
Thank you.
PATCH 1/8 kevent: Description.
Description.
Documentation/kevent.txt new file +240 -0
@@ -0,0 +1,240 @@ +Description. + +int kevent_init(struct kevent_ring *ring, unsigned int ring_size, + unsigned int flags); + +num - size of the ring buffer in events +ring - pointer to allocated ring buffer +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: kevent control file descriptor or negative error value. + + struct kevent_ring + { + unsigned int ring_kidx, ring_over; + struct ukevent event[0]; + } + +ring_kidx - index in the ring buffer where kernel will put new events + when kevent_wait() or kevent_get_events() is called +ring_over - number of overflows of ring_uidx happend from the start. + Overflow counter is used to prevent situation when two threads + are going to free the same events, but one of them was scheduled + away for too long, so ring indexes were wrapped, so when that + thread will be awakened, it will free not those events, which + it suppose to free. + +Example userspace code (ring_buffer.c) can be found on project's homepage. + +Each kevent syscall can be so called cancellation point in glibc, i.e. when +thread has been cancelled in kevent syscall, thread can be safely removed +and no events will be lost, since each syscall (kevent_wait() or +kevent_get_events()) will copy event into special ring buffer, accessible +from other threads or even processes (if shared memory is used). + +When kevent is removed (not dequeued when it is ready, but just removed), +even if it was ready, it is not copied into ring buffer, since if it is +removed, no one cares about it (otherwise user would wait until it becomes +ready and got it through usual way using kevent_get_events() or kevent_wait()) +and thus no need to copy it to the ring buffer. + +------------------------------------------------------------------------------- + + +int kevent_ctl(int fd, unsigned int cmd, unsigned int num, struct ukevent *arg); + +fd - is the file descriptor referring to the kevent queue to manipulate. +It is created by opening "/dev/kevent" char device, which is created with +dynamic minor number and major number assigned for misc devices. + +cmd - is the requested operation. It can be one of the following: + KEVENT_CTL_ADD - add event notification + KEVENT_CTL_REMOVE - remove event notification + KEVENT_CTL_MODIFY - modify existing notification + KEVENT_CTL_READY - mark existing events as ready, if number of events is zero, + it just wakes up parked in syscall thread + +num - number of struct ukevent in the array pointed to by arg +arg - array of struct ukevent + +Return value: + number of events processed or negative error value. + +When called, kevent_ctl will carry out the operation specified in the +cmd parameter. +------------------------------------------------------------------------------- + + int kevent_get_events(int ctl_fd, unsigned int min_nr, unsigned int max_nr, + struct timespec timeout, struct ukevent *buf, unsigned flags); + +ctl_fd - file descriptor referring to the kevent queue +min_nr - minimum number of completed events that kevent_get_events will block + waiting for +max_nr - number of struct ukevent in buf +timeout - time to wait before returning less than min_nr + events. If this is -1, then wait forever. +buf - pointer to an array of struct ukevent. +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied or negative error value. + +kevent_get_events will wait timeout milliseconds for at least min_nr completed +events, copying completed struct ukevents to buf and deleting any +KEVENT_REQ_ONESHOT event requests. In nonblocking mode it returns as many +events as possible, but not more than max_nr. In blocking mode it waits until +timeout or if at least min_nr events are ready. + +This function copies event into ring buffer if it was initialized, if ring buffer +is full, KEVENT_RET_COPY_FAILED flag is set in ret_flags field. +------------------------------------------------------------------------------- + + int kevent_wait(int ctl_fd, unsigned int num, unsigned int old_uidx, + struct timespec timeout, unsigned int flags); + +ctl_fd - file descriptor referring to the kevent queue +num - number of processed kevents +old_uidx - the last index user is aware of +timeout - time to wait until there is free space in kevent queue +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied into ring buffer or negative error value. + +This syscall waits until either timeout expires or at least one event becomes +ready. It also copies events into special ring buffer. If ring buffer is full, +it waits until there are ready events and then return. +If kevent is one-shot kevent it is removed in this syscall. +If kevent is edge-triggered (KEVENT_REQ_ET flag is set in 'req_flags') it is +requeued in this syscall for performance reasons. +------------------------------------------------------------------------------- + + int kevent_commit(int ctl_fd, unsigned int new_idx, unsigned int over); + +ctl_fd - file descriptor referring to the kevent queue +new_uidx - the last committed kevent +over - overflow count for given $new_idx value + +Return value: + number of committed kevents or negative error value. + +This function commits, i.e. marks as empty, slots in the ring buffer, so +they can be reused when userspace completes that entries processing. + +Overflow counter is used to prevent situation when two threads are going +to free the same events, but one of them was scheduled away for too long, +so ring indexes were wrapped, so when that thread will be awakened, it +will free not those events, which it suppose to free. + +It is possible that returned number of committed events will be smaller than +requested number - it is possible when several threads try to commit the +same events. +------------------------------------------------------------------------------- + +The bulk of the interface is entirely done through the ukevent struct. +It is used to add event requests, modify existing event requests, +specify which event requests to remove, and return completed events. + +struct ukevent contains the following members: + +struct kevent_id id + Id of this request, e.g. socket number, file descriptor and so on +__u32 type + Event type, e.g. KEVENT_SOCK, KEVENT_INODE, KEVENT_TIMER and so on +__u32 event + Event itself, e.g. SOCK_ACCEPT, INODE_CREATED, TIMER_FIRED +__u32 req_flags + Per-event request flags, + + KEVENT_REQ_ONESHOT + event will be removed when it is ready + + KEVENT_REQ_WAKEUP_ALL + Kevent wakes up only first thread interested in given event, + or all threads if this flag is set. + + KEVENT_REQ_ET + Edge Triggered behaviour. It is an optimisation which allows to move + ready and dequeued (i.e. copied to userspace) event to move into set + of interest for given storage (socket, inode and so on) again. It is + very usefull for cases when the same event should be used many times + (like reading from pipe). It is similar to epoll()'s EPOLLET flag. + + KEVENT_REQ_LAST_CHECK + if set allows to perform the last check on kevent (call appropriate + callback) when kevent is marked as ready and has been removed from + ready queue. If it will be confirmed that kevent is ready + (k->callbacks.callback(k) returns true) then kevent will be copied + to userspace, otherwise it will be requeued back to storage. + Second (checking) call is performed with this bit cleared, so callback + can detect when it was called from kevent_storage_ready() - bit is set, + or kevent_dequeue_ready() - bit is cleared. If kevent will be requeued, + bit will be set again. + + KEVENT_REQ_ALWAYS_QUEUE + If this flag is set kevent will be queued into ready queue if it is + ready at enqueue time, otherwise it will be copied back to userspace + and will not be queued into the storage. + +__u32 ret_flags + Per-event return flags + + KEVENT_RET_BROKEN + Kevent is broken + + KEVENT_RET_DONE + Kevent processing was finished successfully + + KEVENT_RET_COPY_FAILED + Kevent was not copied into ring buffer due to some error conditions. + +__u32 ret_data + Event return data. Event originator fills it with anything it likes + (for example timer notifications put number of milliseconds when timer + has fired +union { __u32 user[2]; void *ptr; } + User's data. It is not used, just copied to/from user. The whole structure + is aligned to 8 bytes already, so the last union is aligned properly. + +------------------------------------------------------------------------------- + +Kevent waiting syscall flags. + +KEVENT_FLAGS_ABSTIME - provided timespec parameter contains absolute time, + for example Aug 27, 2194, or time(NULL) + 10. + +------------------------------------------------------------------------------- + +Usage + +For KEVENT_CTL_ADD, all fields relevant to the event type must be filled +(id, type, event, req_flags). +After kevent_ctl(..., KEVENT_CTL_ADD, ...) returns each struct's ret_flags +should be checked to see if the event is already broken or done. + +For KEVENT_CTL_MODIFY, the id, req_flags, and user and event fields must be +set and an existing kevent request must have matching id and user fields. If +match is found, req_flags and event are replaced with the newly supplied +values and requeueing is started, so modified kevent can be checked and +probably marked as ready immediately. If a match can't be found, the +passed in ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is +always set. + +For KEVENT_CTL_REMOVE, the id and user fields must be set and an existing +kevent request must have matching id and user fields. If a match is found, +the kevent request is removed. If a match can't be found, the passed in +ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is always set. + +For kevent_get_events, the entire structure is returned. + +------------------------------------------------------------------------------- + +Usage cases + +kevent_timer +struct ukevent should contain following fields: + type - KEVENT_TIMER + event - KEVENT_TIMER_FIRED + req_flags - KEVENT_REQ_ONESHOT if you want to fire that timer only once + id.raw[0] - number of seconds after commit when this timer shout expire + id.raw[0] - additional to number of seconds number of nanoseconds
PATCH 2/8 kevent: Core files.
Core files.
This patch includes core kevent files:
* userspace controlling
* kernelspace interfaces
* initialization
* notification state machines
Some bits of documentation can be found on project's homepage (and links from there):
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
arch/i386/kernel/syscall_table.S +5 -0
@@ -318,3 +318,8 @@ ENTRY(sys_call_table) .long sys_vmsplice .long sys_move_pages .long sys_getcpu + .long sys_kevent_get_events + .long sys_kevent_ctl /* 320 */ + .long sys_kevent_wait + .long sys_kevent_commit + .long sys_kevent_init
arch/x86_64/ia32/ia32entry.S +6 -1
@@ -714,8 +714,13 @@ ia32_sys_call_table: .quad compat_sys_get_robust_list .quad sys_splice .quad sys_sync_file_range - .quad sys_tee + .quad sys_tee /* 315 */ .quad compat_sys_vmsplice .quad compat_sys_move_pages .quad sys_getcpu + .quad sys_kevent_get_events + .quad sys_kevent_ctl /* 320 */ + .quad sys_kevent_wait + .quad sys_kevent_commit + .quad sys_kevent_init ia32_syscall_end:
include/asm-i386/unistd.h +6 -1
@@ -324,10 +324,15 @@#define __NR_vmsplice 316#define __NR_move_pages 317#define __NR_getcpu 318 +#define __NR_kevent_get_events 319 +#define __NR_kevent_ctl 320 +#define __NR_kevent_wait 321 +#define __NR_kevent_commit 322 +#define __NR_kevent_init 323#ifdef __KERNEL__ -#define NR_syscalls 319 +#define NR_syscalls 324#include <linux/err.h> /*
include/asm-x86_64/unistd.h +11 -1
@@ -619,10 +619,20 @@ __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_kevent_get_events 280 +__SYSCALL(__NR_kevent_get_events, sys_kevent_get_events) +#define __NR_kevent_ctl 281 +__SYSCALL(__NR_kevent_ctl, sys_kevent_ctl) +#define __NR_kevent_wait 282 +__SYSCALL(__NR_kevent_wait, sys_kevent_wait) +#define __NR_kevent_commit 283 +__SYSCALL(__NR_kevent_commit, sys_kevent_commit) +#define __NR_kevent_init 284 +__SYSCALL(__NR_kevent_init, sys_kevent_init)#ifdef __KERNEL__ -#define __NR_syscall_max __NR_move_pages +#define __NR_syscall_max __NR_kevent_init#include <linux/err.h> #ifndef __NO_STUBS
include/linux/kevent.h new file +244 -0
244 lines not on this page · raw message
include/linux/kevent_storage.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef __KEVENT_STORAGE_H +#define __KEVENT_STORAGE_H + +struct kevent_storage +{ +void *origin;/* Originator's pointer, e.g. struct sock or struct file. Can be NULL. */ +struct list_head list;/* List of queued kevents. */ +spinlock_t lock;/* Protects users queue. */ +}; + +#endif /* __KEVENT_STORAGE_H */
include/linux/syscalls.h +9 -0
@@ -54,6 +54,8 @@ struct compat_stat;struct compat_timeval ;struct robust_list_head ;struct getcpu_cache ; +struct ukevent ; +struct kevent_ring ;#include <linux/types.h> #include <linux/aio_abi.h>
@@ -599,4 +601,11 @@ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len);asmlinkage long sys_getcpu (unsigned __user *cpu,unsigned __user *node,struct getcpu_cache __user *cache); +asmlinkage long sys_kevent_get_events (int ctl_fd,unsigned int min,unsigned int max, +struct timespec timeout,struct ukevent __user *buf,unsigned flags); +asmlinkage long sys_kevent_ctl (int ctl_fd,unsigned int cmd,unsigned int num,struct ukevent __user *buf); +asmlinkage long sys_kevent_wait (int ctl_fd,unsigned int num,unsigned int old_uidx, +struct timespec timeout,unsigned int flags); +asmlinkage long sys_kevent_commit (int ctl_fd,unsigned int new_uidx,unsigned int over); +asmlinkage long sys_kevent_init (int ctl_fd,struct kevent_ring __user *ring,unsigned int num,unsigned int flags);#endif
include/linux/ukevent.h new file +185 -0
185 lines not on this page · raw message
init/Kconfig +2 -0
@@ -201,6 +201,8 @@ config AUDITSYSCALL such as SELinux. To use audit's filesystem watch feature, please ensure that INOTIFY is configured. +source "kernel/kevent/Kconfig" + config IKCONFIG bool "Kernel .config support" ---help---
kernel/Makefile +1 -0
@@ -47,6 +47,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o +obj-$(CONFIG_KEVENT) += kevent/ obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o
kernel/kevent/Kconfig new file +66 -0
66 lines not on this page · raw message
kernel/kevent/Makefile new file +6 -0
@@ -0,0 +1,6 @@ +obj-y := kevent.o kevent_user.o +obj-$(CONFIG_KEVENT_TIMER) += kevent_timer.o +obj-$(CONFIG_KEVENT_POLL) += kevent_poll.o +obj-$(CONFIG_KEVENT_SOCKET) += kevent_socket.o +obj-$(CONFIG_KEVENT_PIPE) += kevent_pipe.o +obj-$(CONFIG_KEVENT_SIGNAL) += kevent_signal.o
kernel/kevent/kevent.c new file +265 -0
265 lines not on this page · raw message
kernel/kevent/kevent_user.c new file +1360 -0
1,360 lines not on this page · raw message
kernel/sys_ni.c +6 -0
@@ -122,6 +122,12 @@ cond_syscall(ppc_rtas);cond_syscall (sys_spu_run);cond_syscall (sys_spu_create); +cond_syscall (sys_kevent_get_events); +cond_syscall (sys_kevent_ctl); +cond_syscall (sys_kevent_wait); +cond_syscall (sys_kevent_commit); +cond_syscall (sys_kevent_init); +/* mmu depending weak syscall entries */ cond_syscall (sys_mprotect);cond_syscall (sys_msync);
PATCH 3/8 kevent: poll/select() notifications.
poll/select() notifications.
This patch includes generic poll/select notifications. kevent_poll works simialr to epoll and has the same issues (callback is invoked not from internal state machine of the caller, but through process awake, a lot of allocations and so on).
fs/file_table.c +3 -0
@@ -20,6 +20,7 @@#include <linux/cdev.h> #include <linux/fsnotify.h> #include <linux/sysctl.h> +#include <linux/kevent.h> #include <linux/percpu_counter.h> #include <asm/atomic.h>
@@ -119,6 +120,7 @@ struct file *get_empty_filp(void) f->f_uid = tsk->fsuid; f->f_gid = tsk->fsgid;eventpoll_init_file (f); +kevent_init_file (f);/* f->f_version: 0 */ return f;
@@ -164,6 +166,7 @@ void fastcall __fput(struct file *file)* in the file cleanup chain. */ eventpoll_release (file); +kevent_cleanup_file (file);locks_remove_flock (file);if (file->f_op && file->f_op->release)
include/linux/fs.h +8 -0
@@ -276,6 +276,7 @@ extern int dir_notify_enable;#include <linux/init.h> #include <linux/sched.h> #include <linux/mutex.h> +#include <linux/kevent_storage.h> #include <asm/atomic.h> #include <asm/semaphore.h>
@@ -586,6 +587,10 @@ struct inode {struct mutex inotify_mutex;/* protects the watches list */ #endif +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +struct kevent_storage st; +#endif +unsigned long i_state;unsigned long dirtied_when;/* jiffies of first dirtying */
@@ -739,6 +744,9 @@ struct file {struct list_head f_ep_links;spinlock_t f_ep_lock;#endif /* #ifdef CONFIG_EPOLL */ +#ifdef CONFIG_KEVENT_POLL +struct kevent_storage st; +#endif struct address_space *f_mapping; };extern spinlock_t files_lock;
kernel/kevent/kevent_poll.c new file +234 -0
234 lines not on this page · raw message
PATCH 4/8 kevent: Socket notifications.
Socket notifications.
This patch includes socket send/recv/accept notifications. Using trivial web server based on kevent and this features instead of epoll it's performance increased more than noticebly. More details about various benchmarks and server itself (evserver_kevent.c) can be found on project's homepage.
fs/inode.c +7 -0
@@ -21,6 +21,7 @@#include <linux/cdev.h> #include <linux/bootmem.h> #include <linux/inotify.h> +#include <linux/kevent.h> #include <linux/mount.h> /*
@@ -164,12 +165,18 @@ static struct inode *alloc_inode(struct super_block *sb) } inode->i_private =0 ; inode->i_mapping = mapping; +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_init (inode, &inode->st); +#endif }return inode; }void destroy_inode (struct inode *inode) { +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_fini (&inode->st); +#endif BUG_ON (inode_has_buffers (inode));security_inode_free (inode);if (inode->i_sb->s_op->destroy_inode)
include/net/sock.h +17 -15
@@ -48,6 +48,7 @@#include <linux/netdevice.h> #include <linux/skbuff.h> /* struct sk_buff */ #include <linux/security.h> +#include <linux/kevent.h> #include <linux/filter.h>
@@ -450,6 +451,21 @@ static inline int sk_stream_memory_free(struct sock *sk)extern void sk_stream_rfree (struct sk_buff *skb); +struct socket_alloc { +struct socket socket; +struct inode vfs_inode; +}; + +static inline struct socket *SOCKET_I (struct inode *inode) +{ + return &container_of(inode, struct socket_alloc, vfs_inode)->socket; +} + +static inline struct inode *SOCK_INODE (struct socket *socket) +{ + return &container_of(socket, struct socket_alloc, socket)->vfs_inode; +} +static inline void sk_stream_set_owner_r (struct sk_buff *skb,struct sock *sk) { skb->sk = sk;
@@ -477,6 +493,7 @@ static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb) sk->sk_backlog.tail = skb; } skb->next =NULL ; +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); }#define sk_wait_event (__sk, __timeo, __condition) \
@@ -679,21 +696,6 @@ static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si)return si->kiocb; } -struct socket_alloc { -struct socket socket; -struct inode vfs_inode; -}; - -static inline struct socket *SOCKET_I (struct inode *inode) -{ - return &container_of(inode, struct socket_alloc, vfs_inode)->socket; -} - -static inline struct inode *SOCK_INODE (struct socket *socket) -{ - return &container_of(socket, struct socket_alloc, socket)->vfs_inode; -} -extern void __sk_stream_mem_reclaim (struct sock *sk);extern int sk_stream_mem_schedule (struct sock *sk,int size,int kind);
include/net/tcp.h +1 -0
@@ -857,6 +857,7 @@ static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb) tp->ucopy.memory =0 ; }else if (skb_queue_len (&tp->ucopy.prequeue) ==1 ) {wake_up_interruptible (sk->sk_sleep); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND );if (!inet_csk_ack_scheduled (sk)) inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, (3 * TCP_RTO_MIN) / 4,
kernel/kevent/kevent_socket.c new file +144 -0
144 lines not on this page · raw message
net/core/sock.c +9 -1
@@ -1402,6 +1402,7 @@ static void sock_def_wakeup(struct sock *sk)if (sk->sk_sleep &&waitqueue_active (sk->sk_sleep))wake_up_interruptible_all (sk->sk_sleep);read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_error_report (struct sock *sk)
@@ -1411,6 +1412,7 @@ static void sock_def_error_report(struct sock *sk)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,0 ,POLL_ERR );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_readable (struct sock *sk,int len)
@@ -1420,6 +1422,7 @@ static void sock_def_readable(struct sock *sk, int len)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,1 ,POLL_IN );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_write_space (struct sock *sk)
@@ -1439,6 +1442,7 @@ static void sock_def_write_space(struct sock *sk) }read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); }static void sock_def_destruct (struct sock *sk)
@@ -1489,6 +1493,8 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_state =TCP_CLOSE ; sk->sk_socket = sock; +kevent_sk_reinit (sk); +sock_set_flag (sk,SOCK_ZAPPED );if (sock)
@@ -1555,8 +1561,10 @@ void fastcall release_sock(struct sock *sk)if (sk->sk_backlog.tail)__release_sock (sk); sk->sk_lock.owner =NULL ; -if (waitqueue_active (&sk->sk_lock.wq)) +if (waitqueue_active (&sk->sk_lock.wq)) {wake_up (&sk->sk_lock.wq); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); + }spin_unlock_bh (&sk->sk_lock.slock); }EXPORT_SYMBOL (release_sock);
net/core/stream.c +1 -0
@@ -36,6 +36,7 @@ void sk_stream_write_space(struct sock *sk)wake_up_interruptible (sk->sk_sleep);if (sock->fasync_list && !(sk->sk_shutdown &SEND_SHUTDOWN ))sock_wake_async (sock,2 ,POLL_OUT ); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); } }
net/ipv4/tcp_input.c +1 -0
@@ -3119,6 +3119,7 @@ static void tcp_ofo_queue(struct sock *sk)__skb_unlink (skb, &tp->out_of_order_queue);__skb_queue_tail (&sk->sk_receive_queue, skb); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); tp->rcv_nxt =TCP_SKB_CB (skb)->end_seq;if (skb->h.th->fin)tcp_fin (skb, sk, skb->h.th);
net/ipv4/tcp_ipv4.c +2 -0
@@ -61,6 +61,7 @@#include <linux/jhash.h> #include <linux/init.h> #include <linux/times.h> +#include <linux/kevent.h> #include <net/icmp.h> #include <net/inet_hashtables.h>
@@ -870,6 +871,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)reqsk_free (req); }else {inet_csk_reqsk_queue_hash_add (sk, req,TCP_TIMEOUT_INIT ); +kevent_socket_notify (sk,KEVENT_SOCKET_ACCEPT ); }return 0 ;
net/socket.c +3 -0
@@ -85,6 +85,7 @@#include <linux/kmod.h> #include <linux/audit.h> #include <linux/wireless.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -490,6 +491,8 @@ static struct socket *sock_alloc(void) inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; +kevent_socket_reinit (sock); +get_cpu_var (sockets_in_use)++;put_cpu_var (sockets_in_use);return sock;
PATCH 5/8 kevent: Timer notifications.
Timer notifications.
Timer notifications can be used for fine grained per-process time management, since interval timers are very inconvenient to use, and they are limited.
This subsystem uses high-resolution timers.
id.raw[0] is used as number of seconds
id.raw[1] is used as number of nanoseconds
kernel/kevent/kevent_timer.c new file +114 -0
@@ -0,0 +1,114 @@ +/* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/jiffies.h> +#include <linux/kevent.h> + +struct kevent_timer +{ +struct hrtimer ktimer; +struct kevent_storage ktimer_storage; +struct kevent *ktimer_event; +}; + +static int kevent_timer_func (struct hrtimer *timer) +{ + struct kevent_timer *t = container_of(timer, struct kevent_timer, ktimer); +struct kevent *k = t->ktimer_event; + +kevent_storage_ready (&t->ktimer_storage,NULL ,KEVENT_MASK_ALL ); +hrtimer_forward (timer, timer->base->softirq_time, +ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ])); +return HRTIMER_RESTART ; +} + +static struct lock_class_key kevent_timer_key; + +static int kevent_timer_enqueue (struct kevent *k) +{ +int err; +struct kevent_timer *t; + + t =kmalloc (sizeof (struct kevent_timer ),GFP_KERNEL ); +if (!t) +return -ENOMEM ; + +hrtimer_init (&t->ktimer,CLOCK_MONOTONIC ,HRTIMER_REL ); + t->ktimer.expires =ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ]); + t->ktimer.function = kevent_timer_func; + t->ktimer_event = k; + + err =kevent_storage_init (&t->ktimer, &t->ktimer_storage); +if (err) + goto err_out_free; +lockdep_set_class (&t->ktimer_storage.lock, &kevent_timer_key); + + err =kevent_storage_enqueue (&t->ktimer_storage, k); +if (err) + goto err_out_st_fini; + +hrtimer_start (&t->ktimer, t->ktimer.expires,HRTIMER_REL ); + +return 0 ; + +err_out_st_fini: +kevent_storage_fini (&t->ktimer_storage); +err_out_free: +kfree (t); + +return err; +} + +static int kevent_timer_dequeue (struct kevent *k) +{ +struct kevent_storage *st = k->st; + struct kevent_timer *t = container_of(st, struct kevent_timer, ktimer_storage); + +hrtimer_cancel (&t->ktimer); +kevent_storage_dequeue (st, k); +kfree (t); + +return 0 ; +} + +static int kevent_timer_callback (struct kevent *k) +{ + k->event.ret_data[0 ] =jiffies_to_msecs (jiffies); +return 1 ; +} + +static int __init kevent_init_timer (void ) +{ +struct kevent_callbacks tc = { + .callback = &kevent_timer_callback, + .enqueue = &kevent_timer_enqueue, + .dequeue = &kevent_timer_dequeue, + .flags =0 , + }; + +return kevent_add_callbacks (&tc,KEVENT_TIMER ); +} +module_init (kevent_init_timer); +
PATCH 6/8 kevent: Pipe notifications.
Pipe notifications.
fs/pipe.c +6 -0
@@ -16,6 +16,7 @@#include <linux/uio.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/ioctls.h>
@@ -312,6 +313,7 @@ redo:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -321,6 +323,7 @@ redo:/* Signal writers asynchronously that there is more room. */ if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -490,6 +493,7 @@ redo2:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); do_wakeup =0 ;
@@ -501,6 +505,7 @@ redo2: out:mutex_unlock (&inode->i_mutex);if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); }
@@ -605,6 +610,7 @@ pipe_release(struct inode *inode, int decr, int decw)free_pipe_info (inode); }else {wake_up_interruptible (&pipe->wait); +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV );kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN );kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
kernel/kevent/kevent_pipe.c new file +123 -0
123 lines not on this page · raw message
PATCH 7/8 kevent: Signal notifications.
Signal notifications.
This type of notifications allows to deliver signals through kevent queue. One can find example application signal.c on project homepage.
If KEVENT_SIGNAL_NOMASK bit is set in raw_u64 id then signal will be delivered only through queue, otherwise both delivery types are used - old through update of mask of pending signals and through queue.
If signal is delivered only through kevent queue mask of pending signals is not updated at all, which is equal to putting signal into blocked mask, but with delivery of that signal through kevent queue.
include/linux/sched.h +5 -0
@@ -80,6 +80,7 @@ struct sched_param {#include <linux/resource.h> #include <linux/timer.h> #include <linux/hrtimer.h> +#include <linux/kevent_storage.h> #include <asm/processor.h>
@@ -1013,6 +1014,10 @@ struct task_struct {#ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info *delays;#endif +#ifdef CONFIG_KEVENT_SIGNAL +struct kevent_storage st; +u32 kevent_signals; +#endif };static inline pid_t process_group (struct task_struct *tsk)
kernel/fork.c +8 -0
@@ -46,6 +46,7 @@#include <linux/delayacct.h> #include <linux/taskstats_kern.h> #include <linux/random.h> +#include <linux/kevent.h> #include <asm/pgtable.h> #include <asm/pgalloc.h>
@@ -115,6 +116,9 @@ void __put_task_struct(struct task_struct *tsk)WARN_ON (atomic_read (&tsk->usage));WARN_ON (tsk == current); +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_fini (&tsk->st); +#endif security_task_free (tsk);free_uid (tsk->user);put_group_info (tsk->group_info);
@@ -1121,6 +1125,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,if (retval) goto bad_fork_cleanup_namespace; +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_init (p, &p->st); +#endif + p->set_child_tid = (clone_flags &CLONE_CHILD_SETTID ) ? child_tidptr :NULL ;/* * Clear TID on mm_release()?
kernel/kevent/kevent_signal.c new file +94 -0
94 lines not on this page · raw message
kernel/signal.c +26 -0
@@ -23,6 +23,7 @@#include <linux/ptrace.h> #include <linux/signal.h> #include <linux/capability.h> +#include <linux/kevent.h> #include <asm/param.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -703,6 +704,9 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, {struct sigqueue * q =NULL ;int ret =0 ; + +if (kevent_signal_notify (t, sig)) +return 1 ;/* * fast-pathed signals for kernel-internal things like SIGSTOP
@@ -782,6 +786,17 @@ 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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif out:return ret; }
@@ -971,6 +986,17 @@ __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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif if (unlikely (ret))return ret;
PATCH 8/8 kevent: Kevent posix timer notifications.
Kevent posix timer notifications.
Simple extensions to POSIX timers which allows
to deliver notification of the timer expiration
through kevent queue.
Example application posix_timer.c can be found
in archive on project homepage.
include/asm-generic/siginfo.h +3 -0
@@ -235,6 +235,7 @@ typedef struct siginfo {#define SIGEV_NONE 1/* other notification: meaningless */ #define SIGEV_THREAD 2/* deliver via thread creation */ #define SIGEV_THREAD_ID 4/* deliver to thread */ +#define SIGEV_KEVENT 8/* deliver through kevent queue */ /* * This works because the alignment is ok on all current architectures
@@ -260,6 +261,8 @@ typedef struct sigevent {void (*_function)(sigval_t );void *_attribute;/* really pthread_attr_t */ } _sigev_thread; + +int kevent_fd; } _sigev_un; } sigevent_t;
include/linux/posix-timers.h +4 -0
@@ -4,6 +4,7 @@#include <linux/spinlock.h> #include <linux/list.h> #include <linux/sched.h> +#include <linux/kevent_storage.h> union cpu_time_count {cputime_t cpu;
@@ -49,6 +50,9 @@ struct k_itimer {sigval_t it_sigev_value;/* value word of sigevent struct */ struct task_struct *it_process;/* process to send signal to */ struct sigqueue *sigq;/* signal queue entry. */ +#ifdef CONFIG_KEVENT_TIMER +struct kevent_storage st; +#endif union { struct { struct hrtimer timer;
kernel/posix-timers.c +171 -48
264 lines not on this page · raw message
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
In reply to Evgeniy PolyakovQuoted 14 lines · Evgeniy Polyakov
Generic event handling mechanism.
Kevent is a generic subsytem which allows to handle event notifications. It supports both level and edge triggered events. It is similar to poll/epoll in some cases, but it is more scalable, it is faster and allows to work with essentially eny kind of events.
Events are provided into kernel through control syscall and can be read back through ring buffer or using usual syscalls.
Kevent update (i.e. readiness switching) happens directly from internals of the appropriate state machine of the underlying subsytem (like network, filesystem, timer or any other).
Quoted 7 lines
Homepage:
http://tservice.net.ru/~s0mbre/old/?section=projects&item=keventDocumentation page:
http://linux-net.osdl.org/index.php/KeventConsider for inclusion.
Due to this stall kevent inclusion into lighttpd CVS tree is postponed.
The last version will be released saturday or sunday, and looking into overhelming flow of feedback comments on this feature, project will not be released to linux-kernel@, after this I will
complete netchannels support and start kevent based AIO project - mostly network AIO with new design, which is based on set of entities, which can describe set of tasks which should be performed asynchronously (from user point of view, although read and write obviously must be done after open and before close), for example syscall which gets as parameter destination socket and local filename (with optional offset and length fields), which will asynchronously from user point of view open a file and transfer requested part to the destination socket and then return opened file descriptor (or it can be closed if requested). Similar mechanism can be done for read/write calls.
Interested parties will be able to apply patches for theirs own kernels.
Signature · 1 line
Evgeniy Polyakov
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 24 lines · Evgeniy Polyakov
Quoted 13 lines · Evgeniy Polyakov
Generic event handling mechanism.
Kevent is a generic subsytem which allows to handle event notifications. It supports both level and edge triggered events. It is similar to poll/epoll in some cases, but it is more scalable, it is faster and allows to work with essentially eny kind of events.
Events are provided into kernel through control syscall and can be read back through ring buffer or using usual syscalls.
Kevent update (i.e. readiness switching) happens directly from internals of the appropriate state machine of the underlying subsytem (like network, filesystem, timer or any other).Quoted 7 lines
Homepage:
http://tservice.net.ru/~s0mbre/old/?section=projects&item=keventDocumentation page:
http://linux-net.osdl.org/index.php/KeventConsider for inclusion.
Due to this stall kevent inclusion into lighttpd CVS tree is postponed.
Quoted 8 lines
The last version will be released saturday or sunday, and looking into overhelming flow of feedback comments on this feature, project will not be released to linux-kernel@, after this I will
complete netchannels support and start kevent based AIO project - mostly network AIO with new design, which is based on set of entities, which can describe set of tasks which should be performed asynchronously (from user point of view, although read and write obviously must be done after open and before close), for example syscall
kevent is being considered for inclusion, but there is no need to get impatient. Once kevent code stops getting revised rapidly, Andrew Morton can pick it up for -mm, for wide dissemination, testing and review. After that phase, it can be pushed to mainline.
The feeling I get from other kernel hackers is that you are demanding inclusion "now! now! now!" rather than giving all stakeholders a chance to give input, and let your design sink into the collective brain.
This isn't just an optional feature but a key new addition to the kernel. So we should intentionally take more time and consideration than normal. We don't want to go back and have to change fundamental kevent details due to design flaws, we want to get it right.
Jeff
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 35 lines · Jeff Garzik
Quoted 25 lines · Evgeniy Polyakov
Quoted 13 lines · Evgeniy Polyakov
Generic event handling mechanism.
Kevent is a generic subsytem which allows to handle event notifications. It supports both level and edge triggered events. It is similar to poll/epoll in some cases, but it is more scalable, it is faster and allows to work with essentially eny kind of events.
Events are provided into kernel through control syscall and can be read back through ring buffer or using usual syscalls.
Kevent update (i.e. readiness switching) happens directly from internals of the appropriate state machine of the underlying subsytem (like network, filesystem, timer or any other).Quoted 7 lines
Homepage:
http://tservice.net.ru/~s0mbre/old/?section=projects&item=keventDocumentation page:
http://linux-net.osdl.org/index.php/KeventConsider for inclusion.
Due to this stall kevent inclusion into lighttpd CVS tree is postponed.
Quoted 8 lines
The last version will be released saturday or sunday, and looking into overhelming flow of feedback comments on this feature, project will not be released to linux-kernel@, after this I will
complete netchannels support and start kevent based AIO project - mostly network AIO with new design, which is based on set of entities, which can describe set of tasks which should be performed asynchronously (from user point of view, although read and write obviously must be done after open and before close), for example syscall
Quoted 4 lines
kevent is being considered for inclusion, but there is no need to get impatient. Once kevent code stops getting revised rapidly, Andrew Morton can pick it up for -mm, for wide dissemination, testing and review. After that phase, it can be pushed to mainline.
I do not say 'hey, include it now, or I will cry', I just want to have _some_ progress. But I do not get _any_ feedback. What should I think? I doubt bothering people each third day with new resend is a good idea, so I plan to drop it.
Btw, Andrew dropped 'take23' patchset from his tree, when it was obsoleted, but did not import later versions :)
Quoted 3 lines
The feeling I get from other kernel hackers is that you are demanding inclusion "now! now! now!" rather than giving all stakeholders a chance to give input, and let your design sink into the collective brain.
No. I do not want immediate inclusion, I want progress, so I could setup my plans on it - if people keep silence, I stop this and work on my own kevent goals, since I like current state of hte kevent for my tasks.
I do not hack for inclusion.
Quoted 4 lines
This isn't just an optional feature but a key new addition to the kernel. So we should intentionally take more time and consideration than normal. We don't want to go back and have to change fundamental kevent details due to design flaws, we want to get it right.
So comment on its bugs, its design, implementation, ask questions, request features, show interest (even with 'I have no time right now, but will loko at it after in a week after vacations').
No one does it, so no one cares, so my behaviour.
Quoted 1 line
Jeff
Signature · 1 line
Evgeniy Polyakov
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 5 lines · Evgeniy Polyakov
So comment on its bugs, its design, implementation, ask questions, request features, show interest (even with 'I have no time right now, but will loko at it after in a week after vacations').
No one does it, so no one cares, so my behaviour.
Btw, kevent will celebrate its first birtday (one year!) in two weeks (Jan 6). Feel free to party!
Signature · 1 line
Evgeniy Polyakov
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
In reply to Evgeniy PolyakovEvgeniy,
Quoted 6 lines · Evgeniy Polyakov
So comment on its bugs, its design, implementation, ask questions, request features, show interest (even with 'I have no time right now, but will loko at it after in a week after vacations').
No one does it, so no one cares, so my behaviour.
Please dont be discouraged by lack of attention - you are doing good work.
I will concur with Jeff's point that since you are putting out a profound conceptual changes, and there are many stake holders, it requires scrutiny on their part. You need to build consensus in such a situation.
Some things that would help progress and build momentum:
- As i have advised you before, why dont you modify something like existing libraries such as some of the loop thingies of desktop managers such as kde/gnome or better things like libevent etc. Then write your app on top of that? nobody is gonna run your httpd but if you demonstrate that libevent is much better with your changes (with zero changes to apps), people will migrate
- from a user space angle if people like Ulrich would state their views on the current version you have.
Note, they dont have to agree with you i.e the conclusion could be a simple "agree to disagree".
- There really oughta be a limit on how long people are allowed to be silent. After that IMO your code should just go in ...
cheers,
jamal
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 23 lines · jamal
Evgeniy,
Quoted 6 lines · Evgeniy Polyakov
So comment on its bugs, its design, implementation, ask questions, request features, show interest (even with 'I have no time right now, but will loko at it after in a week after vacations').
No one does it, so no one cares, so my behaviour.
Please dont be discouraged by lack of attention - you are doing good work.
I will concur with Jeff's point that since you are putting out a profound conceptual changes, and there are many stake holders, it requires scrutiny on their part. You need to build consensus in such a situation.
Some things that would help progress and build momentum:
- As i have advised you before, why dont you modify something like existing libraries such as some of the loop thingies of desktop managers such as kde/gnome or better things like libevent etc. Then write your app on top of that? nobody is gonna run your httpd but if you
Quoted 8 lines
demonstrate that libevent is much better with your changes (with zero changes to apps), people will migrate
- from a user space angle if people like Ulrich would state their views on the current version you have.
Note, they dont have to agree with you i.e the conclusion could be a simple "agree to disagree".
- There really oughta be a limit on how long people are allowed to be silent. After that IMO your code should just go in ...
I modified world-wide used web server lighttpd and ran a lot of tests with it (compared to epoll version with major performance win).
I was asked yesterday by Jan Kneschke (lighttpd main developer) if kevent API is ready so he could include my patch into mainline lighttpd tree, but I answered 'I do not know if kevent will be or not included, everyone keeps silence'.
I just do not know _what_ else should be done not even for inclusion - but at least for some progress.
You want libevent to be patched? Its site is currently down, but ok, I will create a patch.
Quoted 2 lines
cheers,
jamal
Signature · 1 line
Evgeniy Polyakov
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 8 lines · Evgeniy Polyakov
I modified world-wide used web server lighttpd and ran a lot of tests with it (compared to epoll version with major performance win).
I was asked yesterday by Jan Kneschke (lighttpd main developer) if kevent API is ready so he could include my patch into mainline lighttpd tree, but I answered 'I do not know if kevent will be or not included, everyone keeps silence'.
Ok, so you are building the momentum then. People like Jan are the users of such API and should be speaking up. Then kernel people will be forced to look at it.
Quoted 2 lines
I just do not know _what_ else should be done not even for inclusion - but at least for some progress.
I know you are frustrated but stop doing the above like a broken vinyl record, it doesnt help your case.
Quoted 3 lines
You want libevent to be patched? Its site is currently down, but ok, I will create a patch.
I promise in 2 weeks to migrate an app or two that i have that use libevent to your version if you have it by then. I will then test and give you my opinion.
cheers,
jamal
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 5 lines · jamal
Quoted 2 lines
I just do not know _what_ else should be done not even for inclusion - but at least for some progress.
I know you are frustrated but stop doing the above like a broken vinyl record, it doesnt help your case.
That's why I'm going to stop void resending completely.
Quoted 7 lines
Quoted 3 lines
You want libevent to be patched? Its site is currently down, but ok, I will create a patch.
I promise in 2 weeks to migrate an app or two that i have that use libevent to your version if you have it by then. I will then test and give you my opinion.
Ok, when site will be ready I will patch libevent and post patch or link in this thread. I plan to complete it this week.
Quoted 2 lines
cheers,
jamal
Signature · 1 line
Evgeniy Polyakov
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 2 lines · Evgeniy Polyakov
Ok, when site will be ready I will patch libevent and post patch or link in this thread. I plan to complete it this week.
Btw, it uses only read/write/signal on fd events, so it must use ->poll() and thus be as fast as epoll.
Things like sockets/pipes can only benefit from direct kevent usage instead of ->poll() and wrappers.
Signature · 1 line
Evgeniy Polyakov
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 3 lines · Evgeniy Polyakov
Btw, it uses only read/write/signal on fd events, so it must use ->poll() and thus be as fast as epoll.
It is supposed to "detect" the best mechanism in the kernel and switch to that.
At the moment for example in my app it defaults to epoll.
Quoted 2 lines
Things like sockets/pipes can only benefit from direct kevent usage instead of ->poll() and wrappers.
You should be able change it to use those schemes when it detects that the kernel supports them.
cheers,
jamal
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 5 lines · jamal
Quoted 2 lines
Things like sockets/pipes can only benefit from direct kevent usage instead of ->poll() and wrappers.
You should be able change it to use those schemes when it detects that the kernel supports them.
I.e. stat() for each new file descriptor - note, that _you_ asked it :)
Quoted 2 lines
cheers,
jamal
Signature · 1 line
Evgeniy Polyakov
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 8 lines · Evgeniy Polyakov
Quoted 5 lines · jamal
Quoted 2 lines
Things like sockets/pipes can only benefit from direct kevent usage instead of ->poll() and wrappers.
You should be able change it to use those schemes when it detects that the kernel supports them.
I.e.
stat()for each new file descriptor - note, that _you_ asked it :)
Didnt follow. Is there some issue with libevent you mean?
cheers,
jamal
Re: [take28-resend_1->0 0/8] kevent: Generic event handling mechanism.
Quoted 9 lines · jamal
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
Things like sockets/pipes can only benefit from direct kevent usage instead of ->poll() and wrappers.
You should be able change it to use those schemes when it detects that the kernel supports them.
I.e.
stat()for each new file descriptor - note, that _you_ asked it :)Didnt follow. Is there some issue with libevent you mean?
libevent provides file descriptor without any additional info about it - so when it is added into the waiting subsystem, userspace must select different usage cases (i.e. different kevent notifications for different types of file descriptor - socket notifications for sockets and pipes, poll/select for all others), this requires stat() call per provided file descriptor.
Event addition/waiting itself is the same - only parameters (type and requested event) are changed.
Quoted 2 lines
cheers,
jamal
Signature · 1 line
Evgeniy Polyakov
cover kevent: Generic event handling mechanism.
In reply to a message not in the archiveGeneric event handling mechanism.
Kevent is a generic subsytem which allows to handle event notifications. It supports both level and edge triggered events. It is similar to poll/epoll in some cases, but it is more scalable, it is faster and allows to work with essentially eny kind of events.
Events are provided into kernel through control syscall and can be read back through ring buffer or using usual syscalls.
Kevent update (i.e. readiness switching) happens directly from internals of the appropriate state machine of the underlying subsytem (like network, filesystem, timer or any other).
Homepage:
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
Documentation page:
http://linux-net.osdl.org/index.php/Kevent
Consider for inclusion.
New benchmark, which can be a hoax though, can be found at
http://tservice.net.ru/~s0mbre/blog/2006/11/30#2006_11_30
where kevent on amd64 with 1gb of ram can handle more than 7200 events per second with 8000 requests concurrency with 'ab' benchmark and lighttpd. Although I tought it should not be published due to possible errors, I decided to send it for review.
With this release I start 3 days resending timeout - i.e. each third day I will send either new version (if something new was requested and agreed to be implemented) or resending with back counter started from three. When back counter hits zero after three resending I consider there is no interest in subsystem and I will stop further sending.
First one will be sent about Jan 10.
Thanks for understanding and your time.
Changes from 'take28' patchset:
* optimized af_unix to use socket notifications
* changed ALWAYS_QUEUE behaviour with poll/select notifications - previously kevent was not queued into poll wait queue when ALWAYS_QUEUE flag is set
* added KEVENT_POLL_POLLRDHUP definition into ukevent.h header
* libevent-1.2 patch (Jamal, your request is completed, so I'm waiting two weeks before starting final countdown :)
All regression tests passed successfully except test_evbuffer(), which crashes on my amd64 linux 2.6 test machine for all types of notifications, probably it is fixed in libevent-1.2a version, I did not check. Patch and README can be found at project homepage.
Changes from 'take27' patchset:
* made kevent default yes in non embedded case.
* added falgs to callback structures - currently used to check if kevent can be requested from kernelspace only (posix timers) or userspace (all others)
Changes from 'take26' patchset:
* made kevent visible in config only in case of embedded setup.
* added comment about KEVENT_MAX number.
* spell fix.
Changes from 'take25' patchset:
* use timespec as timeout parameter.
* added high-resolution timer to handle absolute timeouts.
* added flags to waiting and initialization syscalls.
* kevent_commit() has new_uidx parameter.
* kevent_wait() has old_uidx parameter, which, if not equal to u->uidx, results in immediate wakeup (usefull for the case when entries
are added asynchronously from kernel (not supported for now)).
* added interface to mark any event as ready.
* event POSIX timers support.
* return -ENOSYS if there is no registered event type.
* provided file descriptor must be checked for fifo type (spotted by Eric Dumazet).
* signal notifications.
* documentation update.
* lighttpd patch updated (the latest benchmarks with lighttpd patch can be found in blog).
Changes from 'take24' patchset:
* new (old (new)) ring buffer implementation with kernel and user indexes.
* added initialization syscall instead of opening /dev/kevent
* kevent_commit() syscall to commit ring buffer entries
* changed KEVENT_REQ_WAKEUP_ONE flag to KEVENT_REQ_WAKEUP_ALL, kevent wakes only first thread always if that flag is not set
* KEVENT_REQ_ALWAYS_QUEUE flag. If set, kevent will be queued into ready queue instead of copying back to userspace when kevent is ready immediately when it is added.
* lighttpd patch (Hail! Although nothing really outstanding compared to epoll)
Changes from 'take23' patchset:
* kevent PIPE notifications
* KEVENT_REQ_LAST_CHECK flag, which allows to perform last check at dequeueing time
* fixed poll/select notifications (were broken due to tree manipulations)
* made Documentation/kevent.txt look nice in 80-col terminal
* fix for copy_to_user() failure report for the first kevent (Andrew Morton)
* minor function renames
Changes from 'take22' patchset:
* new ring buffer implementation in process' memory
* wakeup-one-thread flag
* edge-triggered behaviour
Changes from 'take21' patchset:
* minor cleanups (different return values, removed unneded variables, whitespaces and so on)
* fixed bug in kevent removal in case when kevent being removed
is the same as overflow_kevent (spotted by Eric Dumazet)
Changes from 'take20' patchset:
* new ring buffer implementation
* removed artificial limit on possible number of kevents
Changes from 'take19' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take18' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take17' patchset:
* Use RB tree instead of hash table.
At least for a web sever, frequency of addition/deletion of new kevent is comparable with number of search access, i.e. most of the time events are added, accesed only couple of times and then removed, so it justifies RB tree usage over AVL tree, since the latter does have much slower deletion time (max O(log(N)) compared to 3 ops),
although faster search time (1.44*O(log(N)) vs. 2*O(log(N))).
So for kevents I use RB tree for now and later, when my AVL tree implementation is ready, it will be possible to compare them.
* Changed readiness check for socket notifications.
With both above changes it is possible to achieve more than 3380 req/second compared to 2200, sometimes 2500 req/second for epoll() for trivial web-server and httperf client on the same hardware.
It is possible that above kevent limit is due to maximum allowed kevents in a time limit, which is 4096 events.
Changes from 'take16' patchset:
* misc cleanups (__read_mostly, const ...)
* created special macro which is used for mmap size (number of pages) calculation
* export kevent_socket_notify(), since it is used in network protocols which can be built as modules (IPv6 for example)
Changes from 'take15' patchset:
* converted kevent_timer to high-resolution timers, this forces timer API update at
http://linux-net.osdl.org/index.php/Kevent
* use struct ukevent* instead of void * in syscalls (documentation has been updated)
* added warning in kevent_add_ukevent() if ring has broken index (for testing)
Changes from 'take14' patchset:
* added kevent_wait()
This syscall waits until either timeout expires or at least one event becomes ready. It also commits that @num events from @start are processed by userspace and thus can be be removed or rearmed (depending on it's flags). It can be used for commit events read by userspace through mmap interface. Example userspace code (evtest.c) can be found on project's homepage.
* added socket notifications (send/recv/accept)
Changes from 'take13' patchset:
* do not get lock aroung user data check in __kevent_search()
* fail early if there were no registered callbacks for given type of kevent
* trailing whitespace cleanup
Changes from 'take12' patchset:
* remove non-chardev interface for initialization
* use pointer to kevent_mring instead of unsigned longs
* use aligned 64bit type in raw user data (can be used by high-res timer if needed)
* simplified enqueue/dequeue callbacks and kevent initialization
* use nanoseconds for timeout
* put number of milliseconds into timer's return data
* move some definitions into user-visible header
* removed filenames from comments
Changes from 'take11' patchset:
* include missing headers into patchset
* some trivial code cleanups (use goto instead of if/else games and so on)
* some whitespace cleanups
* check for ready_callback() callback before main loop which should save us some ticks
Changes from 'take10' patchset:
* removed non-existent prototypes
* added helper function for kevent_registered_callbacks
* fixed 80 lines comments issues
* added shared between userspace and kernelspace header instead of embedd them in one
* core restructuring to remove forward declarations
* s o m e w h i t e s p a c e c o d y n g s t y l e c l e a n u p
* use vm_insert_page() instead of remap_pfn_range()
Changes from 'take9' patchset:
* fixed ->nopage method
Changes from 'take8' patchset:
* fixed mmap release bug
* use module_init() instead of late_initcall()
* use better structures for timer notifications
Changes from 'take7' patchset:
* new mmap interface (not tested, waiting for other changes to be acked)
- use nopage() method to dynamically substitue pages
- allocate new page for events only when new added kevent requres it
- do not use ugly index dereferencing, use structure instead
- reduced amount of data in the ring (id and flags), maximum 12 pages on x86 per kevent fd
Changes from 'take6' patchset:
* a lot of comments!
* do not use list poisoning for detection of the fact, that entry is in the list
* return number of ready kevents even if copy*user() fails
* strict check for number of kevents in syscall
* use ARRAY_SIZE for array size calculation
* changed superblock magic number
* use SLAB_PANIC instead of direct panic() call
* changed -E* return values
* a lot of small cleanups and indent fixes
Changes from 'take5' patchset:
* removed compilation warnings about unused wariables when lockdep is not turned on
* do not use internal socket structures, use appropriate (exported) wrappers instead
* removed default 1 second timeout
* removed AIO stuff from patchset
Changes from 'take4' patchset:
* use miscdevice instead of chardevice
* comments fixes
Changes from 'take3' patchset:
* removed serializing mutex from kevent_user_wait()
* moved storage list processing to RCU
* removed lockdep screaming - all storage locks are initialized in the same function, so it was
learned
to differentiate between various cases
* remove kevent from storage if is marked as broken after callback
* fixed a typo in mmaped buffer implementation which would end up in wrong index calcualtion
Changes from 'take2' patchset:
* split kevent_finish_user() to locked and unlocked variants
* do not use KEVENT_STAT ifdefs, use inline functions instead
* use array of callbacks of each type instead of each kevent callback initialization
* changed name of ukevent guarding lock
* use only one kevent lock in kevent_user for all hash buckets instead of per-bucket locks
* do not use kevent_user_ctl structure instead provide needed arguments as syscall parameters
* various indent cleanups
* added optimisation, which is aimed to help when a lot of kevents are being copied from
userspace
* mapped buffer (initial) implementation (no userspace yet)
Changes from 'take1' patchset:
- rebased against 2.6.18-git tree
- removed ioctl controlling
- added new syscall kevent_get_events(int fd, unsigned int min_nr, unsigned int max_nr, unsigned int timeout, void __user *buf, unsigned flags)
- use old syscall kevent_ctl for creation/removing, modification and initial kevent initialization
- use mutuxes instead of semaphores
- added file descriptor check and return error if provided descriptor does not match kevent file operations
- various indent fixes
- removed aio_sendfile() declarations.
Thank you.
PATCH 1/8 kevent: Description.
Description.
Documentation/kevent.txt new file +240 -0
@@ -0,0 +1,240 @@ +Description. + +int kevent_init(struct kevent_ring *ring, unsigned int ring_size, + unsigned int flags); + +num - size of the ring buffer in events +ring - pointer to allocated ring buffer +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: kevent control file descriptor or negative error value. + + struct kevent_ring + { + unsigned int ring_kidx, ring_over; + struct ukevent event[0]; + } + +ring_kidx - index in the ring buffer where kernel will put new events + when kevent_wait() or kevent_get_events() is called +ring_over - number of overflows of ring_uidx happend from the start. + Overflow counter is used to prevent situation when two threads + are going to free the same events, but one of them was scheduled + away for too long, so ring indexes were wrapped, so when that + thread will be awakened, it will free not those events, which + it suppose to free. + +Example userspace code (ring_buffer.c) can be found on project's homepage. + +Each kevent syscall can be so called cancellation point in glibc, i.e. when +thread has been cancelled in kevent syscall, thread can be safely removed +and no events will be lost, since each syscall (kevent_wait() or +kevent_get_events()) will copy event into special ring buffer, accessible +from other threads or even processes (if shared memory is used). + +When kevent is removed (not dequeued when it is ready, but just removed), +even if it was ready, it is not copied into ring buffer, since if it is +removed, no one cares about it (otherwise user would wait until it becomes +ready and got it through usual way using kevent_get_events() or kevent_wait()) +and thus no need to copy it to the ring buffer. + +------------------------------------------------------------------------------- + + +int kevent_ctl(int fd, unsigned int cmd, unsigned int num, struct ukevent *arg); + +fd - is the file descriptor referring to the kevent queue to manipulate. +It is created by opening "/dev/kevent" char device, which is created with +dynamic minor number and major number assigned for misc devices. + +cmd - is the requested operation. It can be one of the following: + KEVENT_CTL_ADD - add event notification + KEVENT_CTL_REMOVE - remove event notification + KEVENT_CTL_MODIFY - modify existing notification + KEVENT_CTL_READY - mark existing events as ready, if number of events is zero, + it just wakes up parked in syscall thread + +num - number of struct ukevent in the array pointed to by arg +arg - array of struct ukevent + +Return value: + number of events processed or negative error value. + +When called, kevent_ctl will carry out the operation specified in the +cmd parameter. +------------------------------------------------------------------------------- + + int kevent_get_events(int ctl_fd, unsigned int min_nr, unsigned int max_nr, + struct timespec timeout, struct ukevent *buf, unsigned flags); + +ctl_fd - file descriptor referring to the kevent queue +min_nr - minimum number of completed events that kevent_get_events will block + waiting for +max_nr - number of struct ukevent in buf +timeout - time to wait before returning less than min_nr + events. If this is -1, then wait forever. +buf - pointer to an array of struct ukevent. +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied or negative error value. + +kevent_get_events will wait timeout milliseconds for at least min_nr completed +events, copying completed struct ukevents to buf and deleting any +KEVENT_REQ_ONESHOT event requests. In nonblocking mode it returns as many +events as possible, but not more than max_nr. In blocking mode it waits until +timeout or if at least min_nr events are ready. + +This function copies event into ring buffer if it was initialized, if ring buffer +is full, KEVENT_RET_COPY_FAILED flag is set in ret_flags field. +------------------------------------------------------------------------------- + + int kevent_wait(int ctl_fd, unsigned int num, unsigned int old_uidx, + struct timespec timeout, unsigned int flags); + +ctl_fd - file descriptor referring to the kevent queue +num - number of processed kevents +old_uidx - the last index user is aware of +timeout - time to wait until there is free space in kevent queue +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied into ring buffer or negative error value. + +This syscall waits until either timeout expires or at least one event becomes +ready. It also copies events into special ring buffer. If ring buffer is full, +it waits until there are ready events and then return. +If kevent is one-shot kevent it is removed in this syscall. +If kevent is edge-triggered (KEVENT_REQ_ET flag is set in 'req_flags') it is +requeued in this syscall for performance reasons. +------------------------------------------------------------------------------- + + int kevent_commit(int ctl_fd, unsigned int new_idx, unsigned int over); + +ctl_fd - file descriptor referring to the kevent queue +new_uidx - the last committed kevent +over - overflow count for given $new_idx value + +Return value: + number of committed kevents or negative error value. + +This function commits, i.e. marks as empty, slots in the ring buffer, so +they can be reused when userspace completes that entries processing. + +Overflow counter is used to prevent situation when two threads are going +to free the same events, but one of them was scheduled away for too long, +so ring indexes were wrapped, so when that thread will be awakened, it +will free not those events, which it suppose to free. + +It is possible that returned number of committed events will be smaller than +requested number - it is possible when several threads try to commit the +same events. +------------------------------------------------------------------------------- + +The bulk of the interface is entirely done through the ukevent struct. +It is used to add event requests, modify existing event requests, +specify which event requests to remove, and return completed events. + +struct ukevent contains the following members: + +struct kevent_id id + Id of this request, e.g. socket number, file descriptor and so on +__u32 type + Event type, e.g. KEVENT_SOCK, KEVENT_INODE, KEVENT_TIMER and so on +__u32 event + Event itself, e.g. SOCK_ACCEPT, INODE_CREATED, TIMER_FIRED +__u32 req_flags + Per-event request flags, + + KEVENT_REQ_ONESHOT + event will be removed when it is ready + + KEVENT_REQ_WAKEUP_ALL + Kevent wakes up only first thread interested in given event, + or all threads if this flag is set. + + KEVENT_REQ_ET + Edge Triggered behaviour. It is an optimisation which allows to move + ready and dequeued (i.e. copied to userspace) event to move into set + of interest for given storage (socket, inode and so on) again. It is + very usefull for cases when the same event should be used many times + (like reading from pipe). It is similar to epoll()'s EPOLLET flag. + + KEVENT_REQ_LAST_CHECK + if set allows to perform the last check on kevent (call appropriate + callback) when kevent is marked as ready and has been removed from + ready queue. If it will be confirmed that kevent is ready + (k->callbacks.callback(k) returns true) then kevent will be copied + to userspace, otherwise it will be requeued back to storage. + Second (checking) call is performed with this bit cleared, so callback + can detect when it was called from kevent_storage_ready() - bit is set, + or kevent_dequeue_ready() - bit is cleared. If kevent will be requeued, + bit will be set again. + + KEVENT_REQ_ALWAYS_QUEUE + If this flag is set kevent will be queued into ready queue if it is + ready at enqueue time, otherwise it will be copied back to userspace + and will not be queued into the storage. + +__u32 ret_flags + Per-event return flags + + KEVENT_RET_BROKEN + Kevent is broken + + KEVENT_RET_DONE + Kevent processing was finished successfully + + KEVENT_RET_COPY_FAILED + Kevent was not copied into ring buffer due to some error conditions. + +__u32 ret_data + Event return data. Event originator fills it with anything it likes + (for example timer notifications put number of milliseconds when timer + has fired +union { __u32 user[2]; void *ptr; } + User's data. It is not used, just copied to/from user. The whole structure + is aligned to 8 bytes already, so the last union is aligned properly. + +------------------------------------------------------------------------------- + +Kevent waiting syscall flags. + +KEVENT_FLAGS_ABSTIME - provided timespec parameter contains absolute time, + for example Aug 27, 2194, or time(NULL) + 10. + +------------------------------------------------------------------------------- + +Usage + +For KEVENT_CTL_ADD, all fields relevant to the event type must be filled +(id, type, event, req_flags). +After kevent_ctl(..., KEVENT_CTL_ADD, ...) returns each struct's ret_flags +should be checked to see if the event is already broken or done. + +For KEVENT_CTL_MODIFY, the id, req_flags, and user and event fields must be +set and an existing kevent request must have matching id and user fields. If +match is found, req_flags and event are replaced with the newly supplied +values and requeueing is started, so modified kevent can be checked and +probably marked as ready immediately. If a match can't be found, the +passed in ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is +always set. + +For KEVENT_CTL_REMOVE, the id and user fields must be set and an existing +kevent request must have matching id and user fields. If a match is found, +the kevent request is removed. If a match can't be found, the passed in +ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is always set. + +For kevent_get_events, the entire structure is returned. + +------------------------------------------------------------------------------- + +Usage cases + +kevent_timer +struct ukevent should contain following fields: + type - KEVENT_TIMER + event - KEVENT_TIMER_FIRED + req_flags - KEVENT_REQ_ONESHOT if you want to fire that timer only once + id.raw[0] - number of seconds after commit when this timer shout expire + id.raw[0] - additional to number of seconds number of nanoseconds
PATCH 2/8 kevent: Core files.
Core files.
This patch includes core kevent files:
* userspace controlling
* kernelspace interfaces
* initialization
* notification state machines
Some bits of documentation can be found on project's homepage (and links from there):
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
arch/i386/kernel/syscall_table.S +5 -0
@@ -318,3 +318,8 @@ ENTRY(sys_call_table) .long sys_vmsplice .long sys_move_pages .long sys_getcpu + .long sys_kevent_get_events + .long sys_kevent_ctl /* 320 */ + .long sys_kevent_wait + .long sys_kevent_commit + .long sys_kevent_init
arch/x86_64/ia32/ia32entry.S +6 -1
@@ -714,8 +714,13 @@ ia32_sys_call_table: .quad compat_sys_get_robust_list .quad sys_splice .quad sys_sync_file_range - .quad sys_tee + .quad sys_tee /* 315 */ .quad compat_sys_vmsplice .quad compat_sys_move_pages .quad sys_getcpu + .quad sys_kevent_get_events + .quad sys_kevent_ctl /* 320 */ + .quad sys_kevent_wait + .quad sys_kevent_commit + .quad sys_kevent_init ia32_syscall_end:
include/asm-i386/unistd.h +6 -1
@@ -324,10 +324,15 @@#define __NR_vmsplice 316#define __NR_move_pages 317#define __NR_getcpu 318 +#define __NR_kevent_get_events 319 +#define __NR_kevent_ctl 320 +#define __NR_kevent_wait 321 +#define __NR_kevent_commit 322 +#define __NR_kevent_init 323#ifdef __KERNEL__ -#define NR_syscalls 319 +#define NR_syscalls 324#include <linux/err.h> /*
include/asm-x86_64/unistd.h +11 -1
@@ -619,10 +619,20 @@ __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_kevent_get_events 280 +__SYSCALL(__NR_kevent_get_events, sys_kevent_get_events) +#define __NR_kevent_ctl 281 +__SYSCALL(__NR_kevent_ctl, sys_kevent_ctl) +#define __NR_kevent_wait 282 +__SYSCALL(__NR_kevent_wait, sys_kevent_wait) +#define __NR_kevent_commit 283 +__SYSCALL(__NR_kevent_commit, sys_kevent_commit) +#define __NR_kevent_init 284 +__SYSCALL(__NR_kevent_init, sys_kevent_init)#ifdef __KERNEL__ -#define __NR_syscall_max __NR_move_pages +#define __NR_syscall_max __NR_kevent_init#include <linux/err.h> #ifndef __NO_STUBS
include/linux/kevent.h new file +244 -0
244 lines not on this page · raw message
include/linux/kevent_storage.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef __KEVENT_STORAGE_H +#define __KEVENT_STORAGE_H + +struct kevent_storage +{ +void *origin;/* Originator's pointer, e.g. struct sock or struct file. Can be NULL. */ +struct list_head list;/* List of queued kevents. */ +spinlock_t lock;/* Protects users queue. */ +}; + +#endif /* __KEVENT_STORAGE_H */
include/linux/syscalls.h +9 -0
@@ -54,6 +54,8 @@ struct compat_stat;struct compat_timeval ;struct robust_list_head ;struct getcpu_cache ; +struct ukevent ; +struct kevent_ring ;#include <linux/types.h> #include <linux/aio_abi.h>
@@ -599,4 +601,11 @@ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len);asmlinkage long sys_getcpu (unsigned __user *cpu,unsigned __user *node,struct getcpu_cache __user *cache); +asmlinkage long sys_kevent_get_events (int ctl_fd,unsigned int min,unsigned int max, +struct timespec timeout,struct ukevent __user *buf,unsigned flags); +asmlinkage long sys_kevent_ctl (int ctl_fd,unsigned int cmd,unsigned int num,struct ukevent __user *buf); +asmlinkage long sys_kevent_wait (int ctl_fd,unsigned int num,unsigned int old_uidx, +struct timespec timeout,unsigned int flags); +asmlinkage long sys_kevent_commit (int ctl_fd,unsigned int new_uidx,unsigned int over); +asmlinkage long sys_kevent_init (int ctl_fd,struct kevent_ring __user *ring,unsigned int num,unsigned int flags);#endif
include/linux/ukevent.h new file +186 -0
186 lines not on this page · raw message
init/Kconfig +2 -0
@@ -201,6 +201,8 @@ config AUDITSYSCALL such as SELinux. To use audit's filesystem watch feature, please ensure that INOTIFY is configured. +source "kernel/kevent/Kconfig" + config IKCONFIG bool "Kernel .config support" ---help---
kernel/Makefile +1 -0
@@ -47,6 +47,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o +obj-$(CONFIG_KEVENT) += kevent/ obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o obj-$(CONFIG_TASKSTATS) += taskstats.o
kernel/kevent/Kconfig new file +66 -0
66 lines not on this page · raw message
kernel/kevent/Makefile new file +6 -0
@@ -0,0 +1,6 @@ +obj-y := kevent.o kevent_user.o +obj-$(CONFIG_KEVENT_TIMER) += kevent_timer.o +obj-$(CONFIG_KEVENT_POLL) += kevent_poll.o +obj-$(CONFIG_KEVENT_SOCKET) += kevent_socket.o +obj-$(CONFIG_KEVENT_PIPE) += kevent_pipe.o +obj-$(CONFIG_KEVENT_SIGNAL) += kevent_signal.o
kernel/kevent/kevent.c new file +265 -0
265 lines not on this page · raw message
kernel/kevent/kevent_user.c new file +1363 -0
1,363 lines not on this page · raw message
kernel/sys_ni.c +6 -0
@@ -122,6 +122,12 @@ cond_syscall(ppc_rtas);cond_syscall (sys_spu_run);cond_syscall (sys_spu_create); +cond_syscall (sys_kevent_get_events); +cond_syscall (sys_kevent_ctl); +cond_syscall (sys_kevent_wait); +cond_syscall (sys_kevent_commit); +cond_syscall (sys_kevent_init); +/* mmu depending weak syscall entries */ cond_syscall (sys_mprotect);cond_syscall (sys_msync);
PATCH 3/8 kevent: poll/select() notifications.
poll/select() notifications.
This patch includes generic poll/select notifications. kevent_poll works simialr to epoll and has the same issues (callback is invoked not from internal state machine of the caller, but through process awake, a lot of allocations and so on).
fs/file_table.c +3 -0
@@ -20,6 +20,7 @@#include <linux/cdev.h> #include <linux/fsnotify.h> #include <linux/sysctl.h> +#include <linux/kevent.h> #include <linux/percpu_counter.h> #include <asm/atomic.h>
@@ -119,6 +120,7 @@ struct file *get_empty_filp(void) f->f_uid = tsk->fsuid; f->f_gid = tsk->fsgid;eventpoll_init_file (f); +kevent_init_file (f);/* f->f_version: 0 */ return f;
@@ -164,6 +166,7 @@ void fastcall __fput(struct file *file)* in the file cleanup chain. */ eventpoll_release (file); +kevent_cleanup_file (file);locks_remove_flock (file);if (file->f_op && file->f_op->release)
include/linux/fs.h +8 -0
@@ -276,6 +276,7 @@ extern int dir_notify_enable;#include <linux/init.h> #include <linux/sched.h> #include <linux/mutex.h> +#include <linux/kevent_storage.h> #include <asm/atomic.h> #include <asm/semaphore.h>
@@ -586,6 +587,10 @@ struct inode {struct mutex inotify_mutex;/* protects the watches list */ #endif +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +struct kevent_storage st; +#endif +unsigned long i_state;unsigned long dirtied_when;/* jiffies of first dirtying */
@@ -739,6 +744,9 @@ struct file {struct list_head f_ep_links;spinlock_t f_ep_lock;#endif /* #ifdef CONFIG_EPOLL */ +#ifdef CONFIG_KEVENT_POLL +struct kevent_storage st; +#endif struct address_space *f_mapping; };extern spinlock_t files_lock;
kernel/kevent/kevent_poll.c new file +234 -0
234 lines not on this page · raw message
PATCH 4/8 kevent: Socket notifications.
Socket notifications.
This patch includes socket send/recv/accept notifications. Using trivial web server based on kevent and this features instead of epoll it's performance increased more than noticebly. More details about various benchmarks and server itself (evserver_kevent.c) can be found on project's homepage.
fs/inode.c +7 -0
@@ -21,6 +21,7 @@#include <linux/cdev.h> #include <linux/bootmem.h> #include <linux/inotify.h> +#include <linux/kevent.h> #include <linux/mount.h> /*
@@ -164,12 +165,18 @@ static struct inode *alloc_inode(struct super_block *sb) } inode->i_private =0 ; inode->i_mapping = mapping; +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_init (inode, &inode->st); +#endif }return inode; }void destroy_inode (struct inode *inode) { +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_fini (&inode->st); +#endif BUG_ON (inode_has_buffers (inode));security_inode_free (inode);if (inode->i_sb->s_op->destroy_inode)
include/net/sock.h +17 -15
@@ -48,6 +48,7 @@#include <linux/netdevice.h> #include <linux/skbuff.h> /* struct sk_buff */ #include <linux/security.h> +#include <linux/kevent.h> #include <linux/filter.h>
@@ -450,6 +451,21 @@ static inline int sk_stream_memory_free(struct sock *sk)extern void sk_stream_rfree (struct sk_buff *skb); +struct socket_alloc { +struct socket socket; +struct inode vfs_inode; +}; + +static inline struct socket *SOCKET_I (struct inode *inode) +{ + return &container_of(inode, struct socket_alloc, vfs_inode)->socket; +} + +static inline struct inode *SOCK_INODE (struct socket *socket) +{ + return &container_of(socket, struct socket_alloc, socket)->vfs_inode; +} +static inline void sk_stream_set_owner_r (struct sk_buff *skb,struct sock *sk) { skb->sk = sk;
@@ -477,6 +493,7 @@ static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb) sk->sk_backlog.tail = skb; } skb->next =NULL ; +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); }#define sk_wait_event (__sk, __timeo, __condition) \
@@ -679,21 +696,6 @@ static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si)return si->kiocb; } -struct socket_alloc { -struct socket socket; -struct inode vfs_inode; -}; - -static inline struct socket *SOCKET_I (struct inode *inode) -{ - return &container_of(inode, struct socket_alloc, vfs_inode)->socket; -} - -static inline struct inode *SOCK_INODE (struct socket *socket) -{ - return &container_of(socket, struct socket_alloc, socket)->vfs_inode; -} -extern void __sk_stream_mem_reclaim (struct sock *sk);extern int sk_stream_mem_schedule (struct sock *sk,int size,int kind);
include/net/tcp.h +1 -0
@@ -857,6 +857,7 @@ static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb) tp->ucopy.memory =0 ; }else if (skb_queue_len (&tp->ucopy.prequeue) ==1 ) {wake_up_interruptible (sk->sk_sleep); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND );if (!inet_csk_ack_scheduled (sk)) inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, (3 * TCP_RTO_MIN) / 4,
kernel/kevent/kevent_socket.c new file +144 -0
144 lines not on this page · raw message
net/core/sock.c +9 -1
@@ -1402,6 +1402,7 @@ static void sock_def_wakeup(struct sock *sk)if (sk->sk_sleep &&waitqueue_active (sk->sk_sleep))wake_up_interruptible_all (sk->sk_sleep);read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_error_report (struct sock *sk)
@@ -1411,6 +1412,7 @@ static void sock_def_error_report(struct sock *sk)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,0 ,POLL_ERR );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_readable (struct sock *sk,int len)
@@ -1420,6 +1422,7 @@ static void sock_def_readable(struct sock *sk, int len)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,1 ,POLL_IN );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_write_space (struct sock *sk)
@@ -1439,6 +1442,7 @@ static void sock_def_write_space(struct sock *sk) }read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); }static void sock_def_destruct (struct sock *sk)
@@ -1489,6 +1493,8 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_state =TCP_CLOSE ; sk->sk_socket = sock; +kevent_sk_reinit (sk); +sock_set_flag (sk,SOCK_ZAPPED );if (sock)
@@ -1555,8 +1561,10 @@ void fastcall release_sock(struct sock *sk)if (sk->sk_backlog.tail)__release_sock (sk); sk->sk_lock.owner =NULL ; -if (waitqueue_active (&sk->sk_lock.wq)) +if (waitqueue_active (&sk->sk_lock.wq)) {wake_up (&sk->sk_lock.wq); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); + }spin_unlock_bh (&sk->sk_lock.slock); }EXPORT_SYMBOL (release_sock);
net/core/stream.c +1 -0
@@ -36,6 +36,7 @@ void sk_stream_write_space(struct sock *sk)wake_up_interruptible (sk->sk_sleep);if (sock->fasync_list && !(sk->sk_shutdown &SEND_SHUTDOWN ))sock_wake_async (sock,2 ,POLL_OUT ); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); } }
net/ipv4/tcp_input.c +1 -0
@@ -3119,6 +3119,7 @@ static void tcp_ofo_queue(struct sock *sk)__skb_unlink (skb, &tp->out_of_order_queue);__skb_queue_tail (&sk->sk_receive_queue, skb); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); tp->rcv_nxt =TCP_SKB_CB (skb)->end_seq;if (skb->h.th->fin)tcp_fin (skb, sk, skb->h.th);
net/ipv4/tcp_ipv4.c +2 -0
@@ -61,6 +61,7 @@#include <linux/jhash.h> #include <linux/init.h> #include <linux/times.h> +#include <linux/kevent.h> #include <net/icmp.h> #include <net/inet_hashtables.h>
@@ -870,6 +871,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)reqsk_free (req); }else {inet_csk_reqsk_queue_hash_add (sk, req,TCP_TIMEOUT_INIT ); +kevent_socket_notify (sk,KEVENT_SOCKET_ACCEPT ); }return 0 ;
net/socket.c +3 -0
@@ -85,6 +85,7 @@#include <linux/kmod.h> #include <linux/audit.h> #include <linux/wireless.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -490,6 +491,8 @@ static struct socket *sock_alloc(void) inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; +kevent_socket_reinit (sock); +get_cpu_var (sockets_in_use)++;put_cpu_var (sockets_in_use);return sock;
net/unix/af_unix.c +21 -1
@@ -1562,8 +1562,10 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,struct scm_cookie tmp_scm;struct sock *sk = sock->sk;struct unix_sock *u =unix_sk (sk); +struct sock *other;int noblock = flags &MSG_DONTWAIT ;struct sk_buff *skb; +int err; err = -EOPNOTSUPP ;
@@ -1579,6 +1581,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, goto out_unlock;wake_up_interruptible (&u->peer_wait); + other =unix_peer_get (sk); +if (other) { +kevent_socket_notify (other,KEVENT_SOCKET_SEND ); +sock_put (other); + }else +kevent_socket_notify (sk,KEVENT_SOCKET_RECV );if (msg->msg_name)unix_copy_addr (msg, skb->sk);
@@ -1673,7 +1681,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, {struct sock_iocb *siocb =kiocb_to_siocb (iocb);struct scm_cookie tmp_scm; -struct sock *sk = sock->sk; +struct sock *sk = sock->sk, *other;struct unix_sock *u =unix_sk (sk);struct sockaddr_un *sunaddr=msg->msg_name;int copied =0 ;
@@ -1802,6 +1810,14 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, } }while (size); + other =unix_peer_get (sk); +if (other) { +kevent_socket_notify (other,KEVENT_SOCKET_SEND ); +sock_put (other); + } +if (sk->sk_shutdown &RCV_SHUTDOWN || !other) +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); +mutex_unlock (&u->readlock);scm_recv (sock, msg, siocb->scm, flags); out:
@@ -1823,6 +1839,10 @@ static int unix_shutdown(struct socket *sock, int mode)sock_hold (other);unix_state_wunlock (sk); sk->sk_state_change (sk); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); +if (other) +kevent_socket_notify (other,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV );if (other && (sk->sk_type ==SOCK_STREAM || sk->sk_type ==SOCK_SEQPACKET )) {
PATCH 5/8 kevent: Timer notifications.
Timer notifications.
Timer notifications can be used for fine grained per-process time management, since interval timers are very inconvenient to use, and they are limited.
This subsystem uses high-resolution timers.
id.raw[0] is used as number of seconds
id.raw[1] is used as number of nanoseconds
kernel/kevent/kevent_timer.c new file +114 -0
@@ -0,0 +1,114 @@ +/* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/jiffies.h> +#include <linux/kevent.h> + +struct kevent_timer +{ +struct hrtimer ktimer; +struct kevent_storage ktimer_storage; +struct kevent *ktimer_event; +}; + +static int kevent_timer_func (struct hrtimer *timer) +{ + struct kevent_timer *t = container_of(timer, struct kevent_timer, ktimer); +struct kevent *k = t->ktimer_event; + +kevent_storage_ready (&t->ktimer_storage,NULL ,KEVENT_MASK_ALL ); +hrtimer_forward (timer, timer->base->softirq_time, +ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ])); +return HRTIMER_RESTART ; +} + +static struct lock_class_key kevent_timer_key; + +static int kevent_timer_enqueue (struct kevent *k) +{ +int err; +struct kevent_timer *t; + + t =kmalloc (sizeof (struct kevent_timer ),GFP_KERNEL ); +if (!t) +return -ENOMEM ; + +hrtimer_init (&t->ktimer,CLOCK_MONOTONIC ,HRTIMER_REL ); + t->ktimer.expires =ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ]); + t->ktimer.function = kevent_timer_func; + t->ktimer_event = k; + + err =kevent_storage_init (&t->ktimer, &t->ktimer_storage); +if (err) + goto err_out_free; +lockdep_set_class (&t->ktimer_storage.lock, &kevent_timer_key); + + err =kevent_storage_enqueue (&t->ktimer_storage, k); +if (err) + goto err_out_st_fini; + +hrtimer_start (&t->ktimer, t->ktimer.expires,HRTIMER_REL ); + +return 0 ; + +err_out_st_fini: +kevent_storage_fini (&t->ktimer_storage); +err_out_free: +kfree (t); + +return err; +} + +static int kevent_timer_dequeue (struct kevent *k) +{ +struct kevent_storage *st = k->st; + struct kevent_timer *t = container_of(st, struct kevent_timer, ktimer_storage); + +hrtimer_cancel (&t->ktimer); +kevent_storage_dequeue (st, k); +kfree (t); + +return 0 ; +} + +static int kevent_timer_callback (struct kevent *k) +{ + k->event.ret_data[0 ] =jiffies_to_msecs (jiffies); +return 1 ; +} + +static int __init kevent_init_timer (void ) +{ +struct kevent_callbacks tc = { + .callback = &kevent_timer_callback, + .enqueue = &kevent_timer_enqueue, + .dequeue = &kevent_timer_dequeue, + .flags =0 , + }; + +return kevent_add_callbacks (&tc,KEVENT_TIMER ); +} +module_init (kevent_init_timer); +
PATCH 6/8 kevent: Pipe notifications.
Pipe notifications.
fs/pipe.c +6 -0
@@ -16,6 +16,7 @@#include <linux/uio.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/ioctls.h>
@@ -312,6 +313,7 @@ redo:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -321,6 +323,7 @@ redo:/* Signal writers asynchronously that there is more room. */ if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -490,6 +493,7 @@ redo2:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); do_wakeup =0 ;
@@ -501,6 +505,7 @@ redo2: out:mutex_unlock (&inode->i_mutex);if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); }
@@ -605,6 +610,7 @@ pipe_release(struct inode *inode, int decr, int decw)free_pipe_info (inode); }else {wake_up_interruptible (&pipe->wait); +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV );kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN );kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
kernel/kevent/kevent_pipe.c new file +123 -0
123 lines not on this page · raw message
PATCH 7/8 kevent: Signal notifications.
Signal notifications.
This type of notifications allows to deliver signals through kevent queue. One can find example application signal.c on project homepage.
If KEVENT_SIGNAL_NOMASK bit is set in raw_u64 id then signal will be delivered only through queue, otherwise both delivery types are used - old through update of mask of pending signals and through queue.
If signal is delivered only through kevent queue mask of pending signals is not updated at all, which is equal to putting signal into blocked mask, but with delivery of that signal through kevent queue.
include/linux/sched.h +5 -0
@@ -80,6 +80,7 @@ struct sched_param {#include <linux/resource.h> #include <linux/timer.h> #include <linux/hrtimer.h> +#include <linux/kevent_storage.h> #include <asm/processor.h>
@@ -1013,6 +1014,10 @@ struct task_struct {#ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info *delays;#endif +#ifdef CONFIG_KEVENT_SIGNAL +struct kevent_storage st; +u32 kevent_signals; +#endif };static inline pid_t process_group (struct task_struct *tsk)
kernel/fork.c +8 -0
@@ -46,6 +46,7 @@#include <linux/delayacct.h> #include <linux/taskstats_kern.h> #include <linux/random.h> +#include <linux/kevent.h> #include <asm/pgtable.h> #include <asm/pgalloc.h>
@@ -115,6 +116,9 @@ void __put_task_struct(struct task_struct *tsk)WARN_ON (atomic_read (&tsk->usage));WARN_ON (tsk == current); +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_fini (&tsk->st); +#endif security_task_free (tsk);free_uid (tsk->user);put_group_info (tsk->group_info);
@@ -1121,6 +1125,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,if (retval) goto bad_fork_cleanup_namespace; +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_init (p, &p->st); +#endif + p->set_child_tid = (clone_flags &CLONE_CHILD_SETTID ) ? child_tidptr :NULL ;/* * Clear TID on mm_release()?
kernel/kevent/kevent_signal.c new file +94 -0
94 lines not on this page · raw message
kernel/signal.c +26 -0
@@ -23,6 +23,7 @@#include <linux/ptrace.h> #include <linux/signal.h> #include <linux/capability.h> +#include <linux/kevent.h> #include <asm/param.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -703,6 +704,9 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, {struct sigqueue * q =NULL ;int ret =0 ; + +if (kevent_signal_notify (t, sig)) +return 1 ;/* * fast-pathed signals for kernel-internal things like SIGSTOP
@@ -782,6 +786,17 @@ 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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif out:return ret; }
@@ -971,6 +986,17 @@ __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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif if (unlikely (ret))return ret;
PATCH 8/8 kevent: Kevent posix timer notifications.
Kevent posix timer notifications.
Simple extensions to POSIX timers which allows
to deliver notification of the timer expiration
through kevent queue.
Example application posix_timer.c can be found
in archive on project homepage.
include/asm-generic/siginfo.h +3 -0
@@ -235,6 +235,7 @@ typedef struct siginfo {#define SIGEV_NONE 1/* other notification: meaningless */ #define SIGEV_THREAD 2/* deliver via thread creation */ #define SIGEV_THREAD_ID 4/* deliver to thread */ +#define SIGEV_KEVENT 8/* deliver through kevent queue */ /* * This works because the alignment is ok on all current architectures
@@ -260,6 +261,8 @@ typedef struct sigevent {void (*_function)(sigval_t );void *_attribute;/* really pthread_attr_t */ } _sigev_thread; + +int kevent_fd; } _sigev_un; } sigevent_t;
include/linux/posix-timers.h +4 -0
@@ -4,6 +4,7 @@#include <linux/spinlock.h> #include <linux/list.h> #include <linux/sched.h> +#include <linux/kevent_storage.h> union cpu_time_count {cputime_t cpu;
@@ -49,6 +50,9 @@ struct k_itimer {sigval_t it_sigev_value;/* value word of sigevent struct */ struct task_struct *it_process;/* process to send signal to */ struct sigqueue *sigq;/* signal queue entry. */ +#ifdef CONFIG_KEVENT_TIMER +struct kevent_storage st; +#endif union { struct { struct hrtimer timer;
kernel/posix-timers.c +171 -48
264 lines not on this page · raw message
Re: [take29 0/8] kevent: Generic event handling mechanism.
In reply to Evgeniy PolyakovQuoted 38 lines · Evgeniy Polyakov
Generic event handling mechanism.
Kevent is a generic subsytem which allows to handle event notifications. It supports both level and edge triggered events. It is similar to poll/epoll in some cases, but it is more scalable, it is faster and allows to work with essentially eny kind of events.
Events are provided into kernel through control syscall and can be read back through ring buffer or using usual syscalls.
Kevent update (i.e. readiness switching) happens directly from internals of the appropriate state machine of the underlying subsytem (like network, filesystem, timer or any other).Homepage:
http://tservice.net.ru/~s0mbre/old/?section=projects&item=keventDocumentation page:
http://linux-net.osdl.org/index.php/KeventConsider for inclusion.
New benchmark, which can be a hoax though, can be found at
http://tservice.net.ru/~s0mbre/blog/2006/11/30#2006_11_30
where kevent on amd64 with 1gb of ram can handle more than 7200 events per second with 8000 requests concurrency with 'ab' benchmark and lighttpd. Although I tought it should not be published due to possible errors, I decided to send it for review.With this release I start 3 days resending timeout - i.e. each third day I will send either new version (if something new was requested and agreed to be implemented) or resending with back counter started from three. When back counter hits zero after three resending I consider there is no interest in subsystem and I will stop further sending.
First one will be sent about Jan 10.Thanks for understanding and your time.
Quoted 12 lines
Changes from 'take28' patchset:
* optimizedaf_unixto use socket notifications
* changedALWAYS_QUEUEbehaviour with poll/select notifications - previously kevent was not queued into poll wait queue whenALWAYS_QUEUEflag is set
* addedKEVENT_POLL_POLLRDHUPdefinition intoukevent.hheader
* libevent-1.2 patch (Jamal, your request is completed, so I'm waiting two weeks before starting final countdown :)
All regression tests passed successfully excepttest_evbuffer(), which crashes on my amd64 linux 2.6 test machine for all types of notifications, probably it is fixed in libevent-1.2a version, I did not check. Patch and README can be found at project homepage.
P.S. all kernel kevent options must be turned on (namely kevent_poll, kevent_socket and kevent_pipe).
I did not hack 'configure' to check for supported notification types.
Signature · 1 line
Evgeniy Polyakov
Re: [take29 0/8] kevent: Generic event handling mechanism.
In reply to Evgeniy PolyakovQuoted 1 line · Evgeniy Polyakov
Generic event handling mechanism.
it would be /very/ helpful to state against which kernel tree the patch-queue is. It does not apply to 2.6.20-rc1 nor to -rc2 nor to 2.6.19. At which point i gave up ...
Ingo
Re: [take29 0/8] kevent: Generic event handling mechanism.
Quoted 8 lines · Ingo Molnar
Quoted 1 line · Evgeniy Polyakov
Generic event handling mechanism.
it would be /very/ helpful to state against which kernel tree the patch-queue is. It does not apply to 2.6.20-rc1 nor to -rc2 nor to 2.6.19. At which point i gave up ...
It was against 2.6.18 (d4397acde6fd047f13c744e5471a9bfe287f78a3) git. Next patchset with possibility to inject already read event and userspace reserved notifications will be against the latest tree (I will push it today before final New Year celebration started).
Quoted 1 line
Ingo
Signature · 1 line
Evgeniy Polyakov
Re: [take29 0/8] kevent: Generic event handling mechanism.
In reply to Evgeniy PolyakovQuoted 1 line · Evgeniy Polyakov
Generic event handling mechanism.
i see it covers alot of event sources, but i cannot see block IO notifications. Am i missing something?
Ingo
Re: [take29 0/8] kevent: Generic event handling mechanism.
Quoted 7 lines · Ingo Molnar
Quoted 1 line · Evgeniy Polyakov
Generic event handling mechanism.
i see it covers alot of event sources, but i cannot see block IO notifications. Am i missing something?
Depending on what it is :)
If you mean kevent based AIO, then it was dropped to reduce size of the patchset, and in favour of new AIO design.
Other kinds of read/write notifications can be handled by poll/select notifications.
Quoted 1 line
Ingo
Signature · 1 line
Evgeniy Polyakov
Re: [take29 0/8] kevent: Generic event handling mechanism.
Quoted 4 lines · Evgeniy Polyakov
Quoted 3 lines · Ingo Molnar
* Evgeniy Polyakov <[email protected]> wrote:
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
Generic event handling mechanism.
i see it covers alot of event sources, but i cannot see block IO notifications. Am i missing something?
Depending on what it is :) If you mean kevent based AIO, then it was dropped to reduce size of the patchset, and in favour of new AIO design.
yes, kevent based AIO. Could you please re-add it, preferably ontop of Suparna's AIO patchset? I dont see how a "generic event handling mechanism" can exclude block IO because we really need to see how it plugs into (and plays along with) block AIO and how it performs relative to block AIO to be able to judge whether this API and infrastructure should be included in the kernel in its current form.
Quoted 2 lines
Other kinds of read/write notifications can be handled by poll/select notifications.
but poll/select notifications are just a second-degree way of doing an IO state machine, and they are mostly there in kevents for completeness and compatibility.
To be able to judge a "generic" event mechanism it really must support block IO as well, natively. Without that we'd have the following obscene API situation:
- poll()/select(): supports everything but is slow and inaccurate
- epoll(): more modern API ontop of poll notifications
- async IO: supports block IO
- kevent supports almost everything /except/ block IO
so what we need is for kevents to support /all/ the important high-performance event types natively:
- networking
- block IO
- VFS namespace
- timers
(rarer things like mouse/input events can stay with poll notifications)
and it is /especially/ important to include block IO events in kevents to be able to judge its performance and scalability relative to the async IO API and infrastructure.
Ingo
Re: [take29 0/8] kevent: Generic event handling mechanism.
Quoted 9 lines · Ingo Molnar
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
Generic event handling mechanism.
i see it covers alot of event sources, but i cannot see block IO notifications. Am i missing something?
Depending on what it is :) If you mean kevent based AIO, then it was dropped to reduce size of the patchset, and in favour of new AIO design.
Quoted 6 lines
yes, kevent based AIO. Could you please re-add it, preferably ontop of Suparna's AIO patchset? I dont see how a "generic event handling mechanism" can exclude block IO because we really need to see how it plugs into (and plays along with) block AIO and how it performs relative to block AIO to be able to judge whether this API and infrastructure should be included in the kernel in its current form.
I like new design much more than my previous kevent based approach and existing repeated call approach. I plan to start working on it jst after New Year vacations are over (in about a week or two, it is the longest vacations of the year in Russia, which are spent in a way which does not allow to hack or perform any other usefull work).
Kevent AIO was completely different thing than Suparna's AIO, and although it hooked into block/fs subsystem on a bit different layer (I exported ->get_block() callback), it was possible to fully separate AIO from main code.
Quoted 6 lines
Quoted 2 lines
Other kinds of read/write notifications can be handled by poll/select notifications.
but poll/select notifications are just a second-degree way of doing an IO state machine, and they are mostly there in kevents for completeness and compatibility.
Yes, indeed.
Quoted 7 lines
To be able to judge a "generic" event mechanism it really must support block IO as well, natively. Without that we'd have the following obscene API situation:
- poll()/select(): supports everything but is slow and inaccurate
-epoll(): more modern API ontop of poll notifications
- async IO: supports block IO
Network AIO should not be different from block IO - it is essentially the same mechanisms, which just have different lower layer from where callbacks are invoked.
Quoted 10 lines
- kevent supports almost everything /except/ block IO
so what we need is for kevents to support /all/ the important high-performance event types natively:
- networking
- block IO
- VFS namespace
- timers
Quoted 5 lines
(rarer things like mouse/input events can stay with poll notifications)
and it is /especially/ important to include block IO events in kevents to be able to judge its performance and scalability relative to the async IO API and infrastructure.
Yes, async IO is a significant part, and will be implemented, IMHO, new design I highlighted in linux-fsdevel@ in AIO related thread is the way to go (at least I will imlement it that way).
Quoted 1 line
Ingo
Signature · 1 line
Evgeniy Polyakov
Re: [take29 0/8] kevent: Generic event handling mechanism.
Quoted 10 lines · Evgeniy Polyakov
Quoted 6 lines
(rarer things like mouse/input events can stay with poll notifications)
and it is /especially/ important to include block IO events in kevents to be able to judge its performance and scalability relative to the async IO API and infrastructure.
Yes, async IO is a significant part, and will be implemented, IMHO, new design I highlighted in linux-fsdevel@ in AIO related thread is the way to go (at least I will imlement it that way).
yes. Note that a prototype exists already: take a look at Tux's "work atom" infrastructure of how you can build a relatively straightforward state-machine that can be programmed and can be driven even from IRQ contexts. Via that i implemented fully asynchronous IO for networking 5 years ago, and programmed it to handle HTTP and FTP protocol server logic, fully asynchronously. (For block IO it also does emulation of event handling via the 'cachemiss' kernel threads. State-machine driven filesystems are quite hard - but not impossible in the long run.)
It would be a natural thing to extend that fundamental concept to user-space as well. /That/ i'd call a generic, grounds-up event handling infrastructure. That would be a worthwile unification point for all existing IO APIs.
Ingo
cover kevent: Generic event handling mechanism.
In reply to a message not in the archiveGeneric event handling mechanism.
Kevent is a generic subsytem which allows to handle event notifications. It supports both level and edge triggered events. It is similar to poll/epoll in some cases, but it is more scalable, it is faster and allows to work with essentially eny kind of events.
Events are provided into kernel through control syscall and can be read back through ring buffer or using usual syscalls.
Kevent update (i.e. readiness switching) happens directly from internals of the appropriate state machine of the underlying subsytem (like network, filesystem, timer or any other).
Homepage:
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
Documentation page:
http://linux-net.osdl.org/index.php/Kevent
Consider for inclusion.
Changes from 'take29' patchset:
* new private userspace notifications - allows to queue any userspace private event and then mark it as ready using kevent_ctl(KEVENT_READY) command
* KEVENT_REQ_READY flag - if set kevent will be marked as ready at enqueue time
* port to 2.6.20-rc2 tree (54abb5fcdae74a811ed440ec6556cabc6b24f404 commit)
* use struct kmem_cache instead of kmem_cache_t
* added notificaion type into search key, this allows to have the same id for different types of notifications
Changes from 'take28' patchset:
* optimized af_unix to use socket notifications
* changed ALWAYS_QUEUE behaviour with poll/select notifications - previously kevent was not queued into poll wait queue when ALWAYS_QUEUE flag is set
* added KEVENT_POLL_POLLRDHUP definition into ukevent.h header
* libevent-1.2 patch (Jamal, your request is completed, so I'm waiting two weeks before starting final countdown :)
All regression tests passed successfully except test_evbuffer(), which is crashed on my amd64 linux 2.6 test machine for all types of notifications, probably it was fixed in libevent-1.2a version, I did not check. Patch and README can be found at project homepage.
Changes from 'take27' patchset:
* made kevent default yes in non embedded case.
* added falgs to callback structures - currently used to check if kevent can be requested from kernelspace only (posix timers) or userspace (all others)
Changes from 'take26' patchset:
* made kevent visible in config only in case of embedded setup.
* added comment about KEVENT_MAX number.
* spell fix.
Changes from 'take25' patchset:
* use timespec as timeout parameter.
* added high-resolution timer to handle absolute timeouts.
* added flags to waiting and initialization syscalls.
* kevent_commit() has new_uidx parameter.
* kevent_wait() has old_uidx parameter, which, if not equal to u->uidx, results in immediate wakeup (usefull for the case when entries
are added asynchronously from kernel (not supported for now)).
* added interface to mark any event as ready.
* event POSIX timers support.
* return -ENOSYS if there is no registered event type.
* provided file descriptor must be checked for fifo type (spotted by Eric Dumazet).
* signal notifications.
* documentation update.
* lighttpd patch updated (the latest benchmarks with lighttpd patch can be found in blog).
Changes from 'take24' patchset:
* new (old (new)) ring buffer implementation with kernel and user indexes.
* added initialization syscall instead of opening /dev/kevent
* kevent_commit() syscall to commit ring buffer entries
* changed KEVENT_REQ_WAKEUP_ONE flag to KEVENT_REQ_WAKEUP_ALL, kevent wakes only first thread always if that flag is not set
* KEVENT_REQ_ALWAYS_QUEUE flag. If set, kevent will be queued into ready queue instead of copying back to userspace when kevent is ready immediately when it is added.
* lighttpd patch (Hail! Although nothing really outstanding compared to epoll)
Changes from 'take23' patchset:
* kevent PIPE notifications
* KEVENT_REQ_LAST_CHECK flag, which allows to perform last check at dequeueing time
* fixed poll/select notifications (were broken due to tree manipulations)
* made Documentation/kevent.txt look nice in 80-col terminal
* fix for copy_to_user() failure report for the first kevent (Andrew Morton)
* minor function renames
Changes from 'take22' patchset:
* new ring buffer implementation in process' memory
* wakeup-one-thread flag
* edge-triggered behaviour
Changes from 'take21' patchset:
* minor cleanups (different return values, removed unneded variables, whitespaces and so on)
* fixed bug in kevent removal in case when kevent being removed
is the same as overflow_kevent (spotted by Eric Dumazet)
Changes from 'take20' patchset:
* new ring buffer implementation
* removed artificial limit on possible number of kevents
Changes from 'take19' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take18' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take17' patchset:
* Use RB tree instead of hash table.
At least for a web sever, frequency of addition/deletion of new kevent is comparable with number of search access, i.e. most of the time events are added, accesed only couple of times and then removed, so it justifies RB tree usage over AVL tree, since the latter does have much slower deletion time (max O(log(N)) compared to 3 ops),
although faster search time (1.44*O(log(N)) vs. 2*O(log(N))).
So for kevents I use RB tree for now and later, when my AVL tree implementation is ready, it will be possible to compare them.
* Changed readiness check for socket notifications.
With both above changes it is possible to achieve more than 3380 req/second compared to 2200, sometimes 2500 req/second for epoll() for trivial web-server and httperf client on the same hardware.
It is possible that above kevent limit is due to maximum allowed kevents in a time limit, which is 4096 events.
Changes from 'take16' patchset:
* misc cleanups (__read_mostly, const ...)
* created special macro which is used for mmap size (number of pages) calculation
* export kevent_socket_notify(), since it is used in network protocols which can be built as modules (IPv6 for example)
Changes from 'take15' patchset:
* converted kevent_timer to high-resolution timers, this forces timer API update at
http://linux-net.osdl.org/index.php/Kevent
* use struct ukevent* instead of void * in syscalls (documentation has been updated)
* added warning in kevent_add_ukevent() if ring has broken index (for testing)
Changes from 'take14' patchset:
* added kevent_wait()
This syscall waits until either timeout expires or at least one event becomes ready. It also commits that @num events from @start are processed by userspace and thus can be be removed or rearmed (depending on it's flags). It can be used for commit events read by userspace through mmap interface. Example userspace code (evtest.c) can be found on project's homepage.
* added socket notifications (send/recv/accept)
Changes from 'take13' patchset:
* do not get lock aroung user data check in __kevent_search()
* fail early if there were no registered callbacks for given type of kevent
* trailing whitespace cleanup
Changes from 'take12' patchset:
* remove non-chardev interface for initialization
* use pointer to kevent_mring instead of unsigned longs
* use aligned 64bit type in raw user data (can be used by high-res timer if needed)
* simplified enqueue/dequeue callbacks and kevent initialization
* use nanoseconds for timeout
* put number of milliseconds into timer's return data
* move some definitions into user-visible header
* removed filenames from comments
Changes from 'take11' patchset:
* include missing headers into patchset
* some trivial code cleanups (use goto instead of if/else games and so on)
* some whitespace cleanups
* check for ready_callback() callback before main loop which should save us some ticks
Changes from 'take10' patchset:
* removed non-existent prototypes
* added helper function for kevent_registered_callbacks
* fixed 80 lines comments issues
* added shared between userspace and kernelspace header instead of embedd them in one
* core restructuring to remove forward declarations
* s o m e w h i t e s p a c e c o d y n g s t y l e c l e a n u p
* use vm_insert_page() instead of remap_pfn_range()
Changes from 'take9' patchset:
* fixed ->nopage method
Changes from 'take8' patchset:
* fixed mmap release bug
* use module_init() instead of late_initcall()
* use better structures for timer notifications
Changes from 'take7' patchset:
* new mmap interface (not tested, waiting for other changes to be acked)
- use nopage() method to dynamically substitue pages
- allocate new page for events only when new added kevent requres it
- do not use ugly index dereferencing, use structure instead
- reduced amount of data in the ring (id and flags), maximum 12 pages on x86 per kevent fd
Changes from 'take6' patchset:
* a lot of comments!
* do not use list poisoning for detection of the fact, that entry is in the list
* return number of ready kevents even if copy*user() fails
* strict check for number of kevents in syscall
* use ARRAY_SIZE for array size calculation
* changed superblock magic number
* use SLAB_PANIC instead of direct panic() call
* changed -E* return values
* a lot of small cleanups and indent fixes
Changes from 'take5' patchset:
* removed compilation warnings about unused wariables when lockdep is not turned on
* do not use internal socket structures, use appropriate (exported) wrappers instead
* removed default 1 second timeout
* removed AIO stuff from patchset
Changes from 'take4' patchset:
* use miscdevice instead of chardevice
* comments fixes
Changes from 'take3' patchset:
* removed serializing mutex from kevent_user_wait()
* moved storage list processing to RCU
* removed lockdep screaming - all storage locks are initialized in the same function, so it was
learned
to differentiate between various cases
* remove kevent from storage if is marked as broken after callback
* fixed a typo in mmaped buffer implementation which would end up in wrong index calcualtion
Changes from 'take2' patchset:
* split kevent_finish_user() to locked and unlocked variants
* do not use KEVENT_STAT ifdefs, use inline functions instead
* use array of callbacks of each type instead of each kevent callback initialization
* changed name of ukevent guarding lock
* use only one kevent lock in kevent_user for all hash buckets instead of per-bucket locks
* do not use kevent_user_ctl structure instead provide needed arguments as syscall parameters
* various indent cleanups
* added optimisation, which is aimed to help when a lot of kevents are being copied from
userspace
* mapped buffer (initial) implementation (no userspace yet)
Changes from 'take1' patchset:
- rebased against 2.6.18-git tree
- removed ioctl controlling
- added new syscall kevent_get_events(int fd, unsigned int min_nr, unsigned int max_nr, unsigned int timeout, void __user *buf, unsigned flags)
- use old syscall kevent_ctl for creation/removing, modification and initial kevent initialization
- use mutuxes instead of semaphores
- added file descriptor check and return error if provided descriptor does not match kevent file operations
- various indent fixes
- removed aio_sendfile() declarations.
Thank you.
PATCH 1/9 kevent: Description.
Description.
Documentation/kevent.txt new file +244 -0
@@ -0,0 +1,244 @@ +Description. + +int kevent_init(struct kevent_ring *ring, unsigned int ring_size, + unsigned int flags); + +num - size of the ring buffer in events +ring - pointer to allocated ring buffer +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: kevent control file descriptor or negative error value. + + struct kevent_ring + { + unsigned int ring_kidx, ring_over; + struct ukevent event[0]; + } + +ring_kidx - index in the ring buffer where kernel will put new events + when kevent_wait() or kevent_get_events() is called +ring_over - number of overflows of ring_uidx happend from the start. + Overflow counter is used to prevent situation when two threads + are going to free the same events, but one of them was scheduled + away for too long, so ring indexes were wrapped, so when that + thread will be awakened, it will free not those events, which + it suppose to free. + +Example userspace code (ring_buffer.c) can be found on project's homepage. + +Each kevent syscall can be so called cancellation point in glibc, i.e. when +thread has been cancelled in kevent syscall, thread can be safely removed +and no events will be lost, since each syscall (kevent_wait() or +kevent_get_events()) will copy event into special ring buffer, accessible +from other threads or even processes (if shared memory is used). + +When kevent is removed (not dequeued when it is ready, but just removed), +even if it was ready, it is not copied into ring buffer, since if it is +removed, no one cares about it (otherwise user would wait until it becomes +ready and got it through usual way using kevent_get_events() or kevent_wait()) +and thus no need to copy it to the ring buffer. + +------------------------------------------------------------------------------- + + +int kevent_ctl(int fd, unsigned int cmd, unsigned int num, struct ukevent *arg); + +fd - is the file descriptor referring to the kevent queue to manipulate. +It is created by opening "/dev/kevent" char device, which is created with +dynamic minor number and major number assigned for misc devices. + +cmd - is the requested operation. It can be one of the following: + KEVENT_CTL_ADD - add event notification + KEVENT_CTL_REMOVE - remove event notification + KEVENT_CTL_MODIFY - modify existing notification + KEVENT_CTL_READY - mark existing events as ready, if number of events is zero, + it just wakes up parked in syscall thread + +num - number of struct ukevent in the array pointed to by arg +arg - array of struct ukevent + +Return value: + number of events processed or negative error value. + +When called, kevent_ctl will carry out the operation specified in the +cmd parameter. +------------------------------------------------------------------------------- + + int kevent_get_events(int ctl_fd, unsigned int min_nr, unsigned int max_nr, + struct timespec timeout, struct ukevent *buf, unsigned flags); + +ctl_fd - file descriptor referring to the kevent queue +min_nr - minimum number of completed events that kevent_get_events will block + waiting for +max_nr - number of struct ukevent in buf +timeout - time to wait before returning less than min_nr + events. If this is -1, then wait forever. +buf - pointer to an array of struct ukevent. +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied or negative error value. + +kevent_get_events will wait timeout milliseconds for at least min_nr completed +events, copying completed struct ukevents to buf and deleting any +KEVENT_REQ_ONESHOT event requests. In nonblocking mode it returns as many +events as possible, but not more than max_nr. In blocking mode it waits until +timeout or if at least min_nr events are ready. + +This function copies event into ring buffer if it was initialized, if ring buffer +is full, KEVENT_RET_COPY_FAILED flag is set in ret_flags field. +------------------------------------------------------------------------------- + + int kevent_wait(int ctl_fd, unsigned int num, unsigned int old_uidx, + struct timespec timeout, unsigned int flags); + +ctl_fd - file descriptor referring to the kevent queue +num - number of processed kevents +old_uidx - the last index user is aware of +timeout - time to wait until there is free space in kevent queue +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied into ring buffer or negative error value. + +This syscall waits until either timeout expires or at least one event becomes +ready. It also copies events into special ring buffer. If ring buffer is full, +it waits until there are ready events and then return. +If kevent is one-shot kevent it is removed in this syscall. +If kevent is edge-triggered (KEVENT_REQ_ET flag is set in 'req_flags') it is +requeued in this syscall for performance reasons. +------------------------------------------------------------------------------- + + int kevent_commit(int ctl_fd, unsigned int new_idx, unsigned int over); + +ctl_fd - file descriptor referring to the kevent queue +new_uidx - the last committed kevent +over - overflow count for given $new_idx value + +Return value: + number of committed kevents or negative error value. + +This function commits, i.e. marks as empty, slots in the ring buffer, so +they can be reused when userspace completes that entries processing. + +Overflow counter is used to prevent situation when two threads are going +to free the same events, but one of them was scheduled away for too long, +so ring indexes were wrapped, so when that thread will be awakened, it +will free not those events, which it suppose to free. + +It is possible that returned number of committed events will be smaller than +requested number - it is possible when several threads try to commit the +same events. +------------------------------------------------------------------------------- + +The bulk of the interface is entirely done through the ukevent struct. +It is used to add event requests, modify existing event requests, +specify which event requests to remove, and return completed events. + +struct ukevent contains the following members: + +struct kevent_id id + Id of this request, e.g. socket number, file descriptor and so on +__u32 type + Event type, e.g. KEVENT_SOCK, KEVENT_INODE, KEVENT_TIMER and so on +__u32 event + Event itself, e.g. SOCK_ACCEPT, INODE_CREATED, TIMER_FIRED +__u32 req_flags + Per-event request flags, + + KEVENT_REQ_ONESHOT + event will be removed when it is ready + + KEVENT_REQ_WAKEUP_ALL + Kevent wakes up only first thread interested in given event, + or all threads if this flag is set. + + KEVENT_REQ_ET + Edge Triggered behaviour. It is an optimisation which allows to move + ready and dequeued (i.e. copied to userspace) event to move into set + of interest for given storage (socket, inode and so on) again. It is + very usefull for cases when the same event should be used many times + (like reading from pipe). It is similar to epoll()'s EPOLLET flag. + + KEVENT_REQ_LAST_CHECK + if set allows to perform the last check on kevent (call appropriate + callback) when kevent is marked as ready and has been removed from + ready queue. If it will be confirmed that kevent is ready + (k->callbacks.callback(k) returns true) then kevent will be copied + to userspace, otherwise it will be requeued back to storage. + Second (checking) call is performed with this bit cleared, so callback + can detect when it was called from kevent_storage_ready() - bit is set, + or kevent_dequeue_ready() - bit is cleared. If kevent will be requeued, + bit will be set again. + + KEVENT_REQ_ALWAYS_QUEUE + If this flag is set kevent will be queued into ready queue if it is + ready at enqueue time, otherwise it will be copied back to userspace + and will not be queued into the storage. + + KEVENT_REQ_READY + If this flag is set, kevent will be marked as ready immediately at enqueue + time. + +__u32 ret_flags + Per-event return flags + + KEVENT_RET_BROKEN + Kevent is broken + + KEVENT_RET_DONE + Kevent processing was finished successfully + + KEVENT_RET_COPY_FAILED + Kevent was not copied into ring buffer due to some error conditions. + +__u32 ret_data + Event return data. Event originator fills it with anything it likes + (for example timer notifications put number of milliseconds when timer + has fired +union { __u32 user[2]; void *ptr; } + User's data. It is not used, just copied to/from user. The whole structure + is aligned to 8 bytes already, so the last union is aligned properly. + +------------------------------------------------------------------------------- + +Kevent waiting syscall flags. + +KEVENT_FLAGS_ABSTIME - provided timespec parameter contains absolute time, + for example Aug 27, 2194, or time(NULL) + 10. + +------------------------------------------------------------------------------- + +Usage + +For KEVENT_CTL_ADD, all fields relevant to the event type must be filled +(id, type, event, req_flags). +After kevent_ctl(..., KEVENT_CTL_ADD, ...) returns each struct's ret_flags +should be checked to see if the event is already broken or done. + +For KEVENT_CTL_MODIFY, the id, req_flags, and user and event fields must be +set and an existing kevent request must have matching id and user fields. If +match is found, req_flags and event are replaced with the newly supplied +values and requeueing is started, so modified kevent can be checked and +probably marked as ready immediately. If a match can't be found, the +passed in ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is +always set. + +For KEVENT_CTL_REMOVE, the id and user fields must be set and an existing +kevent request must have matching id and user fields. If a match is found, +the kevent request is removed. If a match can't be found, the passed in +ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is always set. + +For kevent_get_events, the entire structure is returned. + +------------------------------------------------------------------------------- + +Usage cases + +kevent_timer +struct ukevent should contain following fields: + type - KEVENT_TIMER + event - KEVENT_TIMER_FIRED + req_flags - KEVENT_REQ_ONESHOT if you want to fire that timer only once + id.raw[0] - number of seconds after commit when this timer shout expire + id.raw[0] - additional to number of seconds number of nanoseconds
PATCH 2/9 kevent: Core files.
Core files.
This patch includes core kevent files:
* userspace controlling
* kernelspace interfaces
* initialization
* notification state machines
Some bits of documentation can be found on project's homepage (and links from there):
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
arch/i386/kernel/syscall_table.S +5 -0
@@ -319,3 +319,8 @@ ENTRY(sys_call_table) .long sys_move_pages .long sys_getcpu .long sys_epoll_pwait + .long sys_kevent_get_events + .long sys_kevent_ctl /* 320 */ + .long sys_kevent_wait + .long sys_kevent_commit + .long sys_kevent_init
arch/x86_64/ia32/ia32entry.S +6 -1
@@ -714,8 +714,13 @@ ia32_sys_call_table: .quad compat_sys_get_robust_list .quad sys_splice .quad sys_sync_file_range - .quad sys_tee + .quad sys_tee /* 315 */ .quad compat_sys_vmsplice .quad compat_sys_move_pages .quad sys_getcpu + .quad sys_kevent_get_events + .quad sys_kevent_ctl /* 320 */ + .quad sys_kevent_wait + .quad sys_kevent_commit + .quad sys_kevent_init ia32_syscall_end:
include/asm-i386/unistd.h +6 -1
@@ -325,10 +325,15 @@#define __NR_move_pages 317#define __NR_getcpu 318#define __NR_epoll_pwait 319 +#define __NR_kevent_get_events 320 +#define __NR_kevent_ctl 321 +#define __NR_kevent_wait 322 +#define __NR_kevent_commit 323 +#define __NR_kevent_init 324#ifdef __KERNEL__ -#define NR_syscalls 320 +#define NR_syscalls 325#define __ARCH_WANT_IPC_PARSE_VERSION#define __ARCH_WANT_OLD_READDIR
include/asm-x86_64/unistd.h +12 -2
@@ -619,8 +619,18 @@ __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_syscall_max __NR_move_pages +#define __NR_kevent_get_events 280 +__SYSCALL(__NR_kevent_get_events, sys_kevent_get_events) +#define __NR_kevent_ctl 281 +__SYSCALL(__NR_kevent_ctl, sys_kevent_ctl) +#define __NR_kevent_wait 282 +__SYSCALL(__NR_kevent_wait, sys_kevent_wait) +#define __NR_kevent_commit 283 +__SYSCALL(__NR_kevent_commit, sys_kevent_commit) +#define __NR_kevent_init 284 +__SYSCALL(__NR_kevent_init, sys_kevent_init) + +#define __NR_syscall_max __NR_kevent_init#ifndef __NO_STUBS#define __ARCH_WANT_OLD_READDIR
include/linux/kevent.h new file +247 -0
247 lines not on this page · raw message
include/linux/kevent_storage.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef __KEVENT_STORAGE_H +#define __KEVENT_STORAGE_H + +struct kevent_storage +{ +void *origin;/* Originator's pointer, e.g. struct sock or struct file. Can be NULL. */ +struct list_head list;/* List of queued kevents. */ +spinlock_t lock;/* Protects users queue. */ +}; + +#endif /* __KEVENT_STORAGE_H */
include/linux/syscalls.h +10 -0
@@ -54,6 +54,8 @@ struct compat_stat;struct compat_timeval ;struct robust_list_head ;struct getcpu_cache ; +struct ukevent ; +struct kevent_ring ;#include <linux/types.h> #include <linux/aio_abi.h>
@@ -603,6 +605,14 @@ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len);asmlinkage long sys_getcpu (unsigned __user *cpu,unsigned __user *node,struct getcpu_cache __user *cache); +asmlinkage long sys_kevent_get_events (int ctl_fd,unsigned int min,unsigned int max, +struct timespec timeout,struct ukevent __user *buf,unsigned flags); +asmlinkage long sys_kevent_ctl (int ctl_fd,unsigned int cmd,unsigned int num,struct ukevent __user *buf); +asmlinkage long sys_kevent_wait (int ctl_fd,unsigned int num,unsigned int old_uidx, +struct timespec timeout,unsigned int flags); +asmlinkage long sys_kevent_commit (int ctl_fd,unsigned int new_uidx,unsigned int over); +asmlinkage long sys_kevent_init (int ctl_fd,struct kevent_ring __user *ring,unsigned int num,unsigned int flags); +int kernel_execve (const char *filename,char *const argv[],char *const envp[]);#endif
include/linux/ukevent.h new file +191 -0
191 lines not on this page · raw message
init/Kconfig +2 -0
@@ -219,6 +219,8 @@ config AUDITSYSCALL such as SELinux. To use audit's filesystem watch feature, please ensure that INOTIFY is configured. +source "kernel/kevent/Kconfig" + config IKCONFIG tristate "Kernel .config support" ---help---
kernel/Makefile +1 -0
@@ -46,6 +46,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o +obj-$(CONFIG_KEVENT) += kevent/ obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_UTS_NS) += utsname.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
kernel/kevent/Kconfig new file +74 -0
74 lines not on this page · raw message
kernel/kevent/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +obj-y := kevent.o kevent_user.o +obj-$(CONFIG_KEVENT_TIMER) += kevent_timer.o +obj-$(CONFIG_KEVENT_POLL) += kevent_poll.o +obj-$(CONFIG_KEVENT_SOCKET) += kevent_socket.o +obj-$(CONFIG_KEVENT_PIPE) += kevent_pipe.o +obj-$(CONFIG_KEVENT_SIGNAL) += kevent_signal.o +obj-$(CONFIG_KEVENT_UNOTIFY) += kevent_unotify.o
kernel/kevent/kevent.c new file +267 -0
267 lines not on this page · raw message
kernel/kevent/kevent_user.c new file +1371 -0
1,371 lines not on this page · raw message
kernel/sys_ni.c +6 -0
@@ -123,6 +123,12 @@ cond_syscall(ppc_rtas);cond_syscall (sys_spu_run);cond_syscall (sys_spu_create); +cond_syscall (sys_kevent_get_events); +cond_syscall (sys_kevent_ctl); +cond_syscall (sys_kevent_wait); +cond_syscall (sys_kevent_commit); +cond_syscall (sys_kevent_init); +/* mmu depending weak syscall entries */ cond_syscall (sys_mprotect);cond_syscall (sys_msync);
PATCH 3/9 kevent: poll/select() notifications.
poll/select() notifications.
This patch includes generic poll/select notifications. kevent_poll works simialr to epoll and has the same issues (callback is invoked not from internal state machine of the caller, but through process awake, a lot of allocations and so on).
fs/file_table.c +3 -0
@@ -20,6 +20,7 @@#include <linux/cdev.h> #include <linux/fsnotify.h> #include <linux/sysctl.h> +#include <linux/kevent.h> #include <linux/percpu_counter.h> #include <asm/atomic.h>
@@ -119,6 +120,7 @@ struct file *get_empty_filp(void) f->f_uid = tsk->fsuid; f->f_gid = tsk->fsgid;eventpoll_init_file (f); +kevent_init_file (f);/* f->f_version: 0 */ return f;
@@ -164,6 +166,7 @@ void fastcall __fput(struct file *file)* in the file cleanup chain. */ eventpoll_release (file); +kevent_cleanup_file (file);locks_remove_flock (file);if (file->f_op && file->f_op->release)
include/linux/fs.h +8 -0
@@ -280,6 +280,7 @@ extern int dir_notify_enable;#include <linux/init.h> #include <linux/pid.h> #include <linux/mutex.h> +#include <linux/kevent_storage.h> #include <asm/atomic.h> #include <asm/semaphore.h>
@@ -578,6 +579,10 @@ struct inode {struct mutex inotify_mutex;/* protects the watches list */ #endif +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +struct kevent_storage st; +#endif +unsigned long i_state;unsigned long dirtied_when;/* jiffies of first dirtying */
@@ -737,6 +742,9 @@ struct file {struct list_head f_ep_links;spinlock_t f_ep_lock;#endif /* #ifdef CONFIG_EPOLL */ +#ifdef CONFIG_KEVENT_POLL +struct kevent_storage st; +#endif struct address_space *f_mapping; };extern spinlock_t files_lock;
kernel/kevent/kevent_poll.c new file +234 -0
234 lines not on this page · raw message
PATCH 4/9 kevent: Socket notifications.
Socket notifications.
This patch includes socket send/recv/accept notifications. Using trivial web server based on kevent and this features instead of epoll it's performance increased more than noticebly. More details about various benchmarks and server itself (evserver_kevent.c) can be found on project's homepage.
fs/inode.c +7 -0
@@ -21,6 +21,7 @@#include <linux/cdev.h> #include <linux/bootmem.h> #include <linux/inotify.h> +#include <linux/kevent.h> #include <linux/mount.h> /*
@@ -164,12 +165,18 @@ static struct inode *alloc_inode(struct super_block *sb) } inode->i_private =NULL ; inode->i_mapping = mapping; +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_init (inode, &inode->st); +#endif }return inode; }void destroy_inode (struct inode *inode) { +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_fini (&inode->st); +#endif BUG_ON (inode_has_buffers (inode));security_inode_free (inode);if (inode->i_sb->s_op->destroy_inode)
include/net/sock.h +17 -15
@@ -49,6 +49,7 @@#include <linux/skbuff.h> /* struct sk_buff */ #include <linux/mm.h> #include <linux/security.h> +#include <linux/kevent.h> #include <linux/filter.h>
@@ -451,6 +452,21 @@ static inline int sk_stream_memory_free(struct sock *sk)extern void sk_stream_rfree (struct sk_buff *skb); +struct socket_alloc { +struct socket socket; +struct inode vfs_inode; +}; + +static inline struct socket *SOCKET_I (struct inode *inode) +{ + return &container_of(inode, struct socket_alloc, vfs_inode)->socket; +} + +static inline struct inode *SOCK_INODE (struct socket *socket) +{ + return &container_of(socket, struct socket_alloc, socket)->vfs_inode; +} +static inline void sk_stream_set_owner_r (struct sk_buff *skb,struct sock *sk) { skb->sk = sk;
@@ -478,6 +494,7 @@ static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb) sk->sk_backlog.tail = skb; } skb->next =NULL ; +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); }#define sk_wait_event (__sk, __timeo, __condition) \
@@ -679,21 +696,6 @@ static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si)return si->kiocb; } -struct socket_alloc { -struct socket socket; -struct inode vfs_inode; -}; - -static inline struct socket *SOCKET_I (struct inode *inode) -{ - return &container_of(inode, struct socket_alloc, vfs_inode)->socket; -} - -static inline struct inode *SOCK_INODE (struct socket *socket) -{ - return &container_of(socket, struct socket_alloc, socket)->vfs_inode; -} -extern void __sk_stream_mem_reclaim (struct sock *sk);extern int sk_stream_mem_schedule (struct sock *sk,int size,int kind);
include/net/tcp.h +1 -0
@@ -864,6 +864,7 @@ static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb) tp->ucopy.memory =0 ; }else if (skb_queue_len (&tp->ucopy.prequeue) ==1 ) {wake_up_interruptible (sk->sk_sleep); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND );if (!inet_csk_ack_scheduled (sk)) inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, (3 * TCP_RTO_MIN) / 4,
kernel/kevent/kevent_socket.c new file +144 -0
144 lines not on this page · raw message
net/core/sock.c +9 -1
@@ -1393,6 +1393,7 @@ static void sock_def_wakeup(struct sock *sk)if (sk->sk_sleep &&waitqueue_active (sk->sk_sleep))wake_up_interruptible_all (sk->sk_sleep);read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_error_report (struct sock *sk)
@@ -1402,6 +1403,7 @@ static void sock_def_error_report(struct sock *sk)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,0 ,POLL_ERR );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_readable (struct sock *sk,int len)
@@ -1411,6 +1413,7 @@ static void sock_def_readable(struct sock *sk, int len)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,1 ,POLL_IN );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_write_space (struct sock *sk)
@@ -1430,6 +1433,7 @@ static void sock_def_write_space(struct sock *sk) }read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); }static void sock_def_destruct (struct sock *sk)
@@ -1480,6 +1484,8 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_state =TCP_CLOSE ; sk->sk_socket = sock; +kevent_sk_reinit (sk); +sock_set_flag (sk,SOCK_ZAPPED );if (sock)
@@ -1546,8 +1552,10 @@ void fastcall release_sock(struct sock *sk)if (sk->sk_backlog.tail)__release_sock (sk); sk->sk_lock.owner =NULL ; -if (waitqueue_active (&sk->sk_lock.wq)) +if (waitqueue_active (&sk->sk_lock.wq)) {wake_up (&sk->sk_lock.wq); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); + }spin_unlock_bh (&sk->sk_lock.slock); }EXPORT_SYMBOL (release_sock);
net/core/stream.c +1 -0
@@ -36,6 +36,7 @@ void sk_stream_write_space(struct sock *sk)wake_up_interruptible (sk->sk_sleep);if (sock->fasync_list && !(sk->sk_shutdown &SEND_SHUTDOWN ))sock_wake_async (sock,2 ,POLL_OUT ); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); } }
net/ipv4/tcp_input.c +1 -0
@@ -3127,6 +3127,7 @@ static void tcp_ofo_queue(struct sock *sk)__skb_unlink (skb, &tp->out_of_order_queue);__skb_queue_tail (&sk->sk_receive_queue, skb); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); tp->rcv_nxt =TCP_SKB_CB (skb)->end_seq;if (skb->h.th->fin)tcp_fin (skb, sk, skb->h.th);
net/ipv4/tcp_ipv4.c +2 -0
@@ -61,6 +61,7 @@#include <linux/jhash.h> #include <linux/init.h> #include <linux/times.h> +#include <linux/kevent.h> #include <net/icmp.h> #include <net/inet_hashtables.h>
@@ -1391,6 +1392,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)reqsk_free (req); }else {inet_csk_reqsk_queue_hash_add (sk, req,TCP_TIMEOUT_INIT ); +kevent_socket_notify (sk,KEVENT_SOCKET_ACCEPT ); }return 0 ;
net/socket.c +3 -0
@@ -84,6 +84,7 @@#include <linux/kmod.h> #include <linux/audit.h> #include <linux/wireless.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -496,6 +497,8 @@ static struct socket *sock_alloc(void) inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; +kevent_socket_reinit (sock); +get_cpu_var (sockets_in_use)++;put_cpu_var (sockets_in_use);return sock;
net/unix/af_unix.c +21 -1
@@ -1563,8 +1563,10 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,struct scm_cookie tmp_scm;struct sock *sk = sock->sk;struct unix_sock *u =unix_sk (sk); +struct sock *other;int noblock = flags &MSG_DONTWAIT ;struct sk_buff *skb; +int err; err = -EOPNOTSUPP ;
@@ -1580,6 +1582,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, goto out_unlock;wake_up_interruptible (&u->peer_wait); + other =unix_peer_get (sk); +if (other) { +kevent_socket_notify (other,KEVENT_SOCKET_SEND ); +sock_put (other); + }else +kevent_socket_notify (sk,KEVENT_SOCKET_RECV );if (msg->msg_name)unix_copy_addr (msg, skb->sk);
@@ -1674,7 +1682,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, {struct sock_iocb *siocb =kiocb_to_siocb (iocb);struct scm_cookie tmp_scm; -struct sock *sk = sock->sk; +struct sock *sk = sock->sk, *other;struct unix_sock *u =unix_sk (sk);struct sockaddr_un *sunaddr=msg->msg_name;int copied =0 ;
@@ -1803,6 +1811,14 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, } }while (size); + other =unix_peer_get (sk); +if (other) { +kevent_socket_notify (other,KEVENT_SOCKET_SEND ); +sock_put (other); + } +if (sk->sk_shutdown &RCV_SHUTDOWN || !other) +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); +mutex_unlock (&u->readlock);scm_recv (sock, msg, siocb->scm, flags); out:
@@ -1824,6 +1840,10 @@ static int unix_shutdown(struct socket *sock, int mode)sock_hold (other);unix_state_wunlock (sk); sk->sk_state_change (sk); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); +if (other) +kevent_socket_notify (other,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV );if (other && (sk->sk_type ==SOCK_STREAM || sk->sk_type ==SOCK_SEQPACKET )) {
PATCH 5/9 kevent: Timer notifications.
Timer notifications.
Timer notifications can be used for fine grained per-process time management, since interval timers are very inconvenient to use, and they are limited.
This subsystem uses high-resolution timers.
id.raw[0] is used as number of seconds
id.raw[1] is used as number of nanoseconds
kernel/kevent/kevent_timer.c new file +114 -0
@@ -0,0 +1,114 @@ +/* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/jiffies.h> +#include <linux/kevent.h> + +struct kevent_timer +{ +struct hrtimer ktimer; +struct kevent_storage ktimer_storage; +struct kevent *ktimer_event; +}; + +static int kevent_timer_func (struct hrtimer *timer) +{ + struct kevent_timer *t = container_of(timer, struct kevent_timer, ktimer); +struct kevent *k = t->ktimer_event; + +kevent_storage_ready (&t->ktimer_storage,NULL ,KEVENT_MASK_ALL ); +hrtimer_forward (timer, timer->base->softirq_time, +ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ])); +return HRTIMER_RESTART ; +} + +static struct lock_class_key kevent_timer_key; + +static int kevent_timer_enqueue (struct kevent *k) +{ +int err; +struct kevent_timer *t; + + t =kmalloc (sizeof (struct kevent_timer ),GFP_KERNEL ); +if (!t) +return -ENOMEM ; + +hrtimer_init (&t->ktimer,CLOCK_MONOTONIC ,HRTIMER_REL ); + t->ktimer.expires =ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ]); + t->ktimer.function = kevent_timer_func; + t->ktimer_event = k; + + err =kevent_storage_init (&t->ktimer, &t->ktimer_storage); +if (err) + goto err_out_free; +lockdep_set_class (&t->ktimer_storage.lock, &kevent_timer_key); + + err =kevent_storage_enqueue (&t->ktimer_storage, k); +if (err) + goto err_out_st_fini; + +hrtimer_start (&t->ktimer, t->ktimer.expires,HRTIMER_REL ); + +return 0 ; + +err_out_st_fini: +kevent_storage_fini (&t->ktimer_storage); +err_out_free: +kfree (t); + +return err; +} + +static int kevent_timer_dequeue (struct kevent *k) +{ +struct kevent_storage *st = k->st; + struct kevent_timer *t = container_of(st, struct kevent_timer, ktimer_storage); + +hrtimer_cancel (&t->ktimer); +kevent_storage_dequeue (st, k); +kfree (t); + +return 0 ; +} + +static int kevent_timer_callback (struct kevent *k) +{ + k->event.ret_data[0 ] =jiffies_to_msecs (jiffies); +return 1 ; +} + +static int __init kevent_init_timer (void ) +{ +struct kevent_callbacks tc = { + .callback = &kevent_timer_callback, + .enqueue = &kevent_timer_enqueue, + .dequeue = &kevent_timer_dequeue, + .flags =0 , + }; + +return kevent_add_callbacks (&tc,KEVENT_TIMER ); +} +module_init (kevent_init_timer); +
PATCH 6/9 kevent: Pipe notifications.
Pipe notifications.
fs/pipe.c +6 -0
@@ -16,6 +16,7 @@#include <linux/uio.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/ioctls.h>
@@ -313,6 +314,7 @@ redo:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -322,6 +324,7 @@ redo:/* Signal writers asynchronously that there is more room. */ if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -484,6 +487,7 @@ redo2:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); do_wakeup =0 ;
@@ -495,6 +499,7 @@ redo2: out:mutex_unlock (&inode->i_mutex);if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); }
@@ -590,6 +595,7 @@ pipe_release(struct inode *inode, int decr, int decw)free_pipe_info (inode); }else {wake_up_interruptible (&pipe->wait); +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV );kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN );kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
kernel/kevent/kevent_pipe.c new file +123 -0
123 lines not on this page · raw message
PATCH 7/9 kevent: Signal notifications.
Signal notifications.
This type of notifications allows to deliver signals through kevent queue. One can find example application signal.c on project homepage.
If KEVENT_SIGNAL_NOMASK bit is set in raw_u64 id then signal will be delivered only through queue, otherwise both delivery types are used - old through update of mask of pending signals and through queue.
If signal is delivered only through kevent queue mask of pending signals is not updated at all, which is equal to putting signal into blocked mask, but with delivery of that signal through kevent queue.
include/linux/sched.h +5 -0
@@ -82,6 +82,7 @@ struct sched_param {#include <linux/resource.h> #include <linux/timer.h> #include <linux/hrtimer.h> +#include <linux/kevent_storage.h> #include <linux/task_io_accounting.h> #include <asm/processor.h>
@@ -1048,6 +1049,10 @@ struct task_struct {#ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info *delays;#endif +#ifdef CONFIG_KEVENT_SIGNAL +struct kevent_storage st; +u32 kevent_signals; +#endif #ifdef CONFIG_FAULT_INJECTION int make_it_fail;#endif
kernel/fork.c +8 -0
@@ -49,6 +49,7 @@#include <linux/delayacct.h> #include <linux/taskstats_kern.h> #include <linux/random.h> +#include <linux/kevent.h> #include <asm/pgtable.h> #include <asm/pgalloc.h>
@@ -118,6 +119,9 @@ void __put_task_struct(struct task_struct *tsk)WARN_ON (atomic_read (&tsk->usage));WARN_ON (tsk == current); +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_fini (&tsk->st); +#endif security_task_free (tsk);free_uid (tsk->user);put_group_info (tsk->group_info);
@@ -1126,6 +1130,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,if (retval) goto bad_fork_cleanup_namespaces; +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_init (p, &p->st); +#endif + p->set_child_tid = (clone_flags &CLONE_CHILD_SETTID ) ? child_tidptr :NULL ;/* * Clear TID on mm_release()?
kernel/kevent/kevent_signal.c new file +94 -0
94 lines not on this page · raw message
kernel/signal.c +26 -0
@@ -23,6 +23,7 @@#include <linux/ptrace.h> #include <linux/signal.h> #include <linux/capability.h> +#include <linux/kevent.h> #include <linux/freezer.h> #include <linux/pid_namespace.h> #include <linux/nsproxy.h>
@@ -714,6 +715,9 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, {struct sigqueue * q =NULL ;int ret =0 ; + +if (kevent_signal_notify (t, sig)) +return 1 ;/* * fast-pathed signals for kernel-internal things like SIGSTOP
@@ -793,6 +797,17 @@ 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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif out:return ret; }
@@ -982,6 +997,17 @@ __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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif if (unlikely (ret))return ret;
PATCH 8/9 kevent: Kevent posix timer notifications.
Kevent posix timer notifications.
Simple extensions to POSIX timers which allows
to deliver notification of the timer expiration
through kevent queue.
Example application posix_timer.c can be found
in archive on project homepage.
include/asm-generic/siginfo.h +3 -0
@@ -235,6 +235,7 @@ typedef struct siginfo {#define SIGEV_NONE 1/* other notification: meaningless */ #define SIGEV_THREAD 2/* deliver via thread creation */ #define SIGEV_THREAD_ID 4/* deliver to thread */ +#define SIGEV_KEVENT 8/* deliver through kevent queue */ /* * This works because the alignment is ok on all current architectures
@@ -260,6 +261,8 @@ typedef struct sigevent {void (*_function)(sigval_t );void *_attribute;/* really pthread_attr_t */ } _sigev_thread; + +int kevent_fd; } _sigev_un; } sigevent_t;
include/linux/posix-timers.h +4 -0
@@ -4,6 +4,7 @@#include <linux/spinlock.h> #include <linux/list.h> #include <linux/sched.h> +#include <linux/kevent_storage.h> union cpu_time_count {cputime_t cpu;
@@ -49,6 +50,9 @@ struct k_itimer {sigval_t it_sigev_value;/* value word of sigevent struct */ struct task_struct *it_process;/* process to send signal to */ struct sigqueue *sigq;/* signal queue entry. */ +#ifdef CONFIG_KEVENT_TIMER +struct kevent_storage st; +#endif union { struct { struct hrtimer timer;
kernel/posix-timers.c +171 -48
264 lines not on this page · raw message
PATCH 9/9 kevent: Private userspace notifications.
Private userspace notifications.
Allows to register notifications of any private userspace events over kevent. Events can be marked as readt using kevent_ctl(KEVENT_READY) command.
kernel/kevent/kevent_unotify.c new file +62 -0
@@ -0,0 +1,62 @@ +/* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/kernel.h> +#include <linux/kevent.h> + +static int kevent_unotify_callback (struct kevent *k) +{ +return 1 ; +} + +int kevent_unotify_enqueue (struct kevent *k) +{ +int err; + + err =kevent_storage_enqueue (&k->user->st, k); +if (err) + goto err_out_exit; + +if (k->event.req_flags &KEVENT_REQ_ALWAYS_QUEUE ) +kevent_requeue (k); + +return 0 ; + +err_out_exit: +return err; +} + +int kevent_unotify_dequeue (struct kevent *k) +{ +kevent_storage_dequeue (k->st, k); +return 0 ; +} + +static int __init kevent_init_unotify (void ) +{ +struct kevent_callbacks sc = { + .callback = &kevent_unotify_callback, + .enqueue = &kevent_unotify_enqueue, + .dequeue = &kevent_unotify_dequeue, + .flags =0 , + }; + +return kevent_add_callbacks (&sc,KEVENT_UNOTIFY ); +} +module_init (kevent_init_unotify);
cover kevent: Generic event handling mechanism.
In reply to a message not in the archiveGeneric event handling mechanism.
Kevent is a generic subsytem which allows to handle event notifications. It supports both level and edge triggered events. It is similar to poll/epoll in some cases, but it is more scalable, it is faster and allows to work with essentially eny kind of events.
Events are provided into kernel through control syscall and can be read back through ring buffer or using usual syscalls.
Kevent update (i.e. readiness switching) happens directly from internals of the appropriate state machine of the underlying subsytem (like network, filesystem, timer or any other).
Homepage:
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
Documentation page:
http://linux-net.osdl.org/index.php/Kevent
Consider for inclusion.
P.S. If you want to be removed from Cc: list just drop me a mail.
Changes from 'take30' patchset:
* AIO state machine.
* aio_sendfile() implementation.
* moved kevent_user_get/kevent_user_put into header.
* use *zalloc where needed.
Changes from 'take29' patchset:
* new private userspace notifications - allows to queue any userspace private event and then mark it as ready using kevent_ctl(KEVENT_READY) command
* KEVENT_REQ_READY flag - if set kevent will be marked as ready at enqueue time
* port to 2.6.20-rc2 tree (54abb5fcdae74a811ed440ec6556cabc6b24f404 commit)
* use struct kmem_cache instead of kmem_cache_t
* added notificaion type into search key, this allows to have the same id for different types of notifications
Changes from 'take28' patchset:
* optimized af_unix to use socket notifications
* changed ALWAYS_QUEUE behaviour with poll/select notifications - previously kevent was not queued into poll wait queue when ALWAYS_QUEUE flag is set
* added KEVENT_POLL_POLLRDHUP definition into ukevent.h header
* libevent-1.2 patch (Jamal, your request is completed, so I'm waiting two weeks before starting final countdown :)
All regression tests passed successfully except test_evbuffer(), which is crashed on my amd64 linux 2.6 test machine for all types of notifications, probably it was fixed in libevent-1.2a version, I did not check. Patch and README can be found at project homepage.
Changes from 'take27' patchset:
* made kevent default yes in non embedded case.
* added falgs to callback structures - currently used to check if kevent can be requested from kernelspace only (posix timers) or userspace (all others)
Changes from 'take26' patchset:
* made kevent visible in config only in case of embedded setup.
* added comment about KEVENT_MAX number.
* spell fix.
Changes from 'take25' patchset:
* use timespec as timeout parameter.
* added high-resolution timer to handle absolute timeouts.
* added flags to waiting and initialization syscalls.
* kevent_commit() has new_uidx parameter.
* kevent_wait() has old_uidx parameter, which, if not equal to u->uidx, results in immediate wakeup (usefull for the case when entries
are added asynchronously from kernel (not supported for now)).
* added interface to mark any event as ready.
* event POSIX timers support.
* return -ENOSYS if there is no registered event type.
* provided file descriptor must be checked for fifo type (spotted by Eric Dumazet).
* signal notifications.
* documentation update.
* lighttpd patch updated (the latest benchmarks with lighttpd patch can be found in blog).
Changes from 'take24' patchset:
* new (old (new)) ring buffer implementation with kernel and user indexes.
* added initialization syscall instead of opening /dev/kevent
* kevent_commit() syscall to commit ring buffer entries
* changed KEVENT_REQ_WAKEUP_ONE flag to KEVENT_REQ_WAKEUP_ALL, kevent wakes only first thread always if that flag is not set
* KEVENT_REQ_ALWAYS_QUEUE flag. If set, kevent will be queued into ready queue instead of copying back to userspace when kevent is ready immediately when it is added.
* lighttpd patch (Hail! Although nothing really outstanding compared to epoll)
Changes from 'take23' patchset:
* kevent PIPE notifications
* KEVENT_REQ_LAST_CHECK flag, which allows to perform last check at dequeueing time
* fixed poll/select notifications (were broken due to tree manipulations)
* made Documentation/kevent.txt look nice in 80-col terminal
* fix for copy_to_user() failure report for the first kevent (Andrew Morton)
* minor function renames
Changes from 'take22' patchset:
* new ring buffer implementation in process' memory
* wakeup-one-thread flag
* edge-triggered behaviour
Changes from 'take21' patchset:
* minor cleanups (different return values, removed unneded variables, whitespaces and so on)
* fixed bug in kevent removal in case when kevent being removed
is the same as overflow_kevent (spotted by Eric Dumazet)
Changes from 'take20' patchset:
* new ring buffer implementation
* removed artificial limit on possible number of kevents
Changes from 'take19' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take18' patchset:
* use __init instead of __devinit
* removed 'default N' from config for user statistic
* removed kevent_user_fini() since kevent can not be unloaded
* use KERN_INFO for statistic output
Changes from 'take17' patchset:
* Use RB tree instead of hash table.
At least for a web sever, frequency of addition/deletion of new kevent is comparable with number of search access, i.e. most of the time events are added, accesed only couple of times and then removed, so it justifies RB tree usage over AVL tree, since the latter does have much slower deletion time (max O(log(N)) compared to 3 ops),
although faster search time (1.44*O(log(N)) vs. 2*O(log(N))).
So for kevents I use RB tree for now and later, when my AVL tree implementation is ready, it will be possible to compare them.
* Changed readiness check for socket notifications.
With both above changes it is possible to achieve more than 3380 req/second compared to 2200, sometimes 2500 req/second for epoll() for trivial web-server and httperf client on the same hardware.
It is possible that above kevent limit is due to maximum allowed kevents in a time limit, which is 4096 events.
Changes from 'take16' patchset:
* misc cleanups (__read_mostly, const ...)
* created special macro which is used for mmap size (number of pages) calculation
* export kevent_socket_notify(), since it is used in network protocols which can be built as modules (IPv6 for example)
Changes from 'take15' patchset:
* converted kevent_timer to high-resolution timers, this forces timer API update at
http://linux-net.osdl.org/index.php/Kevent
* use struct ukevent* instead of void * in syscalls (documentation has been updated)
* added warning in kevent_add_ukevent() if ring has broken index (for testing)
Changes from 'take14' patchset:
* added kevent_wait()
This syscall waits until either timeout expires or at least one event becomes ready. It also commits that @num events from @start are processed by userspace and thus can be be removed or rearmed (depending on it's flags). It can be used for commit events read by userspace through mmap interface. Example userspace code (evtest.c) can be found on project's homepage.
* added socket notifications (send/recv/accept)
Changes from 'take13' patchset:
* do not get lock aroung user data check in __kevent_search()
* fail early if there were no registered callbacks for given type of kevent
* trailing whitespace cleanup
Changes from 'take12' patchset:
* remove non-chardev interface for initialization
* use pointer to kevent_mring instead of unsigned longs
* use aligned 64bit type in raw user data (can be used by high-res timer if needed)
* simplified enqueue/dequeue callbacks and kevent initialization
* use nanoseconds for timeout
* put number of milliseconds into timer's return data
* move some definitions into user-visible header
* removed filenames from comments
Changes from 'take11' patchset:
* include missing headers into patchset
* some trivial code cleanups (use goto instead of if/else games and so on)
* some whitespace cleanups
* check for ready_callback() callback before main loop which should save us some ticks
Changes from 'take10' patchset:
* removed non-existent prototypes
* added helper function for kevent_registered_callbacks
* fixed 80 lines comments issues
* added shared between userspace and kernelspace header instead of embedd them in one
* core restructuring to remove forward declarations
* s o m e w h i t e s p a c e c o d y n g s t y l e c l e a n u p
* use vm_insert_page() instead of remap_pfn_range()
Changes from 'take9' patchset:
* fixed ->nopage method
Changes from 'take8' patchset:
* fixed mmap release bug
* use module_init() instead of late_initcall()
* use better structures for timer notifications
Changes from 'take7' patchset:
* new mmap interface (not tested, waiting for other changes to be acked)
- use nopage() method to dynamically substitue pages
- allocate new page for events only when new added kevent requres it
- do not use ugly index dereferencing, use structure instead
- reduced amount of data in the ring (id and flags), maximum 12 pages on x86 per kevent fd
Changes from 'take6' patchset:
* a lot of comments!
* do not use list poisoning for detection of the fact, that entry is in the list
* return number of ready kevents even if copy*user() fails
* strict check for number of kevents in syscall
* use ARRAY_SIZE for array size calculation
* changed superblock magic number
* use SLAB_PANIC instead of direct panic() call
* changed -E* return values
* a lot of small cleanups and indent fixes
Changes from 'take5' patchset:
* removed compilation warnings about unused wariables when lockdep is not turned on
* do not use internal socket structures, use appropriate (exported) wrappers instead
* removed default 1 second timeout
* removed AIO stuff from patchset
Changes from 'take4' patchset:
* use miscdevice instead of chardevice
* comments fixes
Changes from 'take3' patchset:
* removed serializing mutex from kevent_user_wait()
* moved storage list processing to RCU
* removed lockdep screaming - all storage locks are initialized in the same function, so it was
learned
to differentiate between various cases
* remove kevent from storage if is marked as broken after callback
* fixed a typo in mmaped buffer implementation which would end up in wrong index calcualtion
Changes from 'take2' patchset:
* split kevent_finish_user() to locked and unlocked variants
* do not use KEVENT_STAT ifdefs, use inline functions instead
* use array of callbacks of each type instead of each kevent callback initialization
* changed name of ukevent guarding lock
* use only one kevent lock in kevent_user for all hash buckets instead of per-bucket locks
* do not use kevent_user_ctl structure instead provide needed arguments as syscall parameters
* various indent cleanups
* added optimisation, which is aimed to help when a lot of kevents are being copied from
userspace
* mapped buffer (initial) implementation (no userspace yet)
Changes from 'take1' patchset:
- rebased against 2.6.18-git tree
- removed ioctl controlling
- added new syscall kevent_get_events(int fd, unsigned int min_nr, unsigned int max_nr, unsigned int timeout, void __user *buf, unsigned flags)
- use old syscall kevent_ctl for creation/removing, modification and initial kevent initialization
- use mutuxes instead of semaphores
- added file descriptor check and return error if provided descriptor does not match kevent file operations
- various indent fixes
- removed aio_sendfile() declarations.
Thank you.
PATCH 1/10 kevent: Description.
Description.
Documentation/kevent.txt new file +244 -0
@@ -0,0 +1,244 @@ +Description. + +int kevent_init(struct kevent_ring *ring, unsigned int ring_size, + unsigned int flags); + +num - size of the ring buffer in events +ring - pointer to allocated ring buffer +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: kevent control file descriptor or negative error value. + + struct kevent_ring + { + unsigned int ring_kidx, ring_over; + struct ukevent event[0]; + } + +ring_kidx - index in the ring buffer where kernel will put new events + when kevent_wait() or kevent_get_events() is called +ring_over - number of overflows of ring_uidx happend from the start. + Overflow counter is used to prevent situation when two threads + are going to free the same events, but one of them was scheduled + away for too long, so ring indexes were wrapped, so when that + thread will be awakened, it will free not those events, which + it suppose to free. + +Example userspace code (ring_buffer.c) can be found on project's homepage. + +Each kevent syscall can be so called cancellation point in glibc, i.e. when +thread has been cancelled in kevent syscall, thread can be safely removed +and no events will be lost, since each syscall (kevent_wait() or +kevent_get_events()) will copy event into special ring buffer, accessible +from other threads or even processes (if shared memory is used). + +When kevent is removed (not dequeued when it is ready, but just removed), +even if it was ready, it is not copied into ring buffer, since if it is +removed, no one cares about it (otherwise user would wait until it becomes +ready and got it through usual way using kevent_get_events() or kevent_wait()) +and thus no need to copy it to the ring buffer. + +------------------------------------------------------------------------------- + + +int kevent_ctl(int fd, unsigned int cmd, unsigned int num, struct ukevent *arg); + +fd - is the file descriptor referring to the kevent queue to manipulate. +It is created by opening "/dev/kevent" char device, which is created with +dynamic minor number and major number assigned for misc devices. + +cmd - is the requested operation. It can be one of the following: + KEVENT_CTL_ADD - add event notification + KEVENT_CTL_REMOVE - remove event notification + KEVENT_CTL_MODIFY - modify existing notification + KEVENT_CTL_READY - mark existing events as ready, if number of events is zero, + it just wakes up parked in syscall thread + +num - number of struct ukevent in the array pointed to by arg +arg - array of struct ukevent + +Return value: + number of events processed or negative error value. + +When called, kevent_ctl will carry out the operation specified in the +cmd parameter. +------------------------------------------------------------------------------- + + int kevent_get_events(int ctl_fd, unsigned int min_nr, unsigned int max_nr, + struct timespec timeout, struct ukevent *buf, unsigned flags); + +ctl_fd - file descriptor referring to the kevent queue +min_nr - minimum number of completed events that kevent_get_events will block + waiting for +max_nr - number of struct ukevent in buf +timeout - time to wait before returning less than min_nr + events. If this is -1, then wait forever. +buf - pointer to an array of struct ukevent. +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied or negative error value. + +kevent_get_events will wait timeout milliseconds for at least min_nr completed +events, copying completed struct ukevents to buf and deleting any +KEVENT_REQ_ONESHOT event requests. In nonblocking mode it returns as many +events as possible, but not more than max_nr. In blocking mode it waits until +timeout or if at least min_nr events are ready. + +This function copies event into ring buffer if it was initialized, if ring buffer +is full, KEVENT_RET_COPY_FAILED flag is set in ret_flags field. +------------------------------------------------------------------------------- + + int kevent_wait(int ctl_fd, unsigned int num, unsigned int old_uidx, + struct timespec timeout, unsigned int flags); + +ctl_fd - file descriptor referring to the kevent queue +num - number of processed kevents +old_uidx - the last index user is aware of +timeout - time to wait until there is free space in kevent queue +flags - various flags, see KEVENT_FLAGS_* definitions. + +Return value: + number of events copied into ring buffer or negative error value. + +This syscall waits until either timeout expires or at least one event becomes +ready. It also copies events into special ring buffer. If ring buffer is full, +it waits until there are ready events and then return. +If kevent is one-shot kevent it is removed in this syscall. +If kevent is edge-triggered (KEVENT_REQ_ET flag is set in 'req_flags') it is +requeued in this syscall for performance reasons. +------------------------------------------------------------------------------- + + int kevent_commit(int ctl_fd, unsigned int new_idx, unsigned int over); + +ctl_fd - file descriptor referring to the kevent queue +new_uidx - the last committed kevent +over - overflow count for given $new_idx value + +Return value: + number of committed kevents or negative error value. + +This function commits, i.e. marks as empty, slots in the ring buffer, so +they can be reused when userspace completes that entries processing. + +Overflow counter is used to prevent situation when two threads are going +to free the same events, but one of them was scheduled away for too long, +so ring indexes were wrapped, so when that thread will be awakened, it +will free not those events, which it suppose to free. + +It is possible that returned number of committed events will be smaller than +requested number - it is possible when several threads try to commit the +same events. +------------------------------------------------------------------------------- + +The bulk of the interface is entirely done through the ukevent struct. +It is used to add event requests, modify existing event requests, +specify which event requests to remove, and return completed events. + +struct ukevent contains the following members: + +struct kevent_id id + Id of this request, e.g. socket number, file descriptor and so on +__u32 type + Event type, e.g. KEVENT_SOCK, KEVENT_INODE, KEVENT_TIMER and so on +__u32 event + Event itself, e.g. SOCK_ACCEPT, INODE_CREATED, TIMER_FIRED +__u32 req_flags + Per-event request flags, + + KEVENT_REQ_ONESHOT + event will be removed when it is ready + + KEVENT_REQ_WAKEUP_ALL + Kevent wakes up only first thread interested in given event, + or all threads if this flag is set. + + KEVENT_REQ_ET + Edge Triggered behaviour. It is an optimisation which allows to move + ready and dequeued (i.e. copied to userspace) event to move into set + of interest for given storage (socket, inode and so on) again. It is + very usefull for cases when the same event should be used many times + (like reading from pipe). It is similar to epoll()'s EPOLLET flag. + + KEVENT_REQ_LAST_CHECK + if set allows to perform the last check on kevent (call appropriate + callback) when kevent is marked as ready and has been removed from + ready queue. If it will be confirmed that kevent is ready + (k->callbacks.callback(k) returns true) then kevent will be copied + to userspace, otherwise it will be requeued back to storage. + Second (checking) call is performed with this bit cleared, so callback + can detect when it was called from kevent_storage_ready() - bit is set, + or kevent_dequeue_ready() - bit is cleared. If kevent will be requeued, + bit will be set again. + + KEVENT_REQ_ALWAYS_QUEUE + If this flag is set kevent will be queued into ready queue if it is + ready at enqueue time, otherwise it will be copied back to userspace + and will not be queued into the storage. + + KEVENT_REQ_READY + If this flag is set, kevent will be marked as ready immediately at enqueue + time. + +__u32 ret_flags + Per-event return flags + + KEVENT_RET_BROKEN + Kevent is broken + + KEVENT_RET_DONE + Kevent processing was finished successfully + + KEVENT_RET_COPY_FAILED + Kevent was not copied into ring buffer due to some error conditions. + +__u32 ret_data + Event return data. Event originator fills it with anything it likes + (for example timer notifications put number of milliseconds when timer + has fired +union { __u32 user[2]; void *ptr; } + User's data. It is not used, just copied to/from user. The whole structure + is aligned to 8 bytes already, so the last union is aligned properly. + +------------------------------------------------------------------------------- + +Kevent waiting syscall flags. + +KEVENT_FLAGS_ABSTIME - provided timespec parameter contains absolute time, + for example Aug 27, 2194, or time(NULL) + 10. + +------------------------------------------------------------------------------- + +Usage + +For KEVENT_CTL_ADD, all fields relevant to the event type must be filled +(id, type, event, req_flags). +After kevent_ctl(..., KEVENT_CTL_ADD, ...) returns each struct's ret_flags +should be checked to see if the event is already broken or done. + +For KEVENT_CTL_MODIFY, the id, req_flags, and user and event fields must be +set and an existing kevent request must have matching id and user fields. If +match is found, req_flags and event are replaced with the newly supplied +values and requeueing is started, so modified kevent can be checked and +probably marked as ready immediately. If a match can't be found, the +passed in ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is +always set. + +For KEVENT_CTL_REMOVE, the id and user fields must be set and an existing +kevent request must have matching id and user fields. If a match is found, +the kevent request is removed. If a match can't be found, the passed in +ukevent's ret_flags has KEVENT_RET_BROKEN set. KEVENT_RET_DONE is always set. + +For kevent_get_events, the entire structure is returned. + +------------------------------------------------------------------------------- + +Usage cases + +kevent_timer +struct ukevent should contain following fields: + type - KEVENT_TIMER + event - KEVENT_TIMER_FIRED + req_flags - KEVENT_REQ_ONESHOT if you want to fire that timer only once + id.raw[0] - number of seconds after commit when this timer shout expire + id.raw[0] - additional to number of seconds number of nanoseconds
PATCH 2/10 kevent: Core files.
Core files.
This patch includes core kevent files:
* userspace controlling
* kernelspace interfaces
* initialization
* notification state machines
Some bits of documentation can be found on project's homepage (and links from there):
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
arch/i386/kernel/syscall_table.S +6 -0
@@ -319,3 +319,9 @@ ENTRY(sys_call_table) .long sys_move_pages .long sys_getcpu .long sys_epoll_pwait + .long sys_kevent_get_events + .long sys_kevent_ctl /* 320 */ + .long sys_kevent_wait + .long sys_kevent_commit + .long sys_kevent_init + .lond sys_aio_sendfile
arch/x86_64/ia32/ia32entry.S +7 -1
@@ -714,8 +714,14 @@ ia32_sys_call_table: .quad compat_sys_get_robust_list .quad sys_splice .quad sys_sync_file_range - .quad sys_tee + .quad sys_tee /* 315 */ .quad compat_sys_vmsplice .quad compat_sys_move_pages .quad sys_getcpu + .quad sys_kevent_get_events + .quad sys_kevent_ctl /* 320 */ + .quad sys_kevent_wait + .quad sys_kevent_commit + .quad sys_kevent_init + .quad sys_aio_sendfile ia32_syscall_end:
include/asm-i386/unistd.h +7 -1
@@ -325,10 +325,16 @@#define __NR_move_pages 317#define __NR_getcpu 318#define __NR_epoll_pwait 319 +#define __NR_kevent_get_events 320 +#define __NR_kevent_ctl 321 +#define __NR_kevent_wait 322 +#define __NR_kevent_commit 323 +#define __NR_kevent_init 324 +#define __NR_aio_sendfile 325#ifdef __KERNEL__ -#define NR_syscalls 320 +#define NR_syscalls 326#define __ARCH_WANT_IPC_PARSE_VERSION#define __ARCH_WANT_OLD_READDIR
include/asm-x86_64/unistd.h +14 -2
@@ -619,8 +619,20 @@ __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_syscall_max __NR_move_pages +#define __NR_kevent_get_events 280 +__SYSCALL(__NR_kevent_get_events, sys_kevent_get_events) +#define __NR_kevent_ctl 281 +__SYSCALL(__NR_kevent_ctl, sys_kevent_ctl) +#define __NR_kevent_wait 282 +__SYSCALL(__NR_kevent_wait, sys_kevent_wait) +#define __NR_kevent_commit 283 +__SYSCALL(__NR_kevent_commit, sys_kevent_commit) +#define __NR_kevent_init 284 +__SYSCALL(__NR_kevent_init, sys_kevent_init) +#define __NR_aio_sendfile 285 +__SYSCALL(__NR_aio_sendfile, sys_aio_sendfile) + +#define __NR_syscall_max __NR_aio_sendfile#ifndef __NO_STUBS#define __ARCH_WANT_OLD_READDIR
include/linux/kevent.h new file +268 -0
268 lines not on this page · raw message
include/linux/kevent_storage.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef __KEVENT_STORAGE_H +#define __KEVENT_STORAGE_H + +struct kevent_storage +{ +void *origin;/* Originator's pointer, e.g. struct sock or struct file. Can be NULL. */ +struct list_head list;/* List of queued kevents. */ +spinlock_t lock;/* Protects users queue. */ +}; + +#endif /* __KEVENT_STORAGE_H */
include/linux/syscalls.h +12 -0
@@ -54,6 +54,8 @@ struct compat_stat;struct compat_timeval ;struct robust_list_head ;struct getcpu_cache ; +struct ukevent ; +struct kevent_ring ;#include <linux/types.h> #include <linux/aio_abi.h>
@@ -603,6 +605,16 @@ asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, size_t len);asmlinkage long sys_getcpu (unsigned __user *cpu,unsigned __user *node,struct getcpu_cache __user *cache); +asmlinkage long sys_kevent_get_events (int ctl_fd,unsigned int min,unsigned int max, +struct timespec timeout,struct ukevent __user *buf,unsigned flags); +asmlinkage long sys_kevent_ctl (int ctl_fd,unsigned int cmd,unsigned int num,struct ukevent __user *buf); +asmlinkage long sys_kevent_wait (int ctl_fd,unsigned int num,unsigned int old_uidx, +struct timespec timeout,unsigned int flags); +asmlinkage long sys_kevent_commit (int ctl_fd,unsigned int new_uidx,unsigned int over); +asmlinkage long sys_kevent_init (int ctl_fd,struct kevent_ring __user *ring,unsigned int num,unsigned int flags); +int kernel_execve (const char *filename,char *const argv[],char *const envp[]); +asmlinkage long sys_aio_sendfile (int kevent_fd,int sock_fd,int in_fd,off_t offset,size_t count); +#endif
include/linux/ukevent.h new file +191 -0
191 lines not on this page · raw message
init/Kconfig +2 -0
@@ -219,6 +219,8 @@ config AUDITSYSCALL such as SELinux. To use audit's filesystem watch feature, please ensure that INOTIFY is configured. +source "kernel/kevent/Kconfig" + config IKCONFIG tristate "Kernel .config support" ---help---
kernel/Makefile +1 -0
@@ -46,6 +46,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o +obj-$(CONFIG_KEVENT) += kevent/ obj-$(CONFIG_RELAY) += relay.o obj-$(CONFIG_UTS_NS) += utsname.o obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
kernel/kevent/Kconfig new file +82 -0
82 lines not on this page · raw message
kernel/kevent/Makefile new file +8 -0
@@ -0,0 +1,8 @@ +obj-y := kevent.o kevent_user.o +obj-$(CONFIG_KEVENT_TIMER) += kevent_timer.o +obj-$(CONFIG_KEVENT_POLL) += kevent_poll.o +obj-$(CONFIG_KEVENT_SOCKET) += kevent_socket.o +obj-$(CONFIG_KEVENT_PIPE) += kevent_pipe.o +obj-$(CONFIG_KEVENT_SIGNAL) += kevent_signal.o +obj-$(CONFIG_KEVENT_UNOTIFY) += kevent_unotify.o +obj-$(CONFIG_KEVENT_AIO) += kevent_aio.o
kernel/kevent/kevent.c new file +267 -0
267 lines not on this page · raw message
kernel/kevent/kevent_user.c new file +1360 -0
1,360 lines not on this page · raw message
kernel/sys_ni.c +8 -0
@@ -123,6 +123,14 @@ cond_syscall(ppc_rtas);cond_syscall (sys_spu_run);cond_syscall (sys_spu_create); +cond_syscall (sys_kevent_get_events); +cond_syscall (sys_kevent_ctl); +cond_syscall (sys_kevent_wait); +cond_syscall (sys_kevent_commit); +cond_syscall (sys_kevent_init); + +cond_syscall (sys_aio_sendfile); +/* mmu depending weak syscall entries */ cond_syscall (sys_mprotect);cond_syscall (sys_msync);
PATCH 3/10 kevent: poll/select() notifications.
poll/select() notifications.
This patch includes generic poll/select notifications. kevent_poll works simialr to epoll and has the same issues (callback is invoked not from internal state machine of the caller, but through process awake, a lot of allocations and so on).
fs/file_table.c +3 -0
@@ -20,6 +20,7 @@#include <linux/cdev.h> #include <linux/fsnotify.h> #include <linux/sysctl.h> +#include <linux/kevent.h> #include <linux/percpu_counter.h> #include <asm/atomic.h>
@@ -119,6 +120,7 @@ struct file *get_empty_filp(void) f->f_uid = tsk->fsuid; f->f_gid = tsk->fsgid;eventpoll_init_file (f); +kevent_init_file (f);/* f->f_version: 0 */ return f;
@@ -164,6 +166,7 @@ void fastcall __fput(struct file *file)* in the file cleanup chain. */ eventpoll_release (file); +kevent_cleanup_file (file);locks_remove_flock (file);if (file->f_op && file->f_op->release)
include/linux/fs.h +10 -0
@@ -280,6 +280,7 @@ extern int dir_notify_enable;#include <linux/init.h> #include <linux/pid.h> #include <linux/mutex.h> +#include <linux/kevent_storage.h> #include <asm/atomic.h> #include <asm/semaphore.h>
@@ -408,6 +409,8 @@ struct address_space_operations {int (*readpages)(struct file *filp,struct address_space *mapping,struct list_head *pages,unsigned nr_pages); +int (*aio_readpages)(struct file *filp,struct address_space *mapping, +struct list_head *pages,unsigned nr_pages,void *priv);/* * ext3 requires that a successful prepare_write() call be followed
@@ -578,6 +581,10 @@ struct inode {struct mutex inotify_mutex;/* protects the watches list */ #endif +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +struct kevent_storage st; +#endif +unsigned long i_state;unsigned long dirtied_when;/* jiffies of first dirtying */
@@ -737,6 +744,9 @@ struct file {struct list_head f_ep_links;spinlock_t f_ep_lock;#endif /* #ifdef CONFIG_EPOLL */ +#ifdef CONFIG_KEVENT_POLL +struct kevent_storage st; +#endif struct address_space *f_mapping; };extern spinlock_t files_lock;
kernel/kevent/kevent_poll.c new file +234 -0
234 lines not on this page · raw message
PATCH 4/10 kevent: Socket notifications.
Socket notifications.
This patch includes socket send/recv/accept notifications. Using trivial web server based on kevent and this features instead of epoll it's performance increased more than noticebly. More details about various benchmarks and server itself (evserver_kevent.c) can be found on project's homepage.
fs/inode.c +7 -0
@@ -21,6 +21,7 @@#include <linux/cdev.h> #include <linux/bootmem.h> #include <linux/inotify.h> +#include <linux/kevent.h> #include <linux/mount.h> /*
@@ -164,12 +165,18 @@ static struct inode *alloc_inode(struct super_block *sb) } inode->i_private =NULL ; inode->i_mapping = mapping; +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_init (inode, &inode->st); +#endif }return inode; }void destroy_inode (struct inode *inode) { +#if definedCONFIG_KEVENT_SOCKET || definedCONFIG_KEVENT_PIPE +kevent_storage_fini (&inode->st); +#endif BUG_ON (inode_has_buffers (inode));security_inode_free (inode);if (inode->i_sb->s_op->destroy_inode)
include/net/sock.h +17 -15
@@ -49,6 +49,7 @@#include <linux/skbuff.h> /* struct sk_buff */ #include <linux/mm.h> #include <linux/security.h> +#include <linux/kevent.h> #include <linux/filter.h>
@@ -451,6 +452,21 @@ static inline int sk_stream_memory_free(struct sock *sk)extern void sk_stream_rfree (struct sk_buff *skb); +struct socket_alloc { +struct socket socket; +struct inode vfs_inode; +}; + +static inline struct socket *SOCKET_I (struct inode *inode) +{ + return &container_of(inode, struct socket_alloc, vfs_inode)->socket; +} + +static inline struct inode *SOCK_INODE (struct socket *socket) +{ + return &container_of(socket, struct socket_alloc, socket)->vfs_inode; +} +static inline void sk_stream_set_owner_r (struct sk_buff *skb,struct sock *sk) { skb->sk = sk;
@@ -478,6 +494,7 @@ static inline void sk_add_backlog(struct sock *sk, struct sk_buff *skb) sk->sk_backlog.tail = skb; } skb->next =NULL ; +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); }#define sk_wait_event (__sk, __timeo, __condition) \
@@ -679,21 +696,6 @@ static inline struct kiocb *siocb_to_kiocb(struct sock_iocb *si)return si->kiocb; } -struct socket_alloc { -struct socket socket; -struct inode vfs_inode; -}; - -static inline struct socket *SOCKET_I (struct inode *inode) -{ - return &container_of(inode, struct socket_alloc, vfs_inode)->socket; -} - -static inline struct inode *SOCK_INODE (struct socket *socket) -{ - return &container_of(socket, struct socket_alloc, socket)->vfs_inode; -} -extern void __sk_stream_mem_reclaim (struct sock *sk);extern int sk_stream_mem_schedule (struct sock *sk,int size,int kind);
include/net/tcp.h +1 -0
@@ -864,6 +864,7 @@ static inline int tcp_prequeue(struct sock *sk, struct sk_buff *skb) tp->ucopy.memory =0 ; }else if (skb_queue_len (&tp->ucopy.prequeue) ==1 ) {wake_up_interruptible (sk->sk_sleep); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND );if (!inet_csk_ack_scheduled (sk)) inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, (3 * TCP_RTO_MIN) / 4,
kernel/kevent/kevent_socket.c new file +144 -0
144 lines not on this page · raw message
net/core/sock.c +9 -1
@@ -1393,6 +1393,7 @@ static void sock_def_wakeup(struct sock *sk)if (sk->sk_sleep &&waitqueue_active (sk->sk_sleep))wake_up_interruptible_all (sk->sk_sleep);read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_error_report (struct sock *sk)
@@ -1402,6 +1403,7 @@ static void sock_def_error_report(struct sock *sk)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,0 ,POLL_ERR );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_readable (struct sock *sk,int len)
@@ -1411,6 +1413,7 @@ static void sock_def_readable(struct sock *sk, int len)wake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,1 ,POLL_IN );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_write_space (struct sock *sk)
@@ -1430,6 +1433,7 @@ static void sock_def_write_space(struct sock *sk) }read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); }static void sock_def_destruct (struct sock *sk)
@@ -1480,6 +1484,8 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_state =TCP_CLOSE ; sk->sk_socket = sock; +kevent_sk_reinit (sk); +sock_set_flag (sk,SOCK_ZAPPED );if (sock)
@@ -1546,8 +1552,10 @@ void fastcall release_sock(struct sock *sk)if (sk->sk_backlog.tail)__release_sock (sk); sk->sk_lock.owner =NULL ; -if (waitqueue_active (&sk->sk_lock.wq)) +if (waitqueue_active (&sk->sk_lock.wq)) {wake_up (&sk->sk_lock.wq); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); + }spin_unlock_bh (&sk->sk_lock.slock); }EXPORT_SYMBOL (release_sock);
net/core/stream.c +1 -0
@@ -36,6 +36,7 @@ void sk_stream_write_space(struct sock *sk)wake_up_interruptible (sk->sk_sleep);if (sock->fasync_list && !(sk->sk_shutdown &SEND_SHUTDOWN ))sock_wake_async (sock,2 ,POLL_OUT ); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); } }
net/ipv4/tcp_input.c +1 -0
@@ -3127,6 +3127,7 @@ static void tcp_ofo_queue(struct sock *sk)__skb_unlink (skb, &tp->out_of_order_queue);__skb_queue_tail (&sk->sk_receive_queue, skb); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); tp->rcv_nxt =TCP_SKB_CB (skb)->end_seq;if (skb->h.th->fin)tcp_fin (skb, sk, skb->h.th);
net/ipv4/tcp_ipv4.c +2 -0
@@ -61,6 +61,7 @@#include <linux/jhash.h> #include <linux/init.h> #include <linux/times.h> +#include <linux/kevent.h> #include <net/icmp.h> #include <net/inet_hashtables.h>
@@ -1391,6 +1392,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)reqsk_free (req); }else {inet_csk_reqsk_queue_hash_add (sk, req,TCP_TIMEOUT_INIT ); +kevent_socket_notify (sk,KEVENT_SOCKET_ACCEPT ); }return 0 ;
net/socket.c +3 -0
@@ -84,6 +84,7 @@#include <linux/kmod.h> #include <linux/audit.h> #include <linux/wireless.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/unistd.h>
@@ -496,6 +497,8 @@ static struct socket *sock_alloc(void) inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; +kevent_socket_reinit (sock); +get_cpu_var (sockets_in_use)++;put_cpu_var (sockets_in_use);return sock;
net/unix/af_unix.c +21 -1
@@ -1563,8 +1563,10 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,struct scm_cookie tmp_scm;struct sock *sk = sock->sk;struct unix_sock *u =unix_sk (sk); +struct sock *other;int noblock = flags &MSG_DONTWAIT ;struct sk_buff *skb; +int err; err = -EOPNOTSUPP ;
@@ -1580,6 +1582,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, goto out_unlock;wake_up_interruptible (&u->peer_wait); + other =unix_peer_get (sk); +if (other) { +kevent_socket_notify (other,KEVENT_SOCKET_SEND ); +sock_put (other); + }else +kevent_socket_notify (sk,KEVENT_SOCKET_RECV );if (msg->msg_name)unix_copy_addr (msg, skb->sk);
@@ -1674,7 +1682,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, {struct sock_iocb *siocb =kiocb_to_siocb (iocb);struct scm_cookie tmp_scm; -struct sock *sk = sock->sk; +struct sock *sk = sock->sk, *other;struct unix_sock *u =unix_sk (sk);struct sockaddr_un *sunaddr=msg->msg_name;int copied =0 ;
@@ -1803,6 +1811,14 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, } }while (size); + other =unix_peer_get (sk); +if (other) { +kevent_socket_notify (other,KEVENT_SOCKET_SEND ); +sock_put (other); + } +if (sk->sk_shutdown &RCV_SHUTDOWN || !other) +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); +mutex_unlock (&u->readlock);scm_recv (sock, msg, siocb->scm, flags); out:
@@ -1824,6 +1840,10 @@ static int unix_shutdown(struct socket *sock, int mode)sock_hold (other);unix_state_wunlock (sk); sk->sk_state_change (sk); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); +if (other) +kevent_socket_notify (other,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV );if (other && (sk->sk_type ==SOCK_STREAM || sk->sk_type ==SOCK_SEQPACKET )) {
PATCH 5/10 kevent: Timer notifications.
Timer notifications.
Timer notifications can be used for fine grained per-process time management, since interval timers are very inconvenient to use, and they are limited.
This subsystem uses high-resolution timers.
id.raw[0] is used as number of seconds
id.raw[1] is used as number of nanoseconds
kernel/kevent/kevent_timer.c new file +114 -0
@@ -0,0 +1,114 @@ +/* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/hrtimer.h> +#include <linux/jiffies.h> +#include <linux/kevent.h> + +struct kevent_timer +{ +struct hrtimer ktimer; +struct kevent_storage ktimer_storage; +struct kevent *ktimer_event; +}; + +static int kevent_timer_func (struct hrtimer *timer) +{ + struct kevent_timer *t = container_of(timer, struct kevent_timer, ktimer); +struct kevent *k = t->ktimer_event; + +kevent_storage_ready (&t->ktimer_storage,NULL ,KEVENT_MASK_ALL ); +hrtimer_forward (timer, timer->base->softirq_time, +ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ])); +return HRTIMER_RESTART ; +} + +static struct lock_class_key kevent_timer_key; + +static int kevent_timer_enqueue (struct kevent *k) +{ +int err; +struct kevent_timer *t; + + t =kmalloc (sizeof (struct kevent_timer ),GFP_KERNEL ); +if (!t) +return -ENOMEM ; + +hrtimer_init (&t->ktimer,CLOCK_MONOTONIC ,HRTIMER_REL ); + t->ktimer.expires =ktime_set (k->event.id.raw[0 ], k->event.id.raw[1 ]); + t->ktimer.function = kevent_timer_func; + t->ktimer_event = k; + + err =kevent_storage_init (&t->ktimer, &t->ktimer_storage); +if (err) + goto err_out_free; +lockdep_set_class (&t->ktimer_storage.lock, &kevent_timer_key); + + err =kevent_storage_enqueue (&t->ktimer_storage, k); +if (err) + goto err_out_st_fini; + +hrtimer_start (&t->ktimer, t->ktimer.expires,HRTIMER_REL ); + +return 0 ; + +err_out_st_fini: +kevent_storage_fini (&t->ktimer_storage); +err_out_free: +kfree (t); + +return err; +} + +static int kevent_timer_dequeue (struct kevent *k) +{ +struct kevent_storage *st = k->st; + struct kevent_timer *t = container_of(st, struct kevent_timer, ktimer_storage); + +hrtimer_cancel (&t->ktimer); +kevent_storage_dequeue (st, k); +kfree (t); + +return 0 ; +} + +static int kevent_timer_callback (struct kevent *k) +{ + k->event.ret_data[0 ] =jiffies_to_msecs (jiffies); +return 1 ; +} + +static int __init kevent_init_timer (void ) +{ +struct kevent_callbacks tc = { + .callback = &kevent_timer_callback, + .enqueue = &kevent_timer_enqueue, + .dequeue = &kevent_timer_dequeue, + .flags =0 , + }; + +return kevent_add_callbacks (&tc,KEVENT_TIMER ); +} +module_init (kevent_init_timer); +
PATCH 6/10 kevent: Pipe notifications.
Pipe notifications.
fs/pipe.c +6 -0
@@ -16,6 +16,7 @@#include <linux/uio.h> #include <linux/highmem.h> #include <linux/pagemap.h> +#include <linux/kevent.h> #include <asm/uaccess.h> #include <asm/ioctls.h>
@@ -313,6 +314,7 @@ redo:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -322,6 +324,7 @@ redo:/* Signal writers asynchronously that there is more room. */ if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
@@ -484,6 +487,7 @@ redo2:break ; }if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible_sync (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); do_wakeup =0 ;
@@ -495,6 +499,7 @@ redo2: out:mutex_unlock (&inode->i_mutex);if (do_wakeup) { +kevent_pipe_notify (inode,KEVENT_SOCKET_RECV );wake_up_interruptible (&pipe->wait);kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN ); }
@@ -590,6 +595,7 @@ pipe_release(struct inode *inode, int decr, int decw)free_pipe_info (inode); }else {wake_up_interruptible (&pipe->wait); +kevent_pipe_notify (inode,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV );kill_fasync (&pipe->fasync_readers,SIGIO ,POLL_IN );kill_fasync (&pipe->fasync_writers,SIGIO ,POLL_OUT ); }
kernel/kevent/kevent_pipe.c new file +123 -0
123 lines not on this page · raw message
PATCH 7/10 kevent: Signal notifications.
Signal notifications.
This type of notifications allows to deliver signals through kevent queue. One can find example application signal.c on project homepage.
If KEVENT_SIGNAL_NOMASK bit is set in raw_u64 id then signal will be delivered only through queue, otherwise both delivery types are used - old through update of mask of pending signals and through queue.
If signal is delivered only through kevent queue mask of pending signals is not updated at all, which is equal to putting signal into blocked mask, but with delivery of that signal through kevent queue.
include/linux/sched.h +5 -0
@@ -82,6 +82,7 @@ struct sched_param {#include <linux/resource.h> #include <linux/timer.h> #include <linux/hrtimer.h> +#include <linux/kevent_storage.h> #include <linux/task_io_accounting.h> #include <asm/processor.h>
@@ -1048,6 +1049,10 @@ struct task_struct {#ifdef CONFIG_TASK_DELAY_ACCT struct task_delay_info *delays;#endif +#ifdef CONFIG_KEVENT_SIGNAL +struct kevent_storage st; +u32 kevent_signals; +#endif #ifdef CONFIG_FAULT_INJECTION int make_it_fail;#endif
kernel/fork.c +8 -0
@@ -49,6 +49,7 @@#include <linux/delayacct.h> #include <linux/taskstats_kern.h> #include <linux/random.h> +#include <linux/kevent.h> #include <asm/pgtable.h> #include <asm/pgalloc.h>
@@ -118,6 +119,9 @@ void __put_task_struct(struct task_struct *tsk)WARN_ON (atomic_read (&tsk->usage));WARN_ON (tsk == current); +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_fini (&tsk->st); +#endif security_task_free (tsk);free_uid (tsk->user);put_group_info (tsk->group_info);
@@ -1126,6 +1130,10 @@ static struct task_struct *copy_process(unsigned long clone_flags,if (retval) goto bad_fork_cleanup_namespaces; +#ifdef CONFIG_KEVENT_SIGNAL +kevent_storage_init (p, &p->st); +#endif + p->set_child_tid = (clone_flags &CLONE_CHILD_SETTID ) ? child_tidptr :NULL ;/* * Clear TID on mm_release()?
kernel/kevent/kevent_signal.c new file +94 -0
94 lines not on this page · raw message
kernel/signal.c +26 -0
@@ -23,6 +23,7 @@#include <linux/ptrace.h> #include <linux/signal.h> #include <linux/capability.h> +#include <linux/kevent.h> #include <linux/freezer.h> #include <linux/pid_namespace.h> #include <linux/nsproxy.h>
@@ -714,6 +715,9 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, {struct sigqueue * q =NULL ;int ret =0 ; + +if (kevent_signal_notify (t, sig)) +return 1 ;/* * fast-pathed signals for kernel-internal things like SIGSTOP
@@ -793,6 +797,17 @@ 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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif out:return ret; }
@@ -982,6 +997,17 @@ __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_KEVENT_SIGNAL +/* +* Kevent allows to deliver signals through kevent queue, +* it is possible to setup kevent to not deliver +* signal through the usual way, in that case send_signal() +* returns 1 and signal is delivered only through kevent queue. +* We simulate successfull delivery notification through this hack: +*/ +if (ret ==1 ) + ret =0 ; +#endif if (unlikely (ret))return ret;
PATCH 8/10 kevent: Kevent posix timer notifications.
Kevent posix timer notifications.
Simple extensions to POSIX timers which allows
to deliver notification of the timer expiration
through kevent queue.
Example application posix_timer.c can be found
in archive on project homepage.
include/asm-generic/siginfo.h +3 -0
@@ -235,6 +235,7 @@ typedef struct siginfo {#define SIGEV_NONE 1/* other notification: meaningless */ #define SIGEV_THREAD 2/* deliver via thread creation */ #define SIGEV_THREAD_ID 4/* deliver to thread */ +#define SIGEV_KEVENT 8/* deliver through kevent queue */ /* * This works because the alignment is ok on all current architectures
@@ -260,6 +261,8 @@ typedef struct sigevent {void (*_function)(sigval_t );void *_attribute;/* really pthread_attr_t */ } _sigev_thread; + +int kevent_fd; } _sigev_un; } sigevent_t;
include/linux/posix-timers.h +4 -0
@@ -4,6 +4,7 @@#include <linux/spinlock.h> #include <linux/list.h> #include <linux/sched.h> +#include <linux/kevent_storage.h> union cpu_time_count {cputime_t cpu;
@@ -49,6 +50,9 @@ struct k_itimer {sigval_t it_sigev_value;/* value word of sigevent struct */ struct task_struct *it_process;/* process to send signal to */ struct sigqueue *sigq;/* signal queue entry. */ +#ifdef CONFIG_KEVENT_TIMER +struct kevent_storage st; +#endif union { struct { struct hrtimer timer;
kernel/posix-timers.c +171 -48
264 lines not on this page · raw message
PATCH 9/10 kevent: Private userspace notifications.
Private userspace notifications.
Allows to register notifications of any private userspace events over kevent. Events can be marked as readt using kevent_ctl(KEVENT_READY) command.
kernel/kevent/kevent_unotify.c new file +62 -0
@@ -0,0 +1,62 @@ +/* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/kernel.h> +#include <linux/kevent.h> + +static int kevent_unotify_callback (struct kevent *k) +{ +return 1 ; +} + +int kevent_unotify_enqueue (struct kevent *k) +{ +int err; + + err =kevent_storage_enqueue (&k->user->st, k); +if (err) + goto err_out_exit; + +if (k->event.req_flags &KEVENT_REQ_ALWAYS_QUEUE ) +kevent_requeue (k); + +return 0 ; + +err_out_exit: +return err; +} + +int kevent_unotify_dequeue (struct kevent *k) +{ +kevent_storage_dequeue (k->st, k); +return 0 ; +} + +static int __init kevent_init_unotify (void ) +{ +struct kevent_callbacks sc = { + .callback = &kevent_unotify_callback, + .enqueue = &kevent_unotify_enqueue, + .dequeue = &kevent_unotify_dequeue, + .flags =0 , + }; + +return kevent_add_callbacks (&sc,KEVENT_UNOTIFY ); +} +module_init (kevent_init_unotify);
PATCH 10/10 kevent: Kevent based AIO (aio_sendfile()).
Kevent based AIO (aio_sendfile()).
aio_sendfile() contains of two major parts: AIO state machine and page processing code. The former is just a small subsystem, which allows to queue callback for theirs invocation in process' context on behalf of pool of kernel threads. It allows to queue caches of callbacks to the local thread or to any other specified. Each cache of callbacks is processed until there are callbacks in it, callbacks can requeue themselfs into the same cache.
Real work is being done in page processing code - code which populates pages into VFS cache and then sends pages to the destination socket via ->sendpage(). Unlike previous aio_sendfile() implementation, new one does not require low-level filesystem specific callbacks (->get_block()) at all, instead I extended struct address_space_operations to contain new member called ->aio_readpages(), which is exactly the same as ->readpage() (read: mpage_readpages()) except different BIO allocation and sumbission routines. I changed mpage_readpages() to provide mpage_alloc() and mpage_bio_submit() to the new function called __mpage_readpages(), which is exactly old mpage_readpages() with provided callback invocation instead of usage for old functions. mpage_readpages_aio() provides kevent specific callbacks, which calls old functions, but with different destructor callbacks, which are essentially the same, except that they reschedule AIO processing.
Benchmarks of simple sendfile vs. aio_sendfile did not show noticeble win of any approach, but I want to notice, that my receiving side is not that best in my case (I managed to create a test where usual senfile() stuck until signal received, the same hapend with aio_sendfile() too, but the latter can be buggy).
It would be good to use it in lighttpd (I will create a patch after some feedback received and approach will be considered as good.
AIO state machine is a base for network AIO (which becomes quite trivial), but I will not start implementation until roadback of kevent as a whole and AIO implementation become more clear.
fs/bio.c +1 -1
@@ -120,7 +120,7 @@ void bio_free(struct bio *bio, struct bio_set *bio_set)/* * default destructor for a bio allocated with bio_alloc_bioset() */ -static void bio_fs_destructor (struct bio *bio) +void bio_fs_destructor (struct bio *bio) {bio_free (bio, fs_bio_set); }
fs/ext3/inode.c +8 -0
@@ -1650,6 +1650,13 @@ ext3_readpages(struct file *file, struct address_space *mapping,return mpage_readpages (mapping, pages, nr_pages, ext3_get_block); } +static int +ext3_readpages_aio (struct file *file,struct address_space *mapping, +struct list_head *pages,unsigned nr_pages,void *priv) +{ +return mpage_readpages_aio (mapping, pages, nr_pages, ext3_get_block, priv); +} +static void ext3_invalidatepage (struct page *page,unsigned long offset) {journal_t *journal =EXT3_JOURNAL (page->mapping->host);
@@ -1768,6 +1775,7 @@ static int ext3_journalled_set_page_dirty(struct page *page) }static const struct address_space_operations ext3_ordered_aops = { + .aio_readpages = ext3_readpages_aio, .readpage = ext3_readpage, .readpages = ext3_readpages, .writepage = ext3_ordered_writepage,
fs/mpage.c +76 -41
188 lines not on this page · raw message
include/linux/mpage.h +2 -0
@@ -16,6 +16,8 @@ typedef int (writepage_t)(struct page *page, struct writeback_control *wbc);int mpage_readpages (struct address_space *mapping,struct list_head *pages,unsigned nr_pages,get_block_t get_block); +int mpage_readpages_aio (struct address_space *mapping,struct list_head *pages, +unsigned nr_pages,get_block_t get_block,void *priv);int mpage_readpage (struct page *page,get_block_t get_block);int mpage_writepages (struct address_space *mapping,struct writeback_control *wbc,get_block_t get_block);
kernel/kevent/kevent_aio.c new file +752 -0
752 lines not on this page · raw message