summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
authorTed Unangst <tedu@cvs.openbsd.org>2007-05-30 00:23:49 +0000
committerTed Unangst <tedu@cvs.openbsd.org>2007-05-30 00:23:49 +0000
commitb711ab0ec22d0d40bbb8073a083fe4b24fb490a8 (patch)
tree1a5973526b19853c1f37d913011b3c4a04c9a6ef /sys/kern
parent9e077840ddbc9ac68ff48a540b133f70b1c6ab67 (diff)
add a new kevent filter type for timers. this allows processes to create
a series of oneshot or periodic timers. capped to a global limit. from freebsd via brad. ok art pedro
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_event.c76
1 files changed, 75 insertions, 1 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index d4b1957c653..3a72a3c59d7 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_event.c,v 1.29 2007/03/30 14:21:51 reyk Exp $ */
+/* $OpenBSD: kern_event.c,v 1.30 2007/05/30 00:23:48 tedu Exp $ */
/*-
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
@@ -50,6 +50,7 @@
#include <sys/mount.h>
#include <sys/poll.h>
#include <sys/syscallargs.h>
+#include <sys/timeout.h>
int kqueue_scan(struct file *fp, int maxevents,
struct kevent *ulistp, const struct timespec *timeout,
@@ -90,6 +91,10 @@ int filt_procattach(struct knote *kn);
void filt_procdetach(struct knote *kn);
int filt_proc(struct knote *kn, long hint);
int filt_fileattach(struct knote *kn);
+void filt_timerexpire(void *knx);
+int filt_timerattach(struct knote *kn);
+void filt_timerdetach(struct knote *kn);
+int filt_timer(struct knote *kn, long hint);
struct filterops kqread_filtops =
{ 1, NULL, filt_kqdetach, filt_kqueue };
@@ -97,9 +102,13 @@ struct filterops proc_filtops =
{ 0, filt_procattach, filt_procdetach, filt_proc };
struct filterops file_filtops =
{ 1, filt_fileattach, NULL, NULL };
+struct filterops timer_filtops =
+ { 0, filt_timerattach, filt_timerdetach, filt_timer };
struct pool knote_pool;
struct pool kqueue_pool;
+int kq_ncallouts = 0;
+int kq_calloutmax = (4 * 1024);
#define KNOTE_ACTIVATE(kn) do { \
kn->kn_status |= KN_ACTIVE; \
@@ -125,6 +134,7 @@ struct filterops *sysfilt_ops[] = {
&file_filtops, /* EVFILT_VNODE */
&proc_filtops, /* EVFILT_PROC */
&sig_filtops, /* EVFILT_SIGNAL */
+ &timer_filtops, /* EVFILT_TIMER */
};
void kqueue_init(void);
@@ -284,6 +294,70 @@ filt_proc(struct knote *kn, long hint)
return (kn->kn_fflags != 0);
}
+void
+filt_timerexpire(void *knx)
+{
+ struct knote *kn = knx;
+ struct timeval tv;
+ int tticks;
+
+ kn->kn_data++;
+ KNOTE_ACTIVATE(kn);
+
+ if ((kn->kn_flags & EV_ONESHOT) == 0) {
+ tv.tv_sec = kn->kn_sdata / 1000;
+ tv.tv_usec = (kn->kn_sdata % 1000) * 1000;
+ tticks = tvtohz(&tv);
+ timeout_add((struct timeout *)kn->kn_hook, tticks);
+ }
+}
+
+
+/*
+ * data contains amount of time to sleep, in milliseconds
+ */
+int
+filt_timerattach(struct knote *kn)
+{
+ struct timeout *to;
+ struct timeval tv;
+ int tticks;
+
+ if (kq_ncallouts > kq_calloutmax)
+ return (ENOMEM);
+ kq_ncallouts++;
+
+ tv.tv_sec = kn->kn_sdata / 1000;
+ tv.tv_usec = (kn->kn_sdata % 1000) * 1000;
+ tticks = tvtohz(&tv);
+
+ kn->kn_flags |= EV_CLEAR; /* automatically set */
+ MALLOC(to, struct timeout *, sizeof(*to), M_KEVENT, 0);
+ timeout_set(to, filt_timerexpire, kn);
+ timeout_add(to, tticks);
+ kn->kn_hook = to;
+
+ return (0);
+}
+
+void
+filt_timerdetach(struct knote *kn)
+{
+ struct timeout *to;
+
+ to = (struct timeout *)kn->kn_hook;
+ timeout_del(to);
+ FREE(to, M_KEVENT);
+ kq_ncallouts--;
+}
+
+int
+filt_timer(struct knote *kn, long hint)
+{
+ return (kn->kn_data != 0);
+}
+
+
/*
* filt_seltrue:
*