diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -1398,10 +1398,11 @@ } int -kqueue_add_filteropts(int filt, const struct filterops *filtops) +kqueue_assign_filteropts(int *filtp, struct filterops *filtops) { - int error; + int error, filt, i; + filt = *filtp; error = 0; if (filt > 0 || filt + EVFILT_SYSCOUNT < 0) { printf( @@ -1410,10 +1411,19 @@ return EINVAL; } mtx_lock(&filterops_lock); - if (sysfilt_ops[~filt].for_fop != &null_filtops && + if (filt == NO_EVFILT) { + for (i = EVFILT_USER_START; ~i < EVFILT_SYSCOUNT; i--) + if (sysfilt_ops[~i].for_fop == &null_filtops || + sysfilt_ops[~i].for_fop == NULL) + break; + if (~i == EVFILT_SYSCOUNT) + error = ENFILE; + else + filt = i; /* record the index */ + } else if (sysfilt_ops[~filt].for_fop != &null_filtops && sysfilt_ops[~filt].for_fop != NULL) error = EEXIST; - else { + if (error == 0) { sysfilt_ops[~filt].for_fop = filtops; sysfilt_ops[~filt].for_refcnt = 0; } @@ -1422,6 +1432,15 @@ return (error); } +int +kqueue_add_filteropts(int filt, struct filterops *filtops) +{ + if (filt == NO_EVFILT) + return (EINVAL); + + return kqueue_assign_filteropts(&filt, filtops); +} + int kqueue_del_filteropts(int filt) { @@ -2829,3 +2848,41 @@ fdrop(fp, td); return (error); } + +int +kevent_module_handler(struct module *mod, int what, void *arg) +{ + struct kevent_module_data *data = arg; + modspecific_t ms; + int error; + + switch (what) { + case MOD_LOAD: + if (data->offset != NO_EVFILT && + data->offset > EVFILT_USER_START) { + if (bootverbose) + printf("%s: Invalid slot %d\n", __func__, + data->offset); + return (EINVAL); + } + error = kqueue_assign_filteropts(&data->offset, data->filt_ops); + if (error) { + data->offset = NO_EVFILT; + return (error); + } + ms.intval = data->offset; + MOD_XLOCK; + module_setspecific(mod, &ms); + MOD_XUNLOCK; + return (error); + case MOD_UNLOAD: + if (data->offset == NO_EVFILT) + return (0); + error = kqueue_del_filteropts(data->offset); + return (error); + default: + break; + } + + return (EOPNOTSUPP); +} diff --git a/sys/sys/event.h b/sys/sys/event.h --- a/sys/sys/event.h +++ b/sys/sys/event.h @@ -45,7 +45,9 @@ #define EVFILT_USER (-11) /* User events */ #define EVFILT_SENDFILE (-12) /* attached to sendfile requests */ #define EVFILT_EMPTY (-13) /* empty send socket buf */ -#define EVFILT_SYSCOUNT 13 +#define EVFILT_SYSCOUNT 32 +#define NO_EVFILT (0) /* request for dynamic registration */ +#define EVFILT_USER_START (-17) /* User defined slots start */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L #define EV_SET(kevp_, a, b, c, d, e, f) do { \ @@ -322,12 +324,31 @@ size_t kevent_size; }; +struct kevent_module_data { + const char *name; /* name of kernel event */ + int offset; /* offset */ + struct filterops *filt_ops; /* defined filtops */ +}; + struct thread; struct proc; struct knlist; +struct module; struct mtx; struct rwlock; +#define KEVENT_MODULE(name, offset, new_filtops) \ + static struct kevent_module_data name##_kevent_mod = { \ + "kevent/" #name, offset, new_filtops \ + }; \ + static moduledata_t name##_mod = { \ + "kevent/" #name, \ + kevent_module_handler, \ + &name##_kevent_mod \ + }; \ + DECLARE_MODULE(name, name##_mod, SI_SUB_SYSCALLS, SI_ORDER_MIDDLE) + +int kevent_module_handler(struct module *mod, int what, void *arg); void knote(struct knlist *list, long hint, int lockflags); void knote_fork(struct knlist *list, int pid); struct knlist *knlist_alloc(struct mtx *lock); @@ -349,6 +370,7 @@ int kqfd_register(int fd, struct kevent *kev, struct thread *p, int mflag); int kqueue_add_filteropts(int filt, const struct filterops *filtops); +int kqueue_assign_filteropts(int *filtp, struct filterops *filtops); int kqueue_del_filteropts(int filt); void kqueue_drain_schedtask(void);