2 * Copyright (c) 2017 Gleb Smirnoff <glebius@FreeBSD.org>
3 * Copyright (c) 2002-2017 Igor Sysoev
4 * Copyright (c) 2011-2017 Nginx, Inc.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/types.h>
30 #include <sys/event.h>
41 static int kqueue_set(struct event
*, short, u_short
, u_int
);
43 static event_module_init_t kqueue_init
;
44 static event_module_fini_t kqueue_fini
;
45 static event_module_add_t kqueue_add
;
46 static event_module_del_t kqueue_del
;
47 static event_module_process_t kqueue_process
;
50 static struct kevent
*change_list
;
51 static struct kevent
*event_list
;
52 static u_int nchanges
;
54 #define MAXCHANGES 128
57 struct event_module event_module
= {
60 .process
= kqueue_process
,
73 change_list
= calloc(MAXCHANGES
, sizeof(struct kevent
));
74 event_list
= calloc(MAXEVENTS
, sizeof(struct kevent
));
75 if (change_list
== NULL
|| event_list
== NULL
)
98 kqueue_add(struct event
*ev
)
103 if (ev
->rdwr
== EVFILT_VNODE
) {
104 flags
= EV_ADD
| EV_ENABLE
| EV_CLEAR
;
105 fflags
= NOTE_DELETE
| NOTE_WRITE
| NOTE_EXTEND
;
107 flags
= EV_ADD
| EV_ENABLE
;
111 DPRINTF(E_DEBUG
, L_GENERAL
, "kqueue_add %d\n", ev
->fd
);
112 return (kqueue_set(ev
, ev
->rdwr
, flags
, fflags
));
116 kqueue_del(struct event
*ev
, int flags
)
120 * If the event is still not passed to a kernel,
121 * we will not pass it.
124 if (ev
->index
< nchanges
&&
125 change_list
[ev
->index
].udata
== ev
) {
126 if (ev
->index
< --nchanges
) {
129 ev0
= (struct event
*)change_list
[nchanges
].udata
;
130 change_list
[ev
->index
] = change_list
[nchanges
];
131 ev0
->index
= ev
->index
;
137 * when the file descriptor is closed the kqueue automatically deletes
138 * its filters so we do not need to delete explicitly the event
139 * before the closing the file descriptor.
141 if (flags
& EV_FLAG_CLOSING
)
144 DPRINTF(E_DEBUG
, L_GENERAL
, "kqueue_del %d\n", ev
->fd
);
145 return (kqueue_set(ev
, ev
->rdwr
, EV_DELETE
, 0));
149 kqueue_set(struct event
*ev
, short filter
, u_short flags
, u_int fflags
)
154 if (nchanges
>= MAXCHANGES
) {
155 DPRINTF(E_INFO
, L_GENERAL
, "kqueue change list is filled up\n");
160 if (kevent(kq
, change_list
, (int) nchanges
, NULL
, 0, &ts
) == -1) {
161 DPRINTF(E_ERROR
, L_GENERAL
,"kevent() failed: %s\n", strerror(errno
));
167 kev
= &change_list
[nchanges
];
169 kev
->filter
= filter
;
172 kev
->fflags
= fflags
;
175 ev
->index
= nchanges
++;
181 kqueue_process(struct timeval
*tv
)
190 TIMEVAL_TO_TIMESPEC(tv
, &ts
);
192 DPRINTF(E_DEBUG
, L_GENERAL
, "kevent timer: %lu.%06lu, changes: %d\n",
193 ts
.tv_sec
, ts
.tv_nsec
, n
);
195 events
= kevent(kq
, change_list
, n
, event_list
, MAXEVENTS
, &ts
);
200 DPRINTF(E_FATAL
, L_GENERAL
, "kevent(): %s. EXITING\n", strerror(errno
));
203 DPRINTF(E_DEBUG
, L_GENERAL
, "kevent events: %d\n", events
);
205 for (i
= 0; i
< events
; i
++) {
206 if (event_list
[i
].flags
& EV_ERROR
) {
207 DPRINTF(E_ERROR
, L_GENERAL
,
208 "kevent() error %d on %d filter:%d flags:0x%x\n",
209 (int)event_list
[i
].data
, (int)event_list
[i
].ident
,
210 event_list
[i
].filter
, event_list
[i
].flags
);
214 ev
= (struct event
*)event_list
[i
].udata
;
216 switch (event_list
[i
].filter
) {
222 ev
->process_vnode(ev
, event_list
[i
].fflags
);
225 DPRINTF(E_ERROR
, L_GENERAL
,
226 "unexpected kevent() filter %d",
227 event_list
[i
].filter
);