1/*
2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#ifndef  _KQUEUE_PRIVATE_H
18#define  _KQUEUE_PRIVATE_H
19
20#if defined (__SVR4) && defined (__sun)
21# define SOLARIS
22# include <port.h>
23  /* Used to set portev_events for PORT_SOURCE_USER */
24# define X_PORT_SOURCE_SIGNAL  101
25# define X_PORT_SOURCE_USER    102
26#endif
27
28#include <errno.h>
29#include <pthread.h>
30#include <stdbool.h>
31#include <stdio.h>
32#include <string.h>
33#include <sys/select.h>
34#include "../../include/sys/event.h"
35
36#include "tree.h"
37
38/* GCC atomic builtins.
39 * See: http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
40 */
41#ifdef __sun
42# include <atomic.h>
43# define atomic_inc      atomic_inc_32
44# define atomic_dec      atomic_dec_32
45#else
46# define atomic_inc(p)   __sync_add_and_fetch((p), 1)
47# define atomic_dec(p)   __sync_sub_and_fetch((p), 1)
48#endif
49
50/* Maximum events returnable in a single kevent() call */
51#define MAX_KEVENT  512
52
53
54#ifndef NDEBUG
55
56extern int KQUEUE_DEBUG;
57
58#define dbg_puts(str)           do {                                \
59    if (KQUEUE_DEBUG)                                               \
60      fprintf(stderr, "KQ: %s(): %s\n", __func__,str);              \
61} while (0)
62
63#define dbg_printf(fmt,...)     do {                                \
64    if (KQUEUE_DEBUG)                                               \
65      fprintf(stderr, "KQ: %s(): "fmt"\n", __func__,__VA_ARGS__);   \
66} while (0)
67
68#define dbg_perror(str)         do {                                \
69    if (KQUEUE_DEBUG)                                               \
70      fprintf(stderr, "KQ: %s(): %s: %s (errno=%d)\n",              \
71              __func__, str, strerror(errno), errno);               \
72} while (0)
73
74# define reset_errno()          do { errno = 0; } while (0)
75
76#else /* NDEBUG */
77# define dbg_puts(str)           ;
78# define dbg_printf(fmt,...)     ;
79# define dbg_perror(str)         ;
80# define reset_errno()           ;
81#endif
82
83
84struct kqueue;
85struct kevent;
86struct evfilt_data;
87
88/*
89 * Flags used by knote->flags
90 */
91#define KNFL_PASSIVE_SOCKET  (0x01)  /* Socket is in listen(2) mode */
92
93/* TODO: Make this a variable length structure and allow
94   each filter to add custom fields at the end.
95 */
96struct knote {
97    struct kevent     kev;
98    int               flags;
99    union {
100        int           pfd;       /* Used by timerfd */
101        int           events;    /* Used by socket */
102        struct {
103            nlink_t   nlink;  /* Used by vnode */
104            off_t     size;   /* Used by vnode */
105        } vnode;
106        timer_t       timerid;
107        pthread_t     tid;          /* Used by posix/timer.c */
108    } data;
109    TAILQ_ENTRY(knote) event_ent;    /* Used by filter->kf_event */
110    RB_ENTRY(knote)   kntree_ent;   /* Used by filter->kntree */
111};
112LIST_HEAD(knotelist, knote);
113
114#define KNOTE_ENABLE(ent)           do {                            \
115            (ent)->kev.flags &= ~EV_DISABLE;                        \
116} while (0/*CONSTCOND*/)
117
118#define KNOTE_DISABLE(ent)          do {                            \
119            (ent)->kev.flags |=  EV_DISABLE;                        \
120} while (0/*CONSTCOND*/)
121
122struct filter {
123    short     kf_id;
124
125    /* filter operations */
126
127    int     (*kf_init)(struct filter *);
128    void    (*kf_destroy)(struct filter *);
129    int     (*kf_copyout)(struct filter *, struct kevent *, int);
130
131    /* knote operations */
132
133    int     (*kn_create)(struct filter *, struct knote *);
134    int     (*kn_modify)(struct filter *, struct knote *,
135                            const struct kevent *);
136    int     (*kn_delete)(struct filter *, struct knote *);
137    int     (*kn_enable)(struct filter *, struct knote *);
138    int     (*kn_disable)(struct filter *, struct knote *);
139
140    struct eventfd *kf_efd;             /* Used by user.c */
141    int       kf_pfd;                   /* fd to poll(2) for readiness */
142    int       kf_wfd;                   /* fd to write when an event occurs */
143    sigset_t            kf_sigmask;
144    struct evfilt_data *kf_data;	    /* filter-specific data */
145    RB_HEAD(knt, knote) kf_knote;
146    TAILQ_HEAD(, knote) kf_event;       /* events that have occurred */
147    struct kqueue      *kf_kqueue;
148};
149
150/* Use this to declare a filter that is not implemented */
151#define EVFILT_NOTIMPL { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
152
153struct kqueue {
154    int             kq_sockfd[2];
155    struct filter   kq_filt[EVFILT_SYSCOUNT];
156    fd_set          kq_fds, kq_rfds;
157    int             kq_nfds;
158    pthread_mutex_t kq_mtx;
159#ifdef __sun__
160    int             kq_port;            /* see: port_create(2) */
161    pthread_key_t   kq_port_event;
162#endif
163    volatile uint32_t        kq_ref;
164    RB_ENTRY(kqueue) entries;
165};
166
167struct knote *  knote_lookup(struct filter *, uintptr_t);
168struct knote *  knote_lookup_data(struct filter *filt, intptr_t);
169struct knote *  knote_new(void);
170void        knote_free(struct filter *, struct knote *);
171void        knote_free_all(struct filter *);
172void        knote_insert(struct filter *, struct knote *);
173int         knote_get_socket_type(struct knote *);
174
175/* TODO: these deal with the eventlist, should use a different prefix */
176void        knote_enqueue(struct filter *, struct knote *);
177struct knote *  knote_dequeue(struct filter *);
178int         knote_events_pending(struct filter *);
179
180struct eventfd * eventfd_create(void);
181void        eventfd_free(struct eventfd *);
182int         eventfd_raise(struct eventfd *);
183int         eventfd_lower(struct eventfd *);
184int         eventfd_reader(struct eventfd *);
185int         eventfd_writer(struct eventfd *);
186
187int         filter_lookup(struct filter **, struct kqueue *, short);
188int         filter_socketpair(struct filter *);
189int      	filter_register_all(struct kqueue *);
190void     	filter_unregister_all(struct kqueue *);
191const char *filter_name(short);
192int         filter_lower(struct filter *);
193int         filter_raise(struct filter *);
194
195int         kevent_wait(struct kqueue *, const struct timespec *);
196int         kevent_copyout(struct kqueue *, int, struct kevent *, int);
197void 		kevent_free(struct kqueue *);
198const char *kevent_dump(const struct kevent *);
199
200struct kqueue * kqueue_get(int);
201void        kqueue_put(struct kqueue *);
202#define     kqueue_lock(kq)     pthread_mutex_lock(&(kq)->kq_mtx)
203#define     kqueue_unlock(kq)   pthread_mutex_unlock(&(kq)->kq_mtx)
204int         kqueue_validate(struct kqueue *);
205
206#endif  /* ! _KQUEUE_PRIVATE_H */
207