Line data Source code
1 : /* $OpenBSD: kern_event.c,v 1.99 2018/09/04 02:38:25 cheloha 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/kern/kern_event.c,v 1.22 2001/02/23 20:32:42 jlemon Exp $
29 : */
30 :
31 : #include <sys/param.h>
32 : #include <sys/systm.h>
33 : #include <sys/kernel.h>
34 : #include <sys/proc.h>
35 : #include <sys/pledge.h>
36 : #include <sys/malloc.h>
37 : #include <sys/unistd.h>
38 : #include <sys/file.h>
39 : #include <sys/filedesc.h>
40 : #include <sys/fcntl.h>
41 : #include <sys/selinfo.h>
42 : #include <sys/queue.h>
43 : #include <sys/event.h>
44 : #include <sys/eventvar.h>
45 : #include <sys/ktrace.h>
46 : #include <sys/pool.h>
47 : #include <sys/protosw.h>
48 : #include <sys/socket.h>
49 : #include <sys/socketvar.h>
50 : #include <sys/stat.h>
51 : #include <sys/uio.h>
52 : #include <sys/mount.h>
53 : #include <sys/poll.h>
54 : #include <sys/syscallargs.h>
55 : #include <sys/timeout.h>
56 :
57 : int kqueue_scan(struct kqueue *kq, int maxevents,
58 : struct kevent *ulistp, const struct timespec *timeout,
59 : struct proc *p, int *retval);
60 :
61 : int kqueue_read(struct file *, struct uio *, int);
62 : int kqueue_write(struct file *, struct uio *, int);
63 : int kqueue_ioctl(struct file *fp, u_long com, caddr_t data,
64 : struct proc *p);
65 : int kqueue_poll(struct file *fp, int events, struct proc *p);
66 : int kqueue_kqfilter(struct file *fp, struct knote *kn);
67 : int kqueue_stat(struct file *fp, struct stat *st, struct proc *p);
68 : int kqueue_close(struct file *fp, struct proc *p);
69 : void kqueue_wakeup(struct kqueue *kq);
70 :
71 : struct fileops kqueueops = {
72 : .fo_read = kqueue_read,
73 : .fo_write = kqueue_write,
74 : .fo_ioctl = kqueue_ioctl,
75 : .fo_poll = kqueue_poll,
76 : .fo_kqfilter = kqueue_kqfilter,
77 : .fo_stat = kqueue_stat,
78 : .fo_close = kqueue_close
79 : };
80 :
81 : void knote_attach(struct knote *kn);
82 : void knote_drop(struct knote *kn, struct proc *p);
83 : void knote_enqueue(struct knote *kn);
84 : void knote_dequeue(struct knote *kn);
85 : #define knote_alloc() ((struct knote *)pool_get(&knote_pool, PR_WAITOK))
86 : #define knote_free(kn) pool_put(&knote_pool, (kn))
87 :
88 : void filt_kqdetach(struct knote *kn);
89 : int filt_kqueue(struct knote *kn, long hint);
90 : int filt_procattach(struct knote *kn);
91 : void filt_procdetach(struct knote *kn);
92 : int filt_proc(struct knote *kn, long hint);
93 : int filt_fileattach(struct knote *kn);
94 : void filt_timerexpire(void *knx);
95 : int filt_timerattach(struct knote *kn);
96 : void filt_timerdetach(struct knote *kn);
97 : int filt_timer(struct knote *kn, long hint);
98 : void filt_seltruedetach(struct knote *kn);
99 :
100 : struct filterops kqread_filtops =
101 : { 1, NULL, filt_kqdetach, filt_kqueue };
102 : struct filterops proc_filtops =
103 : { 0, filt_procattach, filt_procdetach, filt_proc };
104 : struct filterops file_filtops =
105 : { 1, filt_fileattach, NULL, NULL };
106 : struct filterops timer_filtops =
107 : { 0, filt_timerattach, filt_timerdetach, filt_timer };
108 :
109 : struct pool knote_pool;
110 : struct pool kqueue_pool;
111 : int kq_ntimeouts = 0;
112 : int kq_timeoutmax = (4 * 1024);
113 :
114 : #define KNOTE_ACTIVATE(kn) do { \
115 : kn->kn_status |= KN_ACTIVE; \
116 : if ((kn->kn_status & (KN_QUEUED | KN_DISABLED)) == 0) \
117 : knote_enqueue(kn); \
118 : } while(0)
119 :
120 : #define KN_HASH(val, mask) (((val) ^ (val >> 8)) & (mask))
121 :
122 : extern struct filterops sig_filtops;
123 : #ifdef notyet
124 : extern struct filterops aio_filtops;
125 : #endif
126 :
127 : /*
128 : * Table for for all system-defined filters.
129 : */
130 : struct filterops *sysfilt_ops[] = {
131 : &file_filtops, /* EVFILT_READ */
132 : &file_filtops, /* EVFILT_WRITE */
133 : NULL, /*&aio_filtops,*/ /* EVFILT_AIO */
134 : &file_filtops, /* EVFILT_VNODE */
135 : &proc_filtops, /* EVFILT_PROC */
136 : &sig_filtops, /* EVFILT_SIGNAL */
137 : &timer_filtops, /* EVFILT_TIMER */
138 : &file_filtops, /* EVFILT_DEVICE */
139 : };
140 :
141 : void KQREF(struct kqueue *);
142 : void KQRELE(struct kqueue *);
143 :
144 : void
145 0 : KQREF(struct kqueue *kq)
146 : {
147 0 : ++kq->kq_refs;
148 0 : }
149 :
150 : void
151 0 : KQRELE(struct kqueue *kq)
152 : {
153 0 : if (--kq->kq_refs > 0)
154 : return;
155 :
156 0 : LIST_REMOVE(kq, kq_next);
157 0 : free(kq->kq_knlist, M_TEMP, kq->kq_knlistsize * sizeof(struct klist));
158 0 : hashfree(kq->kq_knhash, KN_HASHSIZE, M_TEMP);
159 0 : pool_put(&kqueue_pool, kq);
160 0 : }
161 :
162 : void kqueue_init(void);
163 :
164 : void
165 0 : kqueue_init(void)
166 : {
167 :
168 0 : pool_init(&kqueue_pool, sizeof(struct kqueue), 0, IPL_NONE, PR_WAITOK,
169 : "kqueuepl", NULL);
170 0 : pool_init(&knote_pool, sizeof(struct knote), 0, IPL_NONE, PR_WAITOK,
171 : "knotepl", NULL);
172 0 : }
173 :
174 : int
175 0 : filt_fileattach(struct knote *kn)
176 : {
177 0 : struct file *fp = kn->kn_fp;
178 :
179 0 : return fp->f_ops->fo_kqfilter(fp, kn);
180 : }
181 :
182 : int
183 0 : kqueue_kqfilter(struct file *fp, struct knote *kn)
184 : {
185 0 : struct kqueue *kq = kn->kn_fp->f_data;
186 :
187 0 : if (kn->kn_filter != EVFILT_READ)
188 0 : return (EINVAL);
189 :
190 0 : kn->kn_fop = &kqread_filtops;
191 0 : SLIST_INSERT_HEAD(&kq->kq_sel.si_note, kn, kn_selnext);
192 0 : return (0);
193 0 : }
194 :
195 : void
196 0 : filt_kqdetach(struct knote *kn)
197 : {
198 0 : struct kqueue *kq = kn->kn_fp->f_data;
199 :
200 0 : SLIST_REMOVE(&kq->kq_sel.si_note, kn, knote, kn_selnext);
201 0 : }
202 :
203 : int
204 0 : filt_kqueue(struct knote *kn, long hint)
205 : {
206 0 : struct kqueue *kq = kn->kn_fp->f_data;
207 :
208 0 : kn->kn_data = kq->kq_count;
209 0 : return (kn->kn_data > 0);
210 : }
211 :
212 : int
213 0 : filt_procattach(struct knote *kn)
214 : {
215 : struct process *pr;
216 :
217 0 : if ((curproc->p_p->ps_flags & PS_PLEDGE) &&
218 0 : (curproc->p_p->ps_pledge & PLEDGE_PROC) == 0)
219 0 : return pledge_fail(curproc, EPERM, PLEDGE_PROC);
220 :
221 0 : if (kn->kn_id > PID_MAX)
222 0 : return ESRCH;
223 :
224 0 : pr = prfind(kn->kn_id);
225 0 : if (pr == NULL)
226 0 : return (ESRCH);
227 :
228 : /* exiting processes can't be specified */
229 0 : if (pr->ps_flags & PS_EXITING)
230 0 : return (ESRCH);
231 :
232 0 : kn->kn_ptr.p_process = pr;
233 0 : kn->kn_flags |= EV_CLEAR; /* automatically set */
234 :
235 : /*
236 : * internal flag indicating registration done by kernel
237 : */
238 0 : if (kn->kn_flags & EV_FLAG1) {
239 0 : kn->kn_data = kn->kn_sdata; /* ppid */
240 0 : kn->kn_fflags = NOTE_CHILD;
241 0 : kn->kn_flags &= ~EV_FLAG1;
242 0 : }
243 :
244 : /* XXX lock the proc here while adding to the list? */
245 0 : SLIST_INSERT_HEAD(&pr->ps_klist, kn, kn_selnext);
246 :
247 0 : return (0);
248 0 : }
249 :
250 : /*
251 : * The knote may be attached to a different process, which may exit,
252 : * leaving nothing for the knote to be attached to. So when the process
253 : * exits, the knote is marked as DETACHED and also flagged as ONESHOT so
254 : * it will be deleted when read out. However, as part of the knote deletion,
255 : * this routine is called, so a check is needed to avoid actually performing
256 : * a detach, because the original process does not exist any more.
257 : */
258 : void
259 0 : filt_procdetach(struct knote *kn)
260 : {
261 0 : struct process *pr = kn->kn_ptr.p_process;
262 :
263 0 : if (kn->kn_status & KN_DETACHED)
264 0 : return;
265 :
266 : /* XXX locking? this might modify another process. */
267 0 : SLIST_REMOVE(&pr->ps_klist, kn, knote, kn_selnext);
268 0 : }
269 :
270 : int
271 0 : filt_proc(struct knote *kn, long hint)
272 : {
273 : u_int event;
274 :
275 : /*
276 : * mask off extra data
277 : */
278 0 : event = (u_int)hint & NOTE_PCTRLMASK;
279 :
280 : /*
281 : * if the user is interested in this event, record it.
282 : */
283 0 : if (kn->kn_sfflags & event)
284 0 : kn->kn_fflags |= event;
285 :
286 : /*
287 : * process is gone, so flag the event as finished and remove it
288 : * from the process's klist
289 : */
290 0 : if (event == NOTE_EXIT) {
291 0 : struct process *pr = kn->kn_ptr.p_process;
292 :
293 0 : kn->kn_status |= KN_DETACHED;
294 0 : kn->kn_flags |= (EV_EOF | EV_ONESHOT);
295 0 : kn->kn_data = pr->ps_mainproc->p_xstat;
296 0 : SLIST_REMOVE(&pr->ps_klist, kn, knote, kn_selnext);
297 : return (1);
298 : }
299 :
300 : /*
301 : * process forked, and user wants to track the new process,
302 : * so attach a new knote to it, and immediately report an
303 : * event with the parent's pid.
304 : */
305 0 : if ((event == NOTE_FORK) && (kn->kn_sfflags & NOTE_TRACK)) {
306 0 : struct kevent kev;
307 : int error;
308 :
309 : /*
310 : * register knote with new process.
311 : */
312 0 : kev.ident = hint & NOTE_PDATAMASK; /* pid */
313 0 : kev.filter = kn->kn_filter;
314 0 : kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1;
315 0 : kev.fflags = kn->kn_sfflags;
316 0 : kev.data = kn->kn_id; /* parent */
317 0 : kev.udata = kn->kn_kevent.udata; /* preserve udata */
318 0 : error = kqueue_register(kn->kn_kq, &kev, NULL);
319 0 : if (error)
320 0 : kn->kn_fflags |= NOTE_TRACKERR;
321 0 : }
322 :
323 0 : return (kn->kn_fflags != 0);
324 0 : }
325 :
326 : static void
327 0 : filt_timer_timeout_add(struct knote *kn)
328 : {
329 0 : struct timeval tv;
330 : int tticks;
331 :
332 0 : tv.tv_sec = kn->kn_sdata / 1000;
333 0 : tv.tv_usec = (kn->kn_sdata % 1000) * 1000;
334 0 : tticks = tvtohz(&tv);
335 0 : timeout_add(kn->kn_hook, tticks ? tticks : 1);
336 0 : }
337 :
338 : void
339 0 : filt_timerexpire(void *knx)
340 : {
341 0 : struct knote *kn = knx;
342 :
343 0 : kn->kn_data++;
344 0 : KNOTE_ACTIVATE(kn);
345 :
346 0 : if ((kn->kn_flags & EV_ONESHOT) == 0)
347 0 : filt_timer_timeout_add(kn);
348 0 : }
349 :
350 :
351 : /*
352 : * data contains amount of time to sleep, in milliseconds
353 : */
354 : int
355 0 : filt_timerattach(struct knote *kn)
356 : {
357 : struct timeout *to;
358 :
359 0 : if (kq_ntimeouts > kq_timeoutmax)
360 0 : return (ENOMEM);
361 0 : kq_ntimeouts++;
362 :
363 0 : kn->kn_flags |= EV_CLEAR; /* automatically set */
364 0 : to = malloc(sizeof(*to), M_KEVENT, M_WAITOK);
365 0 : timeout_set(to, filt_timerexpire, kn);
366 0 : kn->kn_hook = to;
367 0 : filt_timer_timeout_add(kn);
368 :
369 0 : return (0);
370 0 : }
371 :
372 : void
373 0 : filt_timerdetach(struct knote *kn)
374 : {
375 : struct timeout *to;
376 :
377 0 : to = (struct timeout *)kn->kn_hook;
378 0 : timeout_del(to);
379 0 : free(to, M_KEVENT, sizeof(*to));
380 0 : kq_ntimeouts--;
381 0 : }
382 :
383 : int
384 0 : filt_timer(struct knote *kn, long hint)
385 : {
386 0 : return (kn->kn_data != 0);
387 : }
388 :
389 :
390 : /*
391 : * filt_seltrue:
392 : *
393 : * This filter "event" routine simulates seltrue().
394 : */
395 : int
396 0 : filt_seltrue(struct knote *kn, long hint)
397 : {
398 :
399 : /*
400 : * We don't know how much data can be read/written,
401 : * but we know that it *can* be. This is about as
402 : * good as select/poll does as well.
403 : */
404 0 : kn->kn_data = 0;
405 0 : return (1);
406 : }
407 :
408 : /*
409 : * This provides full kqfilter entry for device switch tables, which
410 : * has same effect as filter using filt_seltrue() as filter method.
411 : */
412 : void
413 0 : filt_seltruedetach(struct knote *kn)
414 : {
415 : /* Nothing to do */
416 0 : }
417 :
418 : const struct filterops seltrue_filtops =
419 : { 1, NULL, filt_seltruedetach, filt_seltrue };
420 :
421 : int
422 0 : seltrue_kqfilter(dev_t dev, struct knote *kn)
423 : {
424 0 : switch (kn->kn_filter) {
425 : case EVFILT_READ:
426 : case EVFILT_WRITE:
427 0 : kn->kn_fop = &seltrue_filtops;
428 : break;
429 : default:
430 0 : return (EINVAL);
431 : }
432 :
433 : /* Nothing more to do */
434 0 : return (0);
435 0 : }
436 :
437 : int
438 0 : sys_kqueue(struct proc *p, void *v, register_t *retval)
439 : {
440 0 : struct filedesc *fdp = p->p_fd;
441 : struct kqueue *kq;
442 0 : struct file *fp;
443 0 : int fd, error;
444 :
445 0 : fdplock(fdp);
446 0 : error = falloc(p, &fp, &fd);
447 0 : if (error)
448 : goto out;
449 0 : fp->f_flag = FREAD | FWRITE;
450 0 : fp->f_type = DTYPE_KQUEUE;
451 0 : fp->f_ops = &kqueueops;
452 0 : kq = pool_get(&kqueue_pool, PR_WAITOK|PR_ZERO);
453 0 : TAILQ_INIT(&kq->kq_head);
454 0 : fp->f_data = kq;
455 0 : KQREF(kq);
456 0 : *retval = fd;
457 0 : kq->kq_fdp = fdp;
458 0 : LIST_INSERT_HEAD(&p->p_p->ps_kqlist, kq, kq_next);
459 0 : fdinsert(fdp, fd, 0, fp);
460 0 : FRELE(fp, p);
461 : out:
462 0 : fdpunlock(fdp);
463 0 : return (error);
464 0 : }
465 :
466 : int
467 0 : sys_kevent(struct proc *p, void *v, register_t *retval)
468 : {
469 0 : struct filedesc* fdp = p->p_fd;
470 : struct sys_kevent_args /* {
471 : syscallarg(int) fd;
472 : syscallarg(const struct kevent *) changelist;
473 : syscallarg(int) nchanges;
474 : syscallarg(struct kevent *) eventlist;
475 : syscallarg(int) nevents;
476 : syscallarg(const struct timespec *) timeout;
477 0 : } */ *uap = v;
478 : struct kevent *kevp;
479 : struct kqueue *kq;
480 : struct file *fp;
481 0 : struct timespec ts;
482 0 : int i, n, nerrors, error;
483 0 : struct kevent kev[KQ_NEVENTS];
484 :
485 0 : if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
486 0 : return (EBADF);
487 :
488 0 : if (fp->f_type != DTYPE_KQUEUE) {
489 : error = EBADF;
490 0 : goto done;
491 : }
492 :
493 0 : if (SCARG(uap, timeout) != NULL) {
494 0 : error = copyin(SCARG(uap, timeout), &ts, sizeof(ts));
495 0 : if (error)
496 : goto done;
497 : #ifdef KTRACE
498 0 : if (KTRPOINT(p, KTR_STRUCT))
499 0 : ktrreltimespec(p, &ts);
500 : #endif
501 0 : SCARG(uap, timeout) = &ts;
502 0 : }
503 :
504 0 : kq = fp->f_data;
505 : nerrors = 0;
506 :
507 0 : while (SCARG(uap, nchanges) > 0) {
508 0 : n = SCARG(uap, nchanges) > KQ_NEVENTS ?
509 : KQ_NEVENTS : SCARG(uap, nchanges);
510 0 : error = copyin(SCARG(uap, changelist), kev,
511 0 : n * sizeof(struct kevent));
512 0 : if (error)
513 : goto done;
514 : #ifdef KTRACE
515 0 : if (KTRPOINT(p, KTR_STRUCT))
516 0 : ktrevent(p, kev, n);
517 : #endif
518 0 : for (i = 0; i < n; i++) {
519 0 : kevp = &kev[i];
520 0 : kevp->flags &= ~EV_SYSFLAGS;
521 0 : error = kqueue_register(kq, kevp, p);
522 0 : if (error || (kevp->flags & EV_RECEIPT)) {
523 0 : if (SCARG(uap, nevents) != 0) {
524 0 : kevp->flags = EV_ERROR;
525 0 : kevp->data = error;
526 0 : copyout(kevp, SCARG(uap, eventlist),
527 : sizeof(*kevp));
528 0 : SCARG(uap, eventlist)++;
529 0 : SCARG(uap, nevents)--;
530 0 : nerrors++;
531 : } else {
532 : goto done;
533 : }
534 0 : }
535 : }
536 0 : SCARG(uap, nchanges) -= n;
537 0 : SCARG(uap, changelist) += n;
538 : }
539 0 : if (nerrors) {
540 0 : *retval = nerrors;
541 : error = 0;
542 0 : goto done;
543 : }
544 :
545 0 : KQREF(kq);
546 0 : FRELE(fp, p);
547 0 : error = kqueue_scan(kq, SCARG(uap, nevents), SCARG(uap, eventlist),
548 0 : SCARG(uap, timeout), p, &n);
549 0 : KQRELE(kq);
550 0 : *retval = n;
551 0 : return (error);
552 :
553 : done:
554 0 : FRELE(fp, p);
555 0 : return (error);
556 0 : }
557 :
558 : int
559 0 : kqueue_register(struct kqueue *kq, struct kevent *kev, struct proc *p)
560 : {
561 0 : struct filedesc *fdp = kq->kq_fdp;
562 : struct filterops *fops = NULL;
563 : struct file *fp = NULL;
564 : struct knote *kn = NULL;
565 : int s, error = 0;
566 :
567 0 : if (kev->filter < 0) {
568 0 : if (kev->filter + EVFILT_SYSCOUNT < 0)
569 0 : return (EINVAL);
570 0 : fops = sysfilt_ops[~kev->filter]; /* to 0-base index */
571 0 : }
572 :
573 0 : if (fops == NULL) {
574 : /*
575 : * XXX
576 : * filter attach routine is responsible for ensuring that
577 : * the identifier can be attached to it.
578 : */
579 0 : return (EINVAL);
580 : }
581 :
582 0 : if (fops->f_isfd) {
583 : /* validate descriptor */
584 0 : if (kev->ident > INT_MAX)
585 0 : return (EBADF);
586 0 : if ((fp = fd_getfile(fdp, kev->ident)) == NULL)
587 0 : return (EBADF);
588 :
589 0 : if (kev->ident < kq->kq_knlistsize) {
590 0 : SLIST_FOREACH(kn, &kq->kq_knlist[kev->ident], kn_link) {
591 0 : if (kev->filter == kn->kn_filter)
592 : break;
593 : }
594 : }
595 : } else {
596 0 : if (kq->kq_knhashmask != 0) {
597 : struct klist *list;
598 :
599 0 : list = &kq->kq_knhash[
600 0 : KN_HASH((u_long)kev->ident, kq->kq_knhashmask)];
601 0 : SLIST_FOREACH(kn, list, kn_link) {
602 0 : if (kev->ident == kn->kn_id &&
603 0 : kev->filter == kn->kn_filter)
604 : break;
605 : }
606 0 : }
607 : }
608 :
609 0 : if (kn == NULL && ((kev->flags & EV_ADD) == 0)) {
610 : error = ENOENT;
611 0 : goto done;
612 : }
613 :
614 : /*
615 : * kn now contains the matching knote, or NULL if no match
616 : */
617 0 : if (kev->flags & EV_ADD) {
618 :
619 0 : if (kn == NULL) {
620 0 : kn = knote_alloc();
621 0 : if (kn == NULL) {
622 : error = ENOMEM;
623 0 : goto done;
624 : }
625 0 : kn->kn_fp = fp;
626 0 : kn->kn_kq = kq;
627 0 : kn->kn_fop = fops;
628 :
629 : /*
630 : * apply reference count to knote structure, and
631 : * do not release it at the end of this routine.
632 : */
633 : fp = NULL;
634 :
635 0 : kn->kn_sfflags = kev->fflags;
636 0 : kn->kn_sdata = kev->data;
637 0 : kev->fflags = 0;
638 0 : kev->data = 0;
639 0 : kn->kn_kevent = *kev;
640 :
641 0 : knote_attach(kn);
642 0 : if ((error = fops->f_attach(kn)) != 0) {
643 0 : knote_drop(kn, p);
644 0 : goto done;
645 : }
646 : } else {
647 : /*
648 : * The user may change some filter values after the
649 : * initial EV_ADD, but doing so will not reset any
650 : * filters which have already been triggered.
651 : */
652 0 : kn->kn_sfflags = kev->fflags;
653 0 : kn->kn_sdata = kev->data;
654 0 : kn->kn_kevent.udata = kev->udata;
655 : }
656 :
657 0 : s = splhigh();
658 0 : if (kn->kn_fop->f_event(kn, 0))
659 0 : KNOTE_ACTIVATE(kn);
660 0 : splx(s);
661 :
662 0 : } else if (kev->flags & EV_DELETE) {
663 0 : kn->kn_fop->f_detach(kn);
664 0 : knote_drop(kn, p);
665 0 : goto done;
666 : }
667 :
668 0 : if ((kev->flags & EV_DISABLE) &&
669 0 : ((kn->kn_status & KN_DISABLED) == 0)) {
670 0 : s = splhigh();
671 0 : kn->kn_status |= KN_DISABLED;
672 0 : splx(s);
673 0 : }
674 :
675 0 : if ((kev->flags & EV_ENABLE) && (kn->kn_status & KN_DISABLED)) {
676 0 : s = splhigh();
677 0 : kn->kn_status &= ~KN_DISABLED;
678 0 : if (kn->kn_fop->f_event(kn, 0))
679 0 : kn->kn_status |= KN_ACTIVE;
680 0 : if ((kn->kn_status & KN_ACTIVE) &&
681 0 : ((kn->kn_status & KN_QUEUED) == 0))
682 0 : knote_enqueue(kn);
683 0 : splx(s);
684 0 : }
685 :
686 : done:
687 0 : if (fp != NULL)
688 0 : FRELE(fp, p);
689 0 : return (error);
690 0 : }
691 :
692 : int
693 0 : kqueue_scan(struct kqueue *kq, int maxevents, struct kevent *ulistp,
694 : const struct timespec *tsp, struct proc *p, int *retval)
695 : {
696 : struct kevent *kevp;
697 0 : struct timespec ats, rts, tts;
698 0 : struct knote *kn, marker;
699 : int s, count, timeout, nkev = 0, error = 0;
700 0 : struct kevent kev[KQ_NEVENTS];
701 :
702 : count = maxevents;
703 0 : if (count == 0)
704 : goto done;
705 :
706 0 : if (tsp != NULL) {
707 0 : ats = *tsp;
708 0 : if (!timespecisset(&ats)) {
709 : /* No timeout, just poll */
710 : timeout = -1;
711 0 : goto start;
712 : }
713 0 : if (timespecfix(&ats)) {
714 : error = EINVAL;
715 0 : goto done;
716 : }
717 :
718 0 : timeout = ats.tv_sec > 24 * 60 * 60 ?
719 0 : 24 * 60 * 60 * hz : tstohz(&ats);
720 :
721 0 : getnanouptime(&rts);
722 0 : timespecadd(&ats, &rts, &ats);
723 : } else {
724 0 : timespecclear(&ats);
725 : timeout = 0;
726 : }
727 0 : goto start;
728 :
729 : retry:
730 0 : if (timespecisset(&ats)) {
731 0 : getnanouptime(&rts);
732 0 : if (timespeccmp(&rts, &ats, >=))
733 : goto done;
734 0 : tts = ats;
735 0 : timespecsub(&tts, &rts, &tts);
736 0 : timeout = tts.tv_sec > 24 * 60 * 60 ?
737 0 : 24 * 60 * 60 * hz : tstohz(&tts);
738 0 : }
739 :
740 : start:
741 0 : if (kq->kq_state & KQ_DYING) {
742 : error = EBADF;
743 0 : goto done;
744 : }
745 :
746 0 : kevp = &kev[0];
747 0 : s = splhigh();
748 0 : if (kq->kq_count == 0) {
749 0 : if (timeout < 0) {
750 : error = EWOULDBLOCK;
751 0 : } else {
752 0 : kq->kq_state |= KQ_SLEEP;
753 0 : error = tsleep(kq, PSOCK | PCATCH, "kqread", timeout);
754 : }
755 0 : splx(s);
756 0 : if (error == 0)
757 : goto retry;
758 : /* don't restart after signals... */
759 0 : if (error == ERESTART)
760 0 : error = EINTR;
761 0 : else if (error == EWOULDBLOCK)
762 0 : error = 0;
763 : goto done;
764 : }
765 :
766 0 : TAILQ_INSERT_TAIL(&kq->kq_head, &marker, kn_tqe);
767 0 : while (count) {
768 0 : kn = TAILQ_FIRST(&kq->kq_head);
769 0 : if (kn == &marker) {
770 0 : TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
771 0 : splx(s);
772 0 : if (count == maxevents)
773 : goto retry;
774 : goto done;
775 : }
776 :
777 0 : TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
778 0 : kq->kq_count--;
779 :
780 0 : if (kn->kn_status & KN_DISABLED) {
781 0 : kn->kn_status &= ~KN_QUEUED;
782 0 : continue;
783 : }
784 0 : if ((kn->kn_flags & EV_ONESHOT) == 0 &&
785 0 : kn->kn_fop->f_event(kn, 0) == 0) {
786 0 : kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
787 0 : continue;
788 : }
789 0 : *kevp = kn->kn_kevent;
790 0 : kevp++;
791 0 : nkev++;
792 0 : if (kn->kn_flags & EV_ONESHOT) {
793 0 : kn->kn_status &= ~KN_QUEUED;
794 0 : splx(s);
795 0 : kn->kn_fop->f_detach(kn);
796 0 : knote_drop(kn, p);
797 0 : s = splhigh();
798 0 : } else if (kn->kn_flags & (EV_CLEAR | EV_DISPATCH)) {
799 0 : if (kn->kn_flags & EV_CLEAR) {
800 0 : kn->kn_data = 0;
801 0 : kn->kn_fflags = 0;
802 0 : }
803 0 : if (kn->kn_flags & EV_DISPATCH)
804 0 : kn->kn_status |= KN_DISABLED;
805 0 : kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
806 0 : } else {
807 0 : TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
808 0 : kq->kq_count++;
809 : }
810 0 : count--;
811 0 : if (nkev == KQ_NEVENTS) {
812 0 : splx(s);
813 : #ifdef KTRACE
814 0 : if (KTRPOINT(p, KTR_STRUCT))
815 0 : ktrevent(p, kev, nkev);
816 : #endif
817 0 : error = copyout(kev, ulistp,
818 0 : sizeof(struct kevent) * nkev);
819 0 : ulistp += nkev;
820 : nkev = 0;
821 : kevp = &kev[0];
822 0 : s = splhigh();
823 0 : if (error)
824 : break;
825 : }
826 : }
827 0 : TAILQ_REMOVE(&kq->kq_head, &marker, kn_tqe);
828 0 : splx(s);
829 : done:
830 0 : if (nkev != 0) {
831 : #ifdef KTRACE
832 0 : if (KTRPOINT(p, KTR_STRUCT))
833 0 : ktrevent(p, kev, nkev);
834 : #endif
835 0 : error = copyout(kev, ulistp,
836 0 : sizeof(struct kevent) * nkev);
837 0 : }
838 0 : *retval = maxevents - count;
839 0 : return (error);
840 0 : }
841 :
842 : /*
843 : * XXX
844 : * This could be expanded to call kqueue_scan, if desired.
845 : */
846 : int
847 0 : kqueue_read(struct file *fp, struct uio *uio, int fflags)
848 : {
849 0 : return (ENXIO);
850 : }
851 :
852 : int
853 0 : kqueue_write(struct file *fp, struct uio *uio, int fflags)
854 : {
855 0 : return (ENXIO);
856 : }
857 :
858 : int
859 0 : kqueue_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
860 : {
861 0 : return (ENOTTY);
862 : }
863 :
864 : int
865 0 : kqueue_poll(struct file *fp, int events, struct proc *p)
866 : {
867 0 : struct kqueue *kq = (struct kqueue *)fp->f_data;
868 : int revents = 0;
869 0 : int s = splhigh();
870 :
871 0 : if (events & (POLLIN | POLLRDNORM)) {
872 0 : if (kq->kq_count) {
873 : revents |= events & (POLLIN | POLLRDNORM);
874 0 : } else {
875 0 : selrecord(p, &kq->kq_sel);
876 0 : kq->kq_state |= KQ_SEL;
877 : }
878 : }
879 0 : splx(s);
880 0 : return (revents);
881 : }
882 :
883 : int
884 0 : kqueue_stat(struct file *fp, struct stat *st, struct proc *p)
885 : {
886 0 : struct kqueue *kq = fp->f_data;
887 :
888 0 : memset(st, 0, sizeof(*st));
889 0 : st->st_size = kq->kq_count;
890 0 : st->st_blksize = sizeof(struct kevent);
891 0 : st->st_mode = S_IFIFO;
892 0 : return (0);
893 : }
894 :
895 : int
896 0 : kqueue_close(struct file *fp, struct proc *p)
897 : {
898 0 : struct kqueue *kq = fp->f_data;
899 : int i;
900 :
901 0 : KERNEL_LOCK();
902 :
903 0 : for (i = 0; i < kq->kq_knlistsize; i++)
904 0 : knote_remove(p, &kq->kq_knlist[i]);
905 0 : if (kq->kq_knhashmask != 0) {
906 0 : for (i = 0; i < kq->kq_knhashmask + 1; i++)
907 0 : knote_remove(p, &kq->kq_knhash[i]);
908 : }
909 0 : fp->f_data = NULL;
910 :
911 0 : kq->kq_state |= KQ_DYING;
912 0 : kqueue_wakeup(kq);
913 0 : KQRELE(kq);
914 :
915 0 : KERNEL_UNLOCK();
916 :
917 0 : return (0);
918 : }
919 :
920 : void
921 0 : kqueue_wakeup(struct kqueue *kq)
922 : {
923 :
924 0 : if (kq->kq_state & KQ_SLEEP) {
925 0 : kq->kq_state &= ~KQ_SLEEP;
926 0 : wakeup(kq);
927 0 : }
928 0 : if (kq->kq_state & KQ_SEL) {
929 0 : kq->kq_state &= ~KQ_SEL;
930 0 : selwakeup(&kq->kq_sel);
931 0 : } else
932 0 : KNOTE(&kq->kq_sel.si_note, 0);
933 0 : }
934 :
935 : /*
936 : * activate one knote.
937 : */
938 : void
939 0 : knote_activate(struct knote *kn)
940 : {
941 0 : KNOTE_ACTIVATE(kn);
942 0 : }
943 :
944 : /*
945 : * walk down a list of knotes, activating them if their event has triggered.
946 : */
947 : void
948 0 : knote(struct klist *list, long hint)
949 : {
950 : struct knote *kn, *kn0;
951 :
952 0 : SLIST_FOREACH_SAFE(kn, list, kn_selnext, kn0)
953 0 : if (kn->kn_fop->f_event(kn, hint))
954 0 : KNOTE_ACTIVATE(kn);
955 0 : }
956 :
957 : /*
958 : * remove all knotes from a specified klist
959 : */
960 : void
961 0 : knote_remove(struct proc *p, struct klist *list)
962 : {
963 : struct knote *kn;
964 :
965 0 : while ((kn = SLIST_FIRST(list)) != NULL) {
966 0 : kn->kn_fop->f_detach(kn);
967 0 : knote_drop(kn, p);
968 : }
969 0 : }
970 :
971 : /*
972 : * remove all knotes referencing a specified fd
973 : */
974 : void
975 0 : knote_fdclose(struct proc *p, int fd)
976 : {
977 : struct kqueue *kq;
978 : struct klist *list;
979 :
980 0 : LIST_FOREACH(kq, &p->p_p->ps_kqlist, kq_next) {
981 0 : if (fd >= kq->kq_knlistsize)
982 : continue;
983 :
984 0 : list = &kq->kq_knlist[fd];
985 0 : knote_remove(p, list);
986 0 : }
987 0 : }
988 :
989 : /*
990 : * handle a process exiting, including the triggering of NOTE_EXIT notes
991 : * XXX this could be more efficient, doing a single pass down the klist
992 : */
993 : void
994 0 : knote_processexit(struct proc *p)
995 : {
996 0 : struct process *pr = p->p_p;
997 :
998 0 : KNOTE(&pr->ps_klist, NOTE_EXIT);
999 :
1000 : /* remove other knotes hanging off the process */
1001 0 : knote_remove(p, &pr->ps_klist);
1002 0 : }
1003 :
1004 : void
1005 0 : knote_attach(struct knote *kn)
1006 : {
1007 0 : struct kqueue *kq = kn->kn_kq;
1008 : struct klist *list;
1009 : int size;
1010 :
1011 0 : if (!kn->kn_fop->f_isfd) {
1012 0 : if (kq->kq_knhashmask == 0)
1013 0 : kq->kq_knhash = hashinit(KN_HASHSIZE, M_TEMP,
1014 : M_WAITOK, &kq->kq_knhashmask);
1015 0 : list = &kq->kq_knhash[KN_HASH(kn->kn_id, kq->kq_knhashmask)];
1016 0 : goto done;
1017 : }
1018 :
1019 0 : if (kq->kq_knlistsize <= kn->kn_id) {
1020 : size = kq->kq_knlistsize;
1021 0 : while (size <= kn->kn_id)
1022 0 : size += KQEXTENT;
1023 0 : list = mallocarray(size, sizeof(struct klist), M_TEMP,
1024 : M_WAITOK);
1025 0 : memcpy(list, kq->kq_knlist,
1026 : kq->kq_knlistsize * sizeof(struct klist));
1027 0 : memset(&list[kq->kq_knlistsize], 0,
1028 : (size - kq->kq_knlistsize) * sizeof(struct klist));
1029 0 : free(kq->kq_knlist, M_TEMP,
1030 0 : kq->kq_knlistsize * sizeof(struct klist));
1031 0 : kq->kq_knlistsize = size;
1032 0 : kq->kq_knlist = list;
1033 0 : }
1034 0 : list = &kq->kq_knlist[kn->kn_id];
1035 : done:
1036 0 : SLIST_INSERT_HEAD(list, kn, kn_link);
1037 0 : kn->kn_status = 0;
1038 0 : }
1039 :
1040 : /*
1041 : * should be called at spl == 0, since we don't want to hold spl
1042 : * while calling FRELE and knote_free.
1043 : */
1044 : void
1045 0 : knote_drop(struct knote *kn, struct proc *p)
1046 : {
1047 0 : struct kqueue *kq = kn->kn_kq;
1048 : struct klist *list;
1049 :
1050 0 : if (kn->kn_fop->f_isfd)
1051 0 : list = &kq->kq_knlist[kn->kn_id];
1052 : else
1053 0 : list = &kq->kq_knhash[KN_HASH(kn->kn_id, kq->kq_knhashmask)];
1054 :
1055 0 : SLIST_REMOVE(list, kn, knote, kn_link);
1056 0 : if (kn->kn_status & KN_QUEUED)
1057 0 : knote_dequeue(kn);
1058 0 : if (kn->kn_fop->f_isfd)
1059 0 : FRELE(kn->kn_fp, p);
1060 0 : knote_free(kn);
1061 0 : }
1062 :
1063 :
1064 : void
1065 0 : knote_enqueue(struct knote *kn)
1066 : {
1067 0 : struct kqueue *kq = kn->kn_kq;
1068 0 : int s = splhigh();
1069 :
1070 0 : KASSERT((kn->kn_status & KN_QUEUED) == 0);
1071 :
1072 0 : TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
1073 0 : kn->kn_status |= KN_QUEUED;
1074 0 : kq->kq_count++;
1075 0 : splx(s);
1076 0 : kqueue_wakeup(kq);
1077 0 : }
1078 :
1079 : void
1080 0 : knote_dequeue(struct knote *kn)
1081 : {
1082 0 : struct kqueue *kq = kn->kn_kq;
1083 0 : int s = splhigh();
1084 :
1085 0 : KASSERT(kn->kn_status & KN_QUEUED);
1086 :
1087 0 : TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
1088 0 : kn->kn_status &= ~KN_QUEUED;
1089 0 : kq->kq_count--;
1090 0 : splx(s);
1091 0 : }
1092 :
1093 : void
1094 0 : klist_invalidate(struct klist *list)
1095 : {
1096 : struct knote *kn;
1097 :
1098 0 : SLIST_FOREACH(kn, list, kn_selnext) {
1099 0 : kn->kn_status |= KN_DETACHED;
1100 0 : kn->kn_flags |= EV_EOF | EV_ONESHOT;
1101 : }
1102 0 : }
|