1/* $OpenBSD: event.h,v 1.74 2025/05/10 09:44:39 visa Exp $ */
2
3/*-
4 * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: src/sys/sys/event.h,v 1.11 2001/02/24 01:41:31 jlemon Exp $
29 */
30
31#ifndef _SYS_EVENT_H_
32#define _SYS_EVENT_H_
33
34#define EVFILT_READ (-1)
35#define EVFILT_WRITE (-2)
36#define EVFILT_AIO (-3) /* attached to aio requests */
37#define EVFILT_VNODE (-4) /* attached to vnodes */
38#define EVFILT_PROC (-5) /* attached to struct process */
39#define EVFILT_SIGNAL (-6) /* attached to struct process */
40#define EVFILT_TIMER (-7) /* timers */
41#define EVFILT_DEVICE (-8) /* devices */
42#define EVFILT_EXCEPT (-9) /* exceptional conditions */
43#define EVFILT_USER (-10) /* user event */
44
45#define EVFILT_SYSCOUNT 10
46
47#define EV_SET(kevp, a, b, c, d, e, f) do { \
48 struct kevent *__kevp = (kevp); \
49 (__kevp)->ident = (a); \
50 (__kevp)->filter = (b); \
51 (__kevp)->flags = (c); \
52 (__kevp)->fflags = (d); \
53 (__kevp)->data = (e); \
54 (__kevp)->udata = (f); \
55} while(0)
56
57struct kevent {
58 __uintptr_t ident; /* identifier for this event */
59 short filter; /* filter for event */
60 unsigned short flags; /* action flags for kqueue */
61 unsigned int fflags; /* filter flag value */
62 __int64_t data; /* filter data value */
63 void *udata; /* opaque user data identifier */
64};
65
66/* actions */
67#define EV_ADD 0x0001 /* add event to kq (implies enable) */
68#define EV_DELETE 0x0002 /* delete event from kq */
69#define EV_ENABLE 0x0004 /* enable event */
70#define EV_DISABLE 0x0008 /* disable event (not reported) */
71
72/* flags */
73#define EV_ONESHOT 0x0010 /* only report one occurrence */
74#define EV_CLEAR 0x0020 /* clear event state after reporting */
75#define EV_RECEIPT 0x0040 /* force EV_ERROR on success, data=0 */
76#define EV_DISPATCH 0x0080 /* disable event after reporting */
77
78#define EV_SYSFLAGS 0xf800 /* reserved by system */
79#define EV_FLAG1 0x2000 /* filter-specific flag */
80
81/* returned values */
82#define EV_EOF 0x8000 /* EOF detected */
83#define EV_ERROR 0x4000 /* error, data contains errno */
84
85/*
86 * data/hint flags for EVFILT_{READ|WRITE}, shared with userspace
87 */
88#define NOTE_LOWAT 0x0001 /* low water mark */
89#define NOTE_EOF 0x0002 /* return on EOF */
90
91/*
92 * data/hint flags for EVFILT_EXCEPT, shared with userspace and with
93 * EVFILT_{READ|WRITE}
94 */
95#define NOTE_OOB 0x0004 /* OOB data on a socket */
96
97/*
98 * data/hint flags for EVFILT_VNODE, shared with userspace
99 */
100#define NOTE_DELETE 0x0001 /* vnode was removed */
101#define NOTE_WRITE 0x0002 /* data contents changed */
102#define NOTE_EXTEND 0x0004 /* size increased */
103#define NOTE_ATTRIB 0x0008 /* attributes changed */
104#define NOTE_LINK 0x0010 /* link count changed */
105#define NOTE_RENAME 0x0020 /* vnode was renamed */
106#define NOTE_REVOKE 0x0040 /* vnode access was revoked */
107#define NOTE_TRUNCATE 0x0080 /* vnode was truncated */
108
109/*
110 * data/hint flags for EVFILT_PROC, shared with userspace
111 */
112#define NOTE_EXIT 0x80000000 /* process exited */
113#define NOTE_FORK 0x40000000 /* process forked */
114#define NOTE_EXEC 0x20000000 /* process exec'd */
115#define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */
116#define NOTE_PDATAMASK 0x000fffff /* mask for pid */
117
118/* additional flags for EVFILT_PROC */
119#define NOTE_TRACK 0x00000001 /* follow across forks */
120#define NOTE_TRACKERR 0x00000002 /* could not track child */
121#define NOTE_CHILD 0x00000004 /* am a child process */
122
123/* data/hint flags for EVFILT_DEVICE, shared with userspace */
124#define NOTE_CHANGE 0x00000001 /* device change event */
125
126/* additional flags for EVFILT_TIMER */
127#define NOTE_MSECONDS 0x00000000 /* data is milliseconds */
128#define NOTE_SECONDS 0x00000001 /* data is seconds */
129#define NOTE_USECONDS 0x00000002 /* data is microseconds */
130#define NOTE_NSECONDS 0x00000003 /* data is nanoseconds */
131#define NOTE_ABSTIME 0x00000010 /* timeout is absolute */
132
133/*
134 * data/hint flags for EVFILT_USER, shared with userspace
135 */
136#define NOTE_FFNOP 0x00000000 /* ignore input fflags */
137#define NOTE_FFAND 0x40000000 /* AND fflags */
138#define NOTE_FFOR 0x80000000 /* OR fflags */
139#define NOTE_FFCOPY 0xc0000000 /* copy fflags */
140
141#define NOTE_FFCTRLMASK 0xc0000000 /* masks for operations */
142#define NOTE_FFLAGSMASK 0x00ffffff
143
144#define NOTE_TRIGGER 0x01000000 /* trigger the event */
145
146/*
147 * This is currently visible to userland to work around broken
148 * programs which pull in <sys/proc.h> or <sys/selinfo.h>.
149 */
150#include <sys/queue.h>
151
152struct klistops;
153struct knote;
154SLIST_HEAD(knlist, knote);
155
156struct klist {
157 struct knlist kl_list;
158 const struct klistops *kl_ops;
159 void *kl_arg;
160};
161
162#ifdef _KERNEL
163
164/* kernel-only flags */
165#define __EV_SELECT 0x0800 /* match behavior of select */
166#define __EV_POLL 0x1000 /* match behavior of poll */
167#define __EV_HUP EV_FLAG1 /* device or socket disconnected */
168
169#define EVFILT_MARKER 0xf /* placemarker for tailq */
170
171/*
172 * hint flag for in-kernel use - must not equal any existing note
173 */
174#define NOTE_SUBMIT 0x01000000 /* initial knote submission */
175
176#define KN_HASHSIZE 64 /* XXX should be tunable */
177
178/*
179 * Flag indicating hint is a signal. Used by EVFILT_SIGNAL, and also
180 * shared by EVFILT_PROC (all knotes attached to p->p_klist)
181 */
182#define NOTE_SIGNAL 0x08000000
183
184/*
185 * = Event filter interface
186 *
187 * == .f_flags
188 *
189 * Defines properties of the event filter:
190 *
191 * - FILTEROP_ISFD Each knote of this filter is associated
192 * with a file descriptor.
193 *
194 * - FILTEROP_MPSAFE The kqueue subsystem can invoke .f_attach(),
195 * .f_detach(), .f_modify() and .f_process() without
196 * the kernel lock.
197 *
198 * == .f_attach()
199 *
200 * Attaches the knote to the object.
201 *
202 * == .f_detach()
203 *
204 * Detaches the knote from the object. The object must not use this knote
205 * for delivering events after this callback has returned.
206 *
207 * == .f_event()
208 *
209 * Notifies the filter about an event. Called through knote().
210 *
211 * == .f_modify()
212 *
213 * Modifies the knote with new state from the user.
214 *
215 * Returns non-zero if the knote has become active.
216 *
217 * == .f_process()
218 *
219 * Checks if the event is active and returns non-zero if the event should be
220 * returned to the user.
221 *
222 * If kev is non-NULL and the event is active, the callback should store
223 * the event's state in kev for delivery to the user.
224 *
225 * == Concurrency control
226 *
227 * The kqueue subsystem serializes calls of .f_attach(), .f_detach(),
228 * .f_modify() and .f_process().
229 */
230
231#define FILTEROP_ISFD 0x00000001 /* ident == filedescriptor */
232#define FILTEROP_MPSAFE 0x00000002 /* safe without kernel lock */
233
234struct filterops {
235 int f_flags;
236 int (*f_attach)(struct knote *kn);
237 void (*f_detach)(struct knote *kn);
238 int (*f_event)(struct knote *kn, long hint);
239 int (*f_modify)(struct kevent *kev, struct knote *kn);
240 int (*f_process)(struct knote *kn, struct kevent *kev);
241};
242
243/*
244 * Locking:
245 * I immutable after creation
246 * o object lock
247 * q kn_kq->kq_lock
248 */
249struct knote {
250 SLIST_ENTRY(knote) kn_link; /* for fd */
251 SLIST_ENTRY(knote) kn_selnext; /* for struct selinfo */
252 TAILQ_ENTRY(knote) kn_tqe;
253 struct kqueue *kn_kq; /* [I] which queue we are on */
254 struct kevent kn_kevent;
255 int kn_status; /* [q] */
256 int kn_sfflags; /* [o] saved filter flags */
257 __int64_t kn_sdata; /* [o] saved data field */
258 union {
259 struct file *p_fp; /* file data pointer */
260 struct process *p_process; /* process pointer */
261 int p_useract; /* user event active */
262 } kn_ptr;
263 const struct filterops *kn_fop;
264 void *kn_hook; /* [o] */
265 unsigned int kn_pollid; /* [I] */
266
267#define KN_ACTIVE 0x0001 /* event has been triggered */
268#define KN_QUEUED 0x0002 /* event is on queue */
269#define KN_DISABLED 0x0004 /* event is disabled */
270#define KN_DETACHED 0x0008 /* knote is detached */
271#define KN_PROCESSING 0x0010 /* knote is being processed */
272#define KN_WAITING 0x0020 /* waiting on processing */
273
274#define kn_id kn_kevent.ident /* [I] */
275#define kn_filter kn_kevent.filter /* [I] */
276#define kn_flags kn_kevent.flags /* [o] */
277#define kn_fflags kn_kevent.fflags /* [o] */
278#define kn_data kn_kevent.data /* [o] */
279#define kn_udata kn_kevent.udata /* [o] */
280#define kn_fp kn_ptr.p_fp /* [o] */
281};
282
283struct klistops {
284 void (*klo_assertlk)(void *);
285 int (*klo_lock)(void *);
286 void (*klo_unlock)(void *, int);
287};
288
289struct kqueue_scan_state {
290 struct kqueue *kqs_kq; /* kqueue of this scan */
291 struct knote kqs_start; /* start marker */
292 struct knote kqs_end; /* end marker */
293 int kqs_nevent; /* number of events collected */
294 int kqs_queued; /* if set, end marker is
295 * in queue */
296};
297
298struct mutex;
299struct proc;
300struct rwlock;
301struct timespec;
302
303extern const struct filterops dead_filtops;
304
305extern void kqpoll_init(unsigned int);
306extern void kqpoll_done(unsigned int);
307extern void kqpoll_exit(void);
308extern void knote(struct klist *list, long hint);
309extern void knote_locked(struct klist *list, long hint);
310extern void knote_fdclose(struct proc *p, int fd);
311extern void knote_processexit(struct process *);
312extern void knote_processfork(struct process *, pid_t);
313extern void knote_assign(const struct kevent *, struct knote *);
314extern void knote_submit(struct knote *, struct kevent *);
315extern void kqueue_init(void);
316extern void kqueue_init_percpu(void);
317extern int kqueue_register(struct kqueue *kq, struct kevent *kev,
318 unsigned int pollid, struct proc *p);
319extern int kqueue_scan(struct kqueue_scan_state *, int, struct kevent *,
320 struct timespec *, struct proc *, int *);
321extern void kqueue_scan_setup(struct kqueue_scan_state *, struct kqueue *);
322extern void kqueue_scan_finish(struct kqueue_scan_state *);
323extern int filt_seltrue(struct knote *kn, long hint);
324extern int seltrue_kqfilter(dev_t, struct knote *);
325extern void klist_init(struct klist *, const struct klistops *, void *);
326extern void klist_init_mutex(struct klist *, struct mutex *);
327extern void klist_init_rwlock(struct klist *, struct rwlock *);
328extern void klist_free(struct klist *);
329extern void klist_insert(struct klist *, struct knote *);
330extern void klist_insert_locked(struct klist *, struct knote *);
331extern void klist_remove(struct klist *, struct knote *);
332extern void klist_remove_locked(struct klist *, struct knote *);
333extern void klist_invalidate(struct klist *);
334
335static inline int
336knote_modify_fn(const struct kevent *kev, struct knote *kn,
337 int (*f_event)(struct knote *, long))
338{
339 knote_assign(kev, kn);
340 return ((*f_event)(kn, 0));
341}
342
343static inline int
344knote_modify(const struct kevent *kev, struct knote *kn)
345{
346 return (knote_modify_fn(kev, kn, kn->kn_fop->f_event));
347}
348
349static inline int
350knote_process_fn(struct knote *kn, struct kevent *kev,
351 int (*f_event)(struct knote *, long))
352{
353 int active;
354
355 /*
356 * If called from kqueue_scan(), skip f_event
357 * when EV_ONESHOT is set, to preserve old behaviour.
358 */
359 if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
360 active = 1;
361 else
362 active = (*f_event)(kn, 0);
363 if (active)
364 knote_submit(kn, kev);
365 return (active);
366}
367
368static inline int
369knote_process(struct knote *kn, struct kevent *kev)
370{
371 return (knote_process_fn(kn, kev, kn->kn_fop->f_event));
372}
373
374static inline int
375klist_empty(struct klist *klist)
376{
377 return (SLIST_EMPTY(&klist->kl_list));
378}
379
380#else /* !_KERNEL */
381
382#include <sys/cdefs.h>
383struct timespec;
384
385__BEGIN_DECLS
386int kqueue(void);
387int kqueue1(int flags);
388int kevent(int kq, const struct kevent *changelist, int nchanges,
389 struct kevent *eventlist, int nevents,
390 const struct timespec *timeout);
391__END_DECLS
392
393#endif /* !_KERNEL */
394
395#endif /* !_SYS_EVENT_H_ */