380 lines
12 KiB
C
380 lines
12 KiB
C
/* $OpenBSD: event.h,v 1.73 2024/08/06 08:44:54 claudio Exp $ */
|
|
|
|
/*-
|
|
* Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
* SUCH DAMAGE.
|
|
*
|
|
* $FreeBSD: src/sys/sys/event.h,v 1.11 2001/02/24 01:41:31 jlemon Exp $
|
|
*/
|
|
|
|
#ifndef _SYS_EVENT_H_
|
|
#define _SYS_EVENT_H_
|
|
|
|
#define EVFILT_READ (-1)
|
|
#define EVFILT_WRITE (-2)
|
|
#define EVFILT_AIO (-3) /* attached to aio requests */
|
|
#define EVFILT_VNODE (-4) /* attached to vnodes */
|
|
#define EVFILT_PROC (-5) /* attached to struct process */
|
|
#define EVFILT_SIGNAL (-6) /* attached to struct process */
|
|
#define EVFILT_TIMER (-7) /* timers */
|
|
#define EVFILT_DEVICE (-8) /* devices */
|
|
#define EVFILT_EXCEPT (-9) /* exceptional conditions */
|
|
|
|
#define EVFILT_SYSCOUNT 9
|
|
|
|
#define EV_SET(kevp, a, b, c, d, e, f) do { \
|
|
struct kevent *__kevp = (kevp); \
|
|
(__kevp)->ident = (a); \
|
|
(__kevp)->filter = (b); \
|
|
(__kevp)->flags = (c); \
|
|
(__kevp)->fflags = (d); \
|
|
(__kevp)->data = (e); \
|
|
(__kevp)->udata = (f); \
|
|
} while(0)
|
|
|
|
struct kevent {
|
|
__uintptr_t ident; /* identifier for this event */
|
|
short filter; /* filter for event */
|
|
unsigned short flags; /* action flags for kqueue */
|
|
unsigned int fflags; /* filter flag value */
|
|
__int64_t data; /* filter data value */
|
|
void *udata; /* opaque user data identifier */
|
|
};
|
|
|
|
/* actions */
|
|
#define EV_ADD 0x0001 /* add event to kq (implies enable) */
|
|
#define EV_DELETE 0x0002 /* delete event from kq */
|
|
#define EV_ENABLE 0x0004 /* enable event */
|
|
#define EV_DISABLE 0x0008 /* disable event (not reported) */
|
|
|
|
/* flags */
|
|
#define EV_ONESHOT 0x0010 /* only report one occurrence */
|
|
#define EV_CLEAR 0x0020 /* clear event state after reporting */
|
|
#define EV_RECEIPT 0x0040 /* force EV_ERROR on success, data=0 */
|
|
#define EV_DISPATCH 0x0080 /* disable event after reporting */
|
|
|
|
#define EV_SYSFLAGS 0xf800 /* reserved by system */
|
|
#define EV_FLAG1 0x2000 /* filter-specific flag */
|
|
|
|
/* returned values */
|
|
#define EV_EOF 0x8000 /* EOF detected */
|
|
#define EV_ERROR 0x4000 /* error, data contains errno */
|
|
|
|
/*
|
|
* data/hint flags for EVFILT_{READ|WRITE}, shared with userspace
|
|
*/
|
|
#define NOTE_LOWAT 0x0001 /* low water mark */
|
|
#define NOTE_EOF 0x0002 /* return on EOF */
|
|
|
|
/*
|
|
* data/hint flags for EVFILT_EXCEPT, shared with userspace and with
|
|
* EVFILT_{READ|WRITE}
|
|
*/
|
|
#define NOTE_OOB 0x0004 /* OOB data on a socket */
|
|
|
|
/*
|
|
* data/hint flags for EVFILT_VNODE, shared with userspace
|
|
*/
|
|
#define NOTE_DELETE 0x0001 /* vnode was removed */
|
|
#define NOTE_WRITE 0x0002 /* data contents changed */
|
|
#define NOTE_EXTEND 0x0004 /* size increased */
|
|
#define NOTE_ATTRIB 0x0008 /* attributes changed */
|
|
#define NOTE_LINK 0x0010 /* link count changed */
|
|
#define NOTE_RENAME 0x0020 /* vnode was renamed */
|
|
#define NOTE_REVOKE 0x0040 /* vnode access was revoked */
|
|
#define NOTE_TRUNCATE 0x0080 /* vnode was truncated */
|
|
|
|
/*
|
|
* data/hint flags for EVFILT_PROC, shared with userspace
|
|
*/
|
|
#define NOTE_EXIT 0x80000000 /* process exited */
|
|
#define NOTE_FORK 0x40000000 /* process forked */
|
|
#define NOTE_EXEC 0x20000000 /* process exec'd */
|
|
#define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */
|
|
#define NOTE_PDATAMASK 0x000fffff /* mask for pid */
|
|
|
|
/* additional flags for EVFILT_PROC */
|
|
#define NOTE_TRACK 0x00000001 /* follow across forks */
|
|
#define NOTE_TRACKERR 0x00000002 /* could not track child */
|
|
#define NOTE_CHILD 0x00000004 /* am a child process */
|
|
|
|
/* data/hint flags for EVFILT_DEVICE, shared with userspace */
|
|
#define NOTE_CHANGE 0x00000001 /* device change event */
|
|
|
|
/* additional flags for EVFILT_TIMER */
|
|
#define NOTE_MSECONDS 0x00000000 /* data is milliseconds */
|
|
#define NOTE_SECONDS 0x00000001 /* data is seconds */
|
|
#define NOTE_USECONDS 0x00000002 /* data is microseconds */
|
|
#define NOTE_NSECONDS 0x00000003 /* data is nanoseconds */
|
|
#define NOTE_ABSTIME 0x00000010 /* timeout is absolute */
|
|
|
|
/*
|
|
* This is currently visible to userland to work around broken
|
|
* programs which pull in <sys/proc.h> or <sys/selinfo.h>.
|
|
*/
|
|
#include <sys/queue.h>
|
|
|
|
struct klistops;
|
|
struct knote;
|
|
SLIST_HEAD(knlist, knote);
|
|
|
|
struct klist {
|
|
struct knlist kl_list;
|
|
const struct klistops *kl_ops;
|
|
void *kl_arg;
|
|
};
|
|
|
|
#ifdef _KERNEL
|
|
|
|
/* kernel-only flags */
|
|
#define __EV_SELECT 0x0800 /* match behavior of select */
|
|
#define __EV_POLL 0x1000 /* match behavior of poll */
|
|
#define __EV_HUP EV_FLAG1 /* device or socket disconnected */
|
|
|
|
#define EVFILT_MARKER 0xf /* placemarker for tailq */
|
|
|
|
/*
|
|
* hint flag for in-kernel use - must not equal any existing note
|
|
*/
|
|
#define NOTE_SUBMIT 0x01000000 /* initial knote submission */
|
|
|
|
#define KN_HASHSIZE 64 /* XXX should be tunable */
|
|
|
|
/*
|
|
* Flag indicating hint is a signal. Used by EVFILT_SIGNAL, and also
|
|
* shared by EVFILT_PROC (all knotes attached to p->p_klist)
|
|
*/
|
|
#define NOTE_SIGNAL 0x08000000
|
|
|
|
/*
|
|
* = Event filter interface
|
|
*
|
|
* == .f_flags
|
|
*
|
|
* Defines properties of the event filter:
|
|
*
|
|
* - FILTEROP_ISFD Each knote of this filter is associated
|
|
* with a file descriptor.
|
|
*
|
|
* - FILTEROP_MPSAFE The kqueue subsystem can invoke .f_attach(),
|
|
* .f_detach(), .f_modify() and .f_process() without
|
|
* the kernel lock.
|
|
*
|
|
* == .f_attach()
|
|
*
|
|
* Attaches the knote to the object.
|
|
*
|
|
* == .f_detach()
|
|
*
|
|
* Detaches the knote from the object. The object must not use this knote
|
|
* for delivering events after this callback has returned.
|
|
*
|
|
* == .f_event()
|
|
*
|
|
* Notifies the filter about an event. Called through knote().
|
|
*
|
|
* == .f_modify()
|
|
*
|
|
* Modifies the knote with new state from the user.
|
|
*
|
|
* Returns non-zero if the knote has become active.
|
|
*
|
|
* == .f_process()
|
|
*
|
|
* Checks if the event is active and returns non-zero if the event should be
|
|
* returned to the user.
|
|
*
|
|
* If kev is non-NULL and the event is active, the callback should store
|
|
* the event's state in kev for delivery to the user.
|
|
*
|
|
* == Concurrency control
|
|
*
|
|
* The kqueue subsystem serializes calls of .f_attach(), .f_detach(),
|
|
* .f_modify() and .f_process().
|
|
*/
|
|
|
|
#define FILTEROP_ISFD 0x00000001 /* ident == filedescriptor */
|
|
#define FILTEROP_MPSAFE 0x00000002 /* safe without kernel lock */
|
|
|
|
struct filterops {
|
|
int f_flags;
|
|
int (*f_attach)(struct knote *kn);
|
|
void (*f_detach)(struct knote *kn);
|
|
int (*f_event)(struct knote *kn, long hint);
|
|
int (*f_modify)(struct kevent *kev, struct knote *kn);
|
|
int (*f_process)(struct knote *kn, struct kevent *kev);
|
|
};
|
|
|
|
/*
|
|
* Locking:
|
|
* I immutable after creation
|
|
* o object lock
|
|
* q kn_kq->kq_lock
|
|
*/
|
|
struct knote {
|
|
SLIST_ENTRY(knote) kn_link; /* for fd */
|
|
SLIST_ENTRY(knote) kn_selnext; /* for struct selinfo */
|
|
TAILQ_ENTRY(knote) kn_tqe;
|
|
struct kqueue *kn_kq; /* [I] which queue we are on */
|
|
struct kevent kn_kevent;
|
|
int kn_status; /* [q] */
|
|
int kn_sfflags; /* [o] saved filter flags */
|
|
__int64_t kn_sdata; /* [o] saved data field */
|
|
union {
|
|
struct file *p_fp; /* file data pointer */
|
|
struct process *p_process; /* process pointer */
|
|
} kn_ptr;
|
|
const struct filterops *kn_fop;
|
|
void *kn_hook; /* [o] */
|
|
unsigned int kn_pollid; /* [I] */
|
|
|
|
#define KN_ACTIVE 0x0001 /* event has been triggered */
|
|
#define KN_QUEUED 0x0002 /* event is on queue */
|
|
#define KN_DISABLED 0x0004 /* event is disabled */
|
|
#define KN_DETACHED 0x0008 /* knote is detached */
|
|
#define KN_PROCESSING 0x0010 /* knote is being processed */
|
|
#define KN_WAITING 0x0020 /* waiting on processing */
|
|
|
|
#define kn_id kn_kevent.ident /* [I] */
|
|
#define kn_filter kn_kevent.filter /* [I] */
|
|
#define kn_flags kn_kevent.flags /* [o] */
|
|
#define kn_fflags kn_kevent.fflags /* [o] */
|
|
#define kn_data kn_kevent.data /* [o] */
|
|
#define kn_udata kn_kevent.udata /* [o] */
|
|
#define kn_fp kn_ptr.p_fp /* [o] */
|
|
};
|
|
|
|
struct klistops {
|
|
void (*klo_assertlk)(void *);
|
|
int (*klo_lock)(void *);
|
|
void (*klo_unlock)(void *, int);
|
|
};
|
|
|
|
struct kqueue_scan_state {
|
|
struct kqueue *kqs_kq; /* kqueue of this scan */
|
|
struct knote kqs_start; /* start marker */
|
|
struct knote kqs_end; /* end marker */
|
|
int kqs_nevent; /* number of events collected */
|
|
int kqs_queued; /* if set, end marker is
|
|
* in queue */
|
|
};
|
|
|
|
struct mutex;
|
|
struct proc;
|
|
struct rwlock;
|
|
struct timespec;
|
|
|
|
extern const struct filterops dead_filtops;
|
|
|
|
extern void kqpoll_init(unsigned int);
|
|
extern void kqpoll_done(unsigned int);
|
|
extern void kqpoll_exit(void);
|
|
extern void knote(struct klist *list, long hint);
|
|
extern void knote_locked(struct klist *list, long hint);
|
|
extern void knote_fdclose(struct proc *p, int fd);
|
|
extern void knote_processexit(struct process *);
|
|
extern void knote_processfork(struct process *, pid_t);
|
|
extern void knote_assign(const struct kevent *, struct knote *);
|
|
extern void knote_submit(struct knote *, struct kevent *);
|
|
extern void kqueue_init(void);
|
|
extern void kqueue_init_percpu(void);
|
|
extern int kqueue_register(struct kqueue *kq, struct kevent *kev,
|
|
unsigned int pollid, struct proc *p);
|
|
extern int kqueue_scan(struct kqueue_scan_state *, int, struct kevent *,
|
|
struct timespec *, struct proc *, int *);
|
|
extern void kqueue_scan_setup(struct kqueue_scan_state *, struct kqueue *);
|
|
extern void kqueue_scan_finish(struct kqueue_scan_state *);
|
|
extern int filt_seltrue(struct knote *kn, long hint);
|
|
extern int seltrue_kqfilter(dev_t, struct knote *);
|
|
extern void klist_init(struct klist *, const struct klistops *, void *);
|
|
extern void klist_init_mutex(struct klist *, struct mutex *);
|
|
extern void klist_init_rwlock(struct klist *, struct rwlock *);
|
|
extern void klist_free(struct klist *);
|
|
extern void klist_insert(struct klist *, struct knote *);
|
|
extern void klist_insert_locked(struct klist *, struct knote *);
|
|
extern void klist_remove(struct klist *, struct knote *);
|
|
extern void klist_remove_locked(struct klist *, struct knote *);
|
|
extern void klist_invalidate(struct klist *);
|
|
|
|
static inline int
|
|
knote_modify_fn(const struct kevent *kev, struct knote *kn,
|
|
int (*f_event)(struct knote *, long))
|
|
{
|
|
knote_assign(kev, kn);
|
|
return ((*f_event)(kn, 0));
|
|
}
|
|
|
|
static inline int
|
|
knote_modify(const struct kevent *kev, struct knote *kn)
|
|
{
|
|
return (knote_modify_fn(kev, kn, kn->kn_fop->f_event));
|
|
}
|
|
|
|
static inline int
|
|
knote_process_fn(struct knote *kn, struct kevent *kev,
|
|
int (*f_event)(struct knote *, long))
|
|
{
|
|
int active;
|
|
|
|
/*
|
|
* If called from kqueue_scan(), skip f_event
|
|
* when EV_ONESHOT is set, to preserve old behaviour.
|
|
*/
|
|
if (kev != NULL && (kn->kn_flags & EV_ONESHOT))
|
|
active = 1;
|
|
else
|
|
active = (*f_event)(kn, 0);
|
|
if (active)
|
|
knote_submit(kn, kev);
|
|
return (active);
|
|
}
|
|
|
|
static inline int
|
|
knote_process(struct knote *kn, struct kevent *kev)
|
|
{
|
|
return (knote_process_fn(kn, kev, kn->kn_fop->f_event));
|
|
}
|
|
|
|
static inline int
|
|
klist_empty(struct klist *klist)
|
|
{
|
|
return (SLIST_EMPTY(&klist->kl_list));
|
|
}
|
|
|
|
#else /* !_KERNEL */
|
|
|
|
#include <sys/cdefs.h>
|
|
struct timespec;
|
|
|
|
__BEGIN_DECLS
|
|
int kqueue(void);
|
|
int kqueue1(int flags);
|
|
int kevent(int kq, const struct kevent *changelist, int nchanges,
|
|
struct kevent *eventlist, int nevents,
|
|
const struct timespec *timeout);
|
|
__END_DECLS
|
|
|
|
#endif /* !_KERNEL */
|
|
|
|
#endif /* !_SYS_EVENT_H_ */
|