]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_event.c
xnu-517.7.7.tar.gz
[apple/xnu.git] / bsd / kern / kern_event.c
CommitLineData
1c79356b 1/*
55e303ae 2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
1c79356b 11 *
e5568f75
A
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
1c79356b
A
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 *
22 */
55e303ae
A
23/*-
24 * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
25 * All rights reserved.
26 *
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions
29 * are met:
30 * 1. Redistributions of source code must retain the above copyright
31 * notice, this list of conditions and the following disclaimer.
32 * 2. Redistributions in binary form must reproduce the above copyright
33 * notice, this list of conditions and the following disclaimer in the
34 * documentation and/or other materials provided with the distribution.
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 */
1c79356b
A
48/*
49 * @(#)kern_event.c 1.0 (3/31/2000)
50 */
51
55e303ae
A
52#include <sys/param.h>
53#include <sys/systm.h>
54#include <sys/filedesc.h>
55#include <sys/kernel.h>
56#include <sys/proc.h>
57#include <sys/malloc.h>
58#include <sys/unistd.h>
59#include <sys/file.h>
60#include <sys/fcntl.h>
61#include <sys/select.h>
62#include <sys/queue.h>
63#include <sys/event.h>
64#include <sys/eventvar.h>
65#include <sys/protosw.h>
66#include <sys/socket.h>
67#include <sys/socketvar.h>
68#include <sys/stat.h>
69#include <sys/sysctl.h>
70#include <sys/uio.h>
71
72#include <kern/zalloc.h>
73
74MALLOC_DEFINE(M_KQUEUE, "kqueue", "memory for kqueue system");
75
76static int kqueue_scan(struct file *fp, int maxevents,
77 struct kevent *ulistp, const struct timespec *timeout,
78 register_t *retval, struct proc *p);
79static void kqueue_wakeup(struct kqueue *kq);
80
81static int kqueue_read __P((struct file *fp, struct uio *uio,
82 struct ucred *cred, int flags, struct proc *p));
83static int kqueue_write __P((struct file *fp, struct uio *uio,
84 struct ucred *cred, int flags, struct proc *p));
85static int kqueue_ioctl __P((struct file *fp, u_long com, caddr_t data,
86 struct proc *p));
87static int kqueue_select __P((struct file *fp, int which, void *wql,
88 struct proc *p));
89static int kqueue_close __P((struct file *fp, struct proc *p));
90static int kqueue_kqfilter __P((struct file *fp, struct knote *kn, struct proc *p));
91
92static struct fileops kqueueops = {
93 kqueue_read,
94 kqueue_write,
95 kqueue_ioctl,
96 kqueue_select,
97 kqueue_close,
98 kqueue_kqfilter
99};
100
101static void knote_fdpattach(struct knote *kn, struct filedesc *fdp);
102static void knote_drop(struct knote *kn, struct proc *p);
103static void knote_enqueue(struct knote *kn);
104static void knote_dequeue(struct knote *kn);
105static struct knote *knote_alloc(void);
106static void knote_free(struct knote *kn);
107
108static int filt_fileattach(struct knote *kn);
109static struct filterops file_filtops =
110 { 1, filt_fileattach, NULL, NULL };
111
112static void filt_kqdetach(struct knote *kn);
113static int filt_kqueue(struct knote *kn, long hint);
114static struct filterops kqread_filtops =
115 { 1, NULL, filt_kqdetach, filt_kqueue };
116
117/*
118 * JMM - placeholder for not-yet-implemented filters
119 */
120static int filt_badattach(struct knote *kn);
121static struct filterops bad_filtops =
122 { 0, filt_badattach, 0 , 0 };
123
124static int filt_procattach(struct knote *kn);
125static void filt_procdetach(struct knote *kn);
126static int filt_proc(struct knote *kn, long hint);
127
128static struct filterops proc_filtops =
129 { 0, filt_procattach, filt_procdetach, filt_proc };
130
131extern struct filterops fs_filtops;
132
133extern struct filterops sig_filtops;
134
135#if 0
136/* JMM - We don't implement these now */
137static void filt_timerexpire(void *knx);
138static int filt_timerattach(struct knote *kn);
139static void filt_timerdetach(struct knote *kn);
140static int filt_timer(struct knote *kn, long hint);
141
142static struct filterops timer_filtops =
143 { 0, filt_timerattach, filt_timerdetach, filt_timer };
144
145static int kq_ncallouts = 0;
146static int kq_calloutmax = (4 * 1024);
147
148SYSCTL_INT(_kern, OID_AUTO, kq_calloutmax, CTLFLAG_RW,
149 &kq_calloutmax, 0, "Maximum number of callouts allocated for kqueue");
150#endif /* 0 */
151
152static zone_t knote_zone;
153
154#define KNOTE_ACTIVATE(kn) do { \
155 kn->kn_status |= KN_ACTIVE; \
156 if ((kn->kn_status & (KN_QUEUED | KN_DISABLED)) == 0) \
157 knote_enqueue(kn); \
158} while(0)
159
160#define KN_HASHSIZE 64 /* XXX should be tunable */
161#define KN_HASH(val, mask) (((val) ^ (val >> 8)) & (mask))
162
163#if 0
164extern struct filterops aio_filtops;
165#endif
166
167/*
168 * Table for for all system-defined filters.
169 */
170static struct filterops *sysfilt_ops[] = {
171 &file_filtops, /* EVFILT_READ */
172 &file_filtops, /* EVFILT_WRITE */
173#if 0
174 &aio_filtops, /* EVFILT_AIO */
175#else
176 &bad_filtops, /* EVFILT_AIO */
177#endif
178 &file_filtops, /* EVFILT_VNODE */
179 &proc_filtops, /* EVFILT_PROC */
180 &sig_filtops, /* EVFILT_SIGNAL */
181#if 0
182 &timer_filtops, /* EVFILT_TIMER */
183#else
184 &bad_filtops, /* EVFILT_TIMER */
185#endif
186 &bad_filtops, /* EVFILT_MACHPORT */
187 &fs_filtops /* EVFILT_FS */
188};
189
190static int
191filt_fileattach(struct knote *kn)
192{
193
194 return (fo_kqfilter(kn->kn_fp, kn, current_proc()));
195}
196
197static void
198filt_kqdetach(struct knote *kn)
199{
200 struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data;
201
202 if (kq->kq_state & KQ_SEL)
203 return;
204
205 KNOTE_DETACH(&kq->kq_sel.si_note, kn);
206}
207
208/*ARGSUSED*/
209static int
210filt_kqueue(struct knote *kn, long hint)
211{
212 struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data;
213
214 kn->kn_data = kq->kq_count;
215 return (kn->kn_data > 0);
216}
217
218static int
219filt_procattach(struct knote *kn)
220{
221 struct proc *p;
222
223 p = pfind(kn->kn_id);
224 if (p == NULL)
225 return (ESRCH);
226 if (! PRISON_CHECK(current_proc(), p))
227 return (EACCES);
228
229 kn->kn_ptr.p_proc = p;
230 kn->kn_flags |= EV_CLEAR; /* automatically set */
231
232 /*
233 * internal flag indicating registration done by kernel
234 */
235 if (kn->kn_flags & EV_FLAG1) {
236 kn->kn_data = kn->kn_sdata; /* ppid */
237 kn->kn_fflags = NOTE_CHILD;
238 kn->kn_flags &= ~EV_FLAG1;
239 }
240
241 /* XXX lock the proc here while adding to the list? */
242 KNOTE_ATTACH(&p->p_klist, kn);
243
244 return (0);
245}
246
247/*
248 * The knote may be attached to a different process, which may exit,
249 * leaving nothing for the knote to be attached to. So when the process
250 * exits, the knote is marked as DETACHED and also flagged as ONESHOT so
251 * it will be deleted when read out. However, as part of the knote deletion,
252 * this routine is called, so a check is needed to avoid actually performing
253 * a detach, because the original process does not exist any more.
254 */
255static void
256filt_procdetach(struct knote *kn)
257{
258 struct proc *p = kn->kn_ptr.p_proc;
259
260 if (kn->kn_status & KN_DETACHED)
261 return;
262
263 /* XXX locking? this might modify another process. */
264 KNOTE_DETACH(&p->p_klist, kn);
265}
266
267static int
268filt_proc(struct knote *kn, long hint)
269{
270 u_int event;
271
272 /*
273 * mask off extra data
274 */
275 event = (u_int)hint & NOTE_PCTRLMASK;
276
277 /*
278 * if the user is interested in this event, record it.
279 */
280 if (kn->kn_sfflags & event)
281 kn->kn_fflags |= event;
282
283 /*
284 * process is gone, so flag the event as finished.
285 */
286 if (event == NOTE_EXIT) {
287 kn->kn_status |= KN_DETACHED;
288 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
289 return (1);
290 }
291
292 /*
293 * process forked, and user wants to track the new process,
294 * so attach a new knote to it, and immediately report an
295 * event with the parent's pid.
296 */
297 if ((event == NOTE_FORK) && (kn->kn_sfflags & NOTE_TRACK)) {
298 struct kevent kev;
299 int error;
300
301 /*
302 * register knote with new process.
303 */
304 kev.ident = hint & NOTE_PDATAMASK; /* pid */
305 kev.filter = kn->kn_filter;
306 kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1;
307 kev.fflags = kn->kn_sfflags;
308 kev.data = kn->kn_id; /* parent */
309 kev.udata = kn->kn_kevent.udata; /* preserve udata */
310 error = kqueue_register(kn->kn_kq, &kev, NULL);
311 if (error)
312 kn->kn_fflags |= NOTE_TRACKERR;
313 }
314
315 return (kn->kn_fflags != 0);
316}
317
318#if 0
319static void
320filt_timerexpire(void *knx)
321{
322 struct knote *kn = knx;
323 struct callout *calloutp;
324 struct timeval tv;
325 int tticks;
326
327 kn->kn_data++;
328 KNOTE_ACTIVATE(kn);
329
330 if ((kn->kn_flags & EV_ONESHOT) == 0) {
331 tv.tv_sec = kn->kn_sdata / 1000;
332 tv.tv_usec = (kn->kn_sdata % 1000) * 1000;
333 tticks = tvtohz(&tv);
334 calloutp = (struct callout *)kn->kn_hook;
335 callout_reset(calloutp, tticks, filt_timerexpire, kn);
336 }
337}
338
339/*
340 * data contains amount of time to sleep, in milliseconds
341 */
342static int
343filt_timerattach(struct knote *kn)
344{
345 struct callout *calloutp;
346 struct timeval tv;
347 int tticks;
348
349 if (kq_ncallouts >= kq_calloutmax)
350 return (ENOMEM);
351 kq_ncallouts++;
352
353 tv.tv_sec = kn->kn_sdata / 1000;
354 tv.tv_usec = (kn->kn_sdata % 1000) * 1000;
355 tticks = tvtohz(&tv);
356
357 kn->kn_flags |= EV_CLEAR; /* automatically set */
358 MALLOC(calloutp, struct callout *, sizeof(*calloutp),
359 M_KQUEUE, M_WAITOK);
360 callout_init(calloutp);
361 callout_reset(calloutp, tticks, filt_timerexpire, kn);
362 kn->kn_hook = (caddr_t)calloutp;
363
364 return (0);
365}
366
367static void
368filt_timerdetach(struct knote *kn)
369{
370 struct callout *calloutp;
371
372 calloutp = (struct callout *)kn->kn_hook;
373 callout_stop(calloutp);
374 FREE(calloutp, M_KQUEUE);
375 kq_ncallouts--;
376}
377
378static int
379filt_timer(struct knote *kn, long hint)
380{
381
382 return (kn->kn_data != 0);
383}
384#endif /* 0 */
385
386/*
387 * JMM - placeholder for not-yet-implemented filters
388 */
389static int
390filt_badattach(struct knote *kn)
391{
392 return(EOPNOTSUPP);
393}
394
395#ifndef _SYS_SYSPROTO_H_
396struct kqueue_args {
397 int dummy;
398};
399#endif
400
401int
402kqueue(struct proc *p, struct kqueue_args *uap, register_t *retval)
403{
404 struct filedesc *fdp = p->p_fd;
405 struct kqueue *kq;
406 struct file *fp;
407 int fd, error;
408
409 error = falloc(p, &fp, &fd);
410 if (error)
411 return (error);
412 fp->f_flag = FREAD | FWRITE;
413 fp->f_type = DTYPE_KQUEUE;
414 fp->f_ops = &kqueueops;
415 kq = (struct kqueue *)_MALLOC(sizeof(struct kqueue), M_KQUEUE, M_WAITOK | M_ZERO);
416 TAILQ_INIT(&kq->kq_head);
417 fp->f_data = (caddr_t)kq;
418 *retval = fd;
419 if (fdp->fd_knlistsize < 0)
420 fdp->fd_knlistsize = 0; /* this process has a kq */
421 kq->kq_fdp = fdp;
422 return (error);
423}
424
425#ifndef _SYS_SYSPROTO_H_
426struct kqueue_portset_np_args {
427 int fd;
428};
429#endif
430int
431kqueue_portset_np(struct proc *p, struct kqueue_portset_np_args *uap, register_t *retval)
432{
433 /* JMM - Placeholder for now */
434 return (EOPNOTSUPP);
435}
436
437#ifndef _SYS_SYSPROTO_H_
438struct kqueue_from_portset_np_args {
439 int fd;
440};
441#endif
442int
443kqueue_from_portset_np(struct proc *p, struct kqueue_from_portset_np_args *uap, register_t *retval)
444{
445 /* JMM - Placeholder for now */
446 return (EOPNOTSUPP);
447}
448
449#if !0
450/* JMM - We don't implement this yet */
451#define fhold(fp)
452#define fdrop(fp, p)
453#endif /* !0 */
454
455#ifndef _SYS_SYSPROTO_H_
456struct kevent_args {
457 int fd;
458 const struct kevent *changelist;
459 int nchanges;
460 struct kevent *eventlist;
461 int nevents;
462 const struct timespec *timeout;
463};
464#endif
465int
466kevent(struct proc *p, struct kevent_args *uap, register_t *retval)
467{
468 struct filedesc* fdp = p->p_fd;
469 struct kqueue *kq;
470 struct file *fp = NULL;
471 struct timespec ts;
472 int i, nerrors, error;
473
474 if (uap->timeout != NULL) {
475 error = copyin((caddr_t)uap->timeout, (caddr_t)&ts, sizeof(ts));
476 if (error)
477 goto done;
478 uap->timeout = &ts;
479 }
480
481 if (((u_int)uap->fd) >= fdp->fd_nfiles ||
482 (fp = fdp->fd_ofiles[uap->fd]) == NULL ||
483 (fp->f_type != DTYPE_KQUEUE))
484 return (EBADF);
485
486 fhold(fp);
487
488 kq = (struct kqueue *)fp->f_data;
489 nerrors = 0;
490
491 while (uap->nchanges > 0) {
492 int i;
493 int n = uap->nchanges > KQ_NEVENTS ? KQ_NEVENTS : uap->nchanges;
494 struct kevent kq_kev[n];
495
496 error = copyin((caddr_t)uap->changelist, (caddr_t)kq_kev,
497 n * sizeof(struct kevent));
498 if (error)
499 goto done;
500 for (i = 0; i < n; i++) {
501 struct kevent *kevp = &kq_kev[i];
502
503 kevp->flags &= ~EV_SYSFLAGS;
504 error = kqueue_register(kq, kevp, p);
505 if (error) {
506 if (uap->nevents != 0) {
507 kevp->flags = EV_ERROR;
508 kevp->data = error;
509 (void) copyout((caddr_t)kevp,
510 (caddr_t)uap->eventlist,
511 sizeof(*kevp));
512 uap->eventlist++;
513 uap->nevents--;
514 nerrors++;
515 } else {
516 goto done;
517 }
518 }
519 }
520 uap->nchanges -= n;
521 uap->changelist += n;
522 }
523 if (nerrors) {
524 *retval = nerrors;
525 error = 0;
526 goto done;
527 }
528
529 error = kqueue_scan(fp, uap->nevents, uap->eventlist, uap->timeout, retval, p);
530done:
531 if (fp != NULL)
532 fdrop(fp, p);
533 return (error);
534}
535
536int
537kqueue_register(struct kqueue *kq, struct kevent *kev, struct proc *p)
538{
539 struct filedesc *fdp = kq->kq_fdp;
540 struct filterops *fops;
541 struct file *fp = NULL;
542 struct knote *kn = NULL;
543 int s, error = 0;
544
545 if (kev->filter < 0) {
546 if (kev->filter + EVFILT_SYSCOUNT < 0)
547 return (EINVAL);
548 fops = sysfilt_ops[~kev->filter]; /* to 0-base index */
549 } else {
550 /*
551 * XXX
552 * filter attach routine is responsible for insuring that
553 * the identifier can be attached to it.
554 */
555 printf("unknown filter: %d\n", kev->filter);
556 return (EINVAL);
557 }
558
559 if (fops->f_isfd) {
560 /* validate descriptor */
561 if ((u_int)kev->ident >= fdp->fd_nfiles ||
562 (fp = fdp->fd_ofiles[kev->ident]) == NULL)
563 return (EBADF);
564 fhold(fp);
565
566 if (kev->ident < fdp->fd_knlistsize) {
567 SLIST_FOREACH(kn, &fdp->fd_knlist[kev->ident], kn_link)
568 if (kq == kn->kn_kq &&
569 kev->filter == kn->kn_filter)
570 break;
571 }
572 } else {
573 if (fdp->fd_knhashmask != 0) {
574 struct klist *list;
575
576 list = &fdp->fd_knhash[
577 KN_HASH((u_long)kev->ident, fdp->fd_knhashmask)];
578 SLIST_FOREACH(kn, list, kn_link)
579 if (kev->ident == kn->kn_id &&
580 kq == kn->kn_kq &&
581 kev->filter == kn->kn_filter)
582 break;
583 }
584 }
585
586 if (kn == NULL && ((kev->flags & EV_ADD) == 0)) {
587 error = ENOENT;
588 goto done;
589 }
590
591 /*
592 * kn now contains the matching knote, or NULL if no match
593 */
594 if (kev->flags & EV_ADD) {
595
596 if (kn == NULL) {
597 kn = knote_alloc();
598 if (kn == NULL) {
599 error = ENOMEM;
600 goto done;
601 }
602 kn->kn_fp = fp;
603 kn->kn_kq = kq;
604 kn->kn_fop = fops;
605
606 /*
607 * apply reference count to knote structure, and
608 * do not release it at the end of this routine.
609 */
610 fp = NULL;
611
612 kn->kn_sfflags = kev->fflags;
613 kn->kn_sdata = kev->data;
614 kev->fflags = 0;
615 kev->data = 0;
616 kn->kn_kevent = *kev;
617
618 knote_fdpattach(kn, fdp);
619 if ((error = fops->f_attach(kn)) != 0) {
620 knote_drop(kn, p);
621 goto done;
622 }
623 } else {
624 /*
625 * The user may change some filter values after the
626 * initial EV_ADD, but doing so will not reset any
627 * filter which have already been triggered.
628 */
629 kn->kn_sfflags = kev->fflags;
630 kn->kn_sdata = kev->data;
631 kn->kn_kevent.udata = kev->udata;
632 }
633
634 s = splhigh();
635 if (kn->kn_fop->f_event(kn, 0))
636 KNOTE_ACTIVATE(kn);
637 splx(s);
638
639 } else if (kev->flags & EV_DELETE) {
640 kn->kn_fop->f_detach(kn);
641 knote_drop(kn, p);
642 goto done;
643 }
644
645 if ((kev->flags & EV_DISABLE) &&
646 ((kn->kn_status & KN_DISABLED) == 0)) {
647 s = splhigh();
648 kn->kn_status |= KN_DISABLED;
649 splx(s);
650 }
651
652 if ((kev->flags & EV_ENABLE) && (kn->kn_status & KN_DISABLED)) {
653 s = splhigh();
654 kn->kn_status &= ~KN_DISABLED;
655 if ((kn->kn_status & KN_ACTIVE) &&
656 ((kn->kn_status & KN_QUEUED) == 0))
657 knote_enqueue(kn);
658 splx(s);
659 }
660
661done:
662 if (fp != NULL)
663 fdrop(fp, p);
664 return (error);
665}
666
667static int
668kqueue_scan(struct file *fp, int maxevents, struct kevent *ulistp,
669 const struct timespec *tsp, register_t *retval, struct proc *p)
670{
671 struct kqueue *kq = (struct kqueue *)fp->f_data;
672 struct timeval atv, rtv, ttv;
673 int s, count, timeout, error = 0;
674 struct knote marker;
675
676 count = maxevents;
677 if (count == 0)
678 goto done;
679
680 if (tsp != NULL) {
681 TIMESPEC_TO_TIMEVAL(&atv, tsp);
682 if (itimerfix(&atv)) {
683 error = EINVAL;
684 goto done;
685 }
686 if (tsp->tv_sec == 0 && tsp->tv_nsec == 0)
687 timeout = -1;
688 else
689 timeout = atv.tv_sec > 24 * 60 * 60 ?
690 24 * 60 * 60 * hz : tvtohz(&atv);
691 getmicrouptime(&rtv);
692 timevaladd(&atv, &rtv);
693 } else {
694 atv.tv_sec = 0;
695 atv.tv_usec = 0;
696 timeout = 0;
697 }
698 goto start;
699
700retry:
701 if (atv.tv_sec || atv.tv_usec) {
702 getmicrouptime(&rtv);
703 if (timevalcmp(&rtv, &atv, >=))
704 goto done;
705 ttv = atv;
706 timevalsub(&ttv, &rtv);
707 timeout = ttv.tv_sec > 24 * 60 * 60 ?
708 24 * 60 * 60 * hz : tvtohz(&ttv);
709 }
710
711start:
712 s = splhigh();
713 if (kq->kq_count == 0) {
714 if (timeout < 0) {
715 error = EWOULDBLOCK;
716 } else {
717 kq->kq_state |= KQ_SLEEP;
718 error = tsleep(kq, PSOCK | PCATCH, "kqread", timeout);
719 }
720 splx(s);
721 if (error == 0)
722 goto retry;
723 /* don't restart after signals... */
724 if (error == ERESTART)
725 error = EINTR;
726 else if (error == EWOULDBLOCK)
727 error = 0;
728 goto done;
729 }
730
731 /* JMM - This marker trick doesn't work with multiple threads */
732 TAILQ_INSERT_TAIL(&kq->kq_head, &marker, kn_tqe);
733 while (count) {
734 int maxkev = (count > KQ_NEVENTS) ? KQ_NEVENTS : count;
735 struct kevent kq_kev[maxkev];
736 struct kevent *kevp = kq_kev;
737 struct knote *kn;
738 int nkev = 0;
739
740 while (nkev < maxkev) {
741 kn = TAILQ_FIRST(&kq->kq_head);
742 TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
743 if (kn == &marker) {
744 if (count == maxevents)
745 goto retry;
746 break;
747 } else if (kn->kn_status & KN_DISABLED) {
748 kn->kn_status &= ~KN_QUEUED;
749 kq->kq_count--;
750 continue;
751 } else if ((kn->kn_flags & EV_ONESHOT) == 0 &&
752 kn->kn_fop->f_event(kn, 0) == 0) {
753 kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
754 kq->kq_count--;
755 continue;
756 }
757
758 *kevp = kn->kn_kevent;
759 kevp++;
760 nkev++;
761 count--;
762
763 if (kn->kn_flags & EV_ONESHOT) {
764 kn->kn_status &= ~KN_QUEUED;
765 kq->kq_count--;
766 splx(s);
767 kn->kn_fop->f_detach(kn);
768 knote_drop(kn, p);
769 s = splhigh();
770 } else if (kn->kn_flags & EV_CLEAR) {
771 kn->kn_data = 0;
772 kn->kn_fflags = 0;
773 kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
774 kq->kq_count--;
775 } else {
776 TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
777 }
778 }
779 splx(s);
780 error = copyout((caddr_t)kq_kev, (caddr_t)ulistp,
781 sizeof(struct kevent) * nkev);
782 if (kn == &marker)
783 goto done;
784 ulistp += nkev;
785 s = splhigh();
786 if (error)
787 break;
788 }
789 TAILQ_REMOVE(&kq->kq_head, &marker, kn_tqe);
790 splx(s);
791done:
792 *retval = maxevents - count;
793 return (error);
794}
795
796/*
797 * XXX
798 * This could be expanded to call kqueue_scan, if desired.
799 */
800/*ARGSUSED*/
801static int
802kqueue_read(struct file *fp, struct uio *uio, struct ucred *cred,
803 int flags, struct proc *p)
804{
805 return (ENXIO);
806}
807
808/*ARGSUSED*/
809static int
810kqueue_write(struct file *fp, struct uio *uio, struct ucred *cred,
811 int flags, struct proc *p)
812{
813 return (ENXIO);
814}
815
816/*ARGSUSED*/
817static int
818kqueue_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
819{
820 return (ENOTTY);
821}
822
823/*ARGSUSED*/
824static int
825kqueue_select(struct file *fp, int which, void *wql, struct proc *p)
826{
827 struct kqueue *kq = (struct kqueue *)fp->f_data;
828 int retnum = 0;
829 int s = splnet();
830
831 if (which == FREAD) {
832 if (kq->kq_count) {
833 retnum = 1;
834 } else {
835 selrecord(p, &kq->kq_sel, wql);
836 kq->kq_state |= KQ_SEL;
837 }
838 }
839 splx(s);
840 return (retnum);
841}
842
843/*ARGSUSED*/
844static int
845kqueue_close(struct file *fp, struct proc *p)
846{
847 struct kqueue *kq = (struct kqueue *)fp->f_data;
848 struct filedesc *fdp = p->p_fd;
849 struct knote **knp, *kn, *kn0;
850 int i;
851
852 for (i = 0; i < fdp->fd_knlistsize; i++) {
853 knp = &SLIST_FIRST(&fdp->fd_knlist[i]);
854 kn = *knp;
855 while (kn != NULL) {
856 kn0 = SLIST_NEXT(kn, kn_link);
857 if (kq == kn->kn_kq) {
858 kn->kn_fop->f_detach(kn);
859 fdrop(kn->kn_fp, p);
860 knote_free(kn);
861 *knp = kn0;
862 } else {
863 knp = &SLIST_NEXT(kn, kn_link);
864 }
865 kn = kn0;
866 }
867 }
868 if (fdp->fd_knhashmask != 0) {
869 for (i = 0; i < fdp->fd_knhashmask + 1; i++) {
870 knp = &SLIST_FIRST(&fdp->fd_knhash[i]);
871 kn = *knp;
872 while (kn != NULL) {
873 kn0 = SLIST_NEXT(kn, kn_link);
874 if (kq == kn->kn_kq) {
875 kn->kn_fop->f_detach(kn);
876 /* XXX non-fd release of kn->kn_ptr */
877 knote_free(kn);
878 *knp = kn0;
879 } else {
880 knp = &SLIST_NEXT(kn, kn_link);
881 }
882 kn = kn0;
883 }
884 }
885 }
886 _FREE(kq, M_KQUEUE);
887 fp->f_data = NULL;
888
889 return (0);
890}
891
892/*ARGSUSED*/
893static int
894kqueue_kqfilter(struct file *fp, struct knote *kn, struct proc *p)
895{
896 struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data;
897
898 if (kn->kn_filter != EVFILT_READ || (kq->kq_state & KQ_SEL))
899 return (1);
900
901 kn->kn_fop = &kqread_filtops;
902 KNOTE_ATTACH(&kq->kq_sel.si_note, kn);
903 return (0);
904}
905
906/*ARGSUSED*/
907int
908kqueue_stat(struct file *fp, struct stat *st, struct proc *p)
909{
910 struct kqueue *kq = (struct kqueue *)fp->f_data;
911
912 bzero((void *)st, sizeof(*st));
913 st->st_size = kq->kq_count;
914 st->st_blksize = sizeof(struct kevent);
915 st->st_mode = S_IFIFO;
916 return (0);
917}
918
919static void
920kqueue_wakeup(struct kqueue *kq)
921{
922
923 if (kq->kq_state & KQ_SLEEP) {
924 kq->kq_state &= ~KQ_SLEEP;
925 wakeup(kq);
926 }
927 if (kq->kq_state & KQ_SEL) {
928 // kq->kq_state &= ~KQ_SEL; /* remove for now */
929 selwakeup(&kq->kq_sel);
930 } else
931 KNOTE(&kq->kq_sel.si_note, 0);
932}
933
934void
935klist_init(struct klist *list)
936{
937 SLIST_INIT(list);
938}
939
940/*
941 * walk down a list of knotes, activating them if their event has triggered.
942 */
943void
944knote(struct klist *list, long hint)
945{
946 struct knote *kn;
947
948 SLIST_FOREACH(kn, list, kn_selnext)
949 if (kn->kn_fop->f_event(kn, hint))
950 KNOTE_ACTIVATE(kn);
951}
952
953/*
954 * attach a knote to the specified list. Return true if this is the first entry.
955 */
956int
957knote_attach(struct klist *list, struct knote *kn)
958{
959 int ret = SLIST_EMPTY(list);
960 SLIST_INSERT_HEAD(list, kn, kn_selnext);
961 return ret;
962}
963
964/*
965 * detach a knote from the specified list. Return true if that was the last entry.
966 */
967int
968knote_detach(struct klist *list, struct knote *kn)
969{
970 SLIST_REMOVE(list, kn, knote, kn_selnext);
971 return SLIST_EMPTY(list);
972}
973
974/*
975 * remove all knotes from a specified klist
976 */
977void
978knote_remove(struct proc *p, struct klist *list)
979{
980 struct knote *kn;
981
982 while ((kn = SLIST_FIRST(list)) != NULL) {
983 kn->kn_fop->f_detach(kn);
984 knote_drop(kn, p);
985 }
986}
987
988/*
989 * remove all knotes referencing a specified fd
990 */
991void
992knote_fdclose(struct proc *p, int fd)
993{
994 struct filedesc *fdp = p->p_fd;
995 struct klist *list = &fdp->fd_knlist[fd];
996
997 knote_remove(p, list);
998}
999
1000static void
1001knote_fdpattach(struct knote *kn, struct filedesc *fdp)
1002{
1003 struct klist *list;
1004 int size;
1005
1006 if (! kn->kn_fop->f_isfd) {
1007 if (fdp->fd_knhashmask == 0)
1008 fdp->fd_knhash = hashinit(KN_HASHSIZE, M_KQUEUE,
1009 &fdp->fd_knhashmask);
1010 list = &fdp->fd_knhash[KN_HASH(kn->kn_id, fdp->fd_knhashmask)];
1011 goto done;
1012 }
1013
1014 if (fdp->fd_knlistsize <= kn->kn_id) {
1015 size = fdp->fd_knlistsize;
1016 while (size <= kn->kn_id)
1017 size += KQEXTENT;
1018 MALLOC(list, struct klist *,
1019 size * sizeof(struct klist *), M_KQUEUE, M_WAITOK);
1020 bcopy((caddr_t)fdp->fd_knlist, (caddr_t)list,
1021 fdp->fd_knlistsize * sizeof(struct klist *));
1022 bzero((caddr_t)list +
1023 fdp->fd_knlistsize * sizeof(struct klist *),
1024 (size - fdp->fd_knlistsize) * sizeof(struct klist *));
1025 if (fdp->fd_knlist != NULL)
1026 FREE(fdp->fd_knlist, M_KQUEUE);
1027 fdp->fd_knlistsize = size;
1028 fdp->fd_knlist = list;
1029 }
1030 list = &fdp->fd_knlist[kn->kn_id];
1031done:
1032 SLIST_INSERT_HEAD(list, kn, kn_link);
1033 kn->kn_status = 0;
1034}
1035
1036/*
1037 * should be called at spl == 0, since we don't want to hold spl
1038 * while calling fdrop and free.
1039 */
1040static void
1041knote_drop(struct knote *kn, struct proc *p)
1042{
1043 struct filedesc *fdp = p->p_fd;
1044 struct klist *list;
1045
1046 if (kn->kn_fop->f_isfd)
1047 list = &fdp->fd_knlist[kn->kn_id];
1048 else
1049 list = &fdp->fd_knhash[KN_HASH(kn->kn_id, fdp->fd_knhashmask)];
1050
1051 SLIST_REMOVE(list, kn, knote, kn_link);
1052 if (kn->kn_status & KN_QUEUED)
1053 knote_dequeue(kn);
1054 if (kn->kn_fop->f_isfd)
1055 fdrop(kn->kn_fp, p);
1056 knote_free(kn);
1057}
1058
1059
1060static void
1061knote_enqueue(struct knote *kn)
1062{
1063 struct kqueue *kq = kn->kn_kq;
1064 int s = splhigh();
1065
1066 KASSERT((kn->kn_status & KN_QUEUED) == 0, ("knote already queued"));
1067
1068 TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
1069 kn->kn_status |= KN_QUEUED;
1070 kq->kq_count++;
1071 splx(s);
1072 kqueue_wakeup(kq);
1073}
1074
1075static void
1076knote_dequeue(struct knote *kn)
1077{
1078 struct kqueue *kq = kn->kn_kq;
1079 int s = splhigh();
1080
1081 KASSERT(kn->kn_status & KN_QUEUED, ("knote not queued"));
1082
1083 TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
1084 kn->kn_status &= ~KN_QUEUED;
1085 kq->kq_count--;
1086 splx(s);
1087}
1088
1089void
1090knote_init(void)
1091{
1092 knote_zone = zinit(sizeof(struct knote), 8192*sizeof(struct knote), 8192, "knote zone");
1093}
1094SYSINIT(knote, SI_SUB_PSEUDO, SI_ORDER_ANY, knote_init, NULL)
1095
1096static struct knote *
1097knote_alloc(void)
1098{
1099 return ((struct knote *)zalloc(knote_zone));
1100}
1101
1102static void
1103knote_free(struct knote *kn)
1104{
1105 zfree(knote_zone, (vm_offset_t)kn);
1106}
1107
1c79356b
A
1108#include <sys/param.h>
1109#include <sys/socket.h>
1110#include <sys/protosw.h>
1111#include <sys/domain.h>
1112#include <sys/mbuf.h>
1113#include <sys/kern_event.h>
1114#include <sys/malloc.h>
9bccf70c
A
1115#include <sys/sys_domain.h>
1116#include <sys/syslog.h>
1c79356b
A
1117
1118
1119int raw_usrreq();
1120struct pr_usrreqs event_usrreqs;
1121
1122struct protosw eventsw[] = {
1123 {
1124 SOCK_RAW, &systemdomain, SYSPROTO_EVENT, PR_ATOMIC,
1125 0, 0, 0, 0,
1126 0,
1127 0, 0, 0, 0,
1128 0, &event_usrreqs
1129 }
1130};
1131
1132static
1133struct kern_event_head kern_event_head;
1134
1135static u_long static_event_id = 0;
1136
9bccf70c
A
1137/*
1138 * Install the protosw's for the NKE manager. Invoked at
1139 * extension load time
1140 */
1141int
1142kern_event_init(void)
1143{
1144 int retval;
1145
1146 if ((retval = net_add_proto(eventsw, &systemdomain)) == 0)
1147 return(KERN_SUCCESS);
1148
1149 log(LOG_WARNING, "Can't install kernel events protocol (%d)\n", retval);
1150 return(retval);
1151}
1152
1c79356b
A
1153int kev_attach(struct socket *so, int proto, struct proc *p)
1154{
1155 int error;
1156 struct kern_event_pcb *ev_pcb;
1157
55e303ae
A
1158 error = soreserve(so, KEV_SNDSPACE, KEV_RECVSPACE);
1159 if (error)
1160 return error;
1161
1c79356b
A
1162 ev_pcb = _MALLOC(sizeof(struct kern_event_pcb), M_PCB, M_WAITOK);
1163 if (ev_pcb == 0)
1164 return ENOBUFS;
1165
1166 ev_pcb->ev_socket = so;
1167 ev_pcb->vendor_code_filter = 0xffffffff;
1168
1169 so->so_pcb = (caddr_t) ev_pcb;
1170 LIST_INSERT_HEAD(&kern_event_head, ev_pcb, ev_link);
1c79356b
A
1171
1172 return 0;
1173}
1174
1175
1176int kev_detach(struct socket *so)
1177{
1178 struct kern_event_pcb *ev_pcb = (struct kern_event_pcb *) so->so_pcb;
1179
55e303ae
A
1180 if (ev_pcb != 0) {
1181 LIST_REMOVE(ev_pcb, ev_link);
1182 FREE(ev_pcb, M_PCB);
1183 so->so_pcb = 0;
1184 }
1c79356b
A
1185
1186 return 0;
1187}
1188
1189
1190int kev_post_msg(struct kev_msg *event_msg)
1191{
1192 struct mbuf *m, *m2;
1193 struct kern_event_pcb *ev_pcb;
1194 struct kern_event_msg *ev;
1195 char *tmp;
1196 int total_size;
1197 int i;
1198
1199
1200 m = m_get(M_DONTWAIT, MT_DATA);
1201 if (m == 0)
1202 return ENOBUFS;
1203
1204 ev = mtod(m, struct kern_event_msg *);
1205 total_size = KEV_MSG_HEADER_SIZE;
1206
1207 tmp = (char *) &ev->event_data[0];
1208 for (i = 0; i < 5; i++) {
1209 if (event_msg->dv[i].data_length == 0)
1210 break;
1211
1212 total_size += event_msg->dv[i].data_length;
1213 bcopy(event_msg->dv[i].data_ptr, tmp,
1214 event_msg->dv[i].data_length);
1215 tmp += event_msg->dv[i].data_length;
1216 }
1217
1218
1219 ev->id = ++static_event_id;
1220 ev->total_size = total_size;
1221 ev->vendor_code = event_msg->vendor_code;
1222 ev->kev_class = event_msg->kev_class;
1223 ev->kev_subclass = event_msg->kev_subclass;
1224 ev->event_code = event_msg->event_code;
1225
1226 m->m_len = total_size;
1c79356b
A
1227 for (ev_pcb = LIST_FIRST(&kern_event_head);
1228 ev_pcb;
1229 ev_pcb = LIST_NEXT(ev_pcb, ev_link)) {
1230
1231 if (ev_pcb->vendor_code_filter != KEV_ANY_VENDOR) {
1232 if (ev_pcb->vendor_code_filter != ev->vendor_code)
1233 continue;
1234
1235 if (ev_pcb->class_filter != KEV_ANY_CLASS) {
1236 if (ev_pcb->class_filter != ev->kev_class)
1237 continue;
1238
1239 if ((ev_pcb->subclass_filter != KEV_ANY_SUBCLASS) &&
1240 (ev_pcb->subclass_filter != ev->kev_subclass))
1241 continue;
1242 }
1243 }
1244
1245 m2 = m_copym(m, 0, m->m_len, M_NOWAIT);
1246 if (m2 == 0) {
1247 m_free(m);
1248 return ENOBUFS;
1249 }
1250
1251 sbappendrecord(&ev_pcb->ev_socket->so_rcv, m2);
1252 sorwakeup(ev_pcb->ev_socket);
1253 }
1254
1255
1256 m_free(m);
1257 return 0;
1258}
1259
1260
1261int kev_control(so, cmd, data, ifp, p)
1262 struct socket *so;
1263 u_long cmd;
1264 caddr_t data;
1265 register struct ifnet *ifp;
1266 struct proc *p;
1267{
1268 struct kev_request *kev_req = (struct kev_request *) data;
1269 int stat = 0;
1270 struct kern_event_pcb *ev_pcb;
1271 u_long *id_value = (u_long *) data;
1272
1273
1274 switch (cmd) {
1275
1276 case SIOCGKEVID:
1277 *id_value = static_event_id;
1278 break;
1279
1280 case SIOCSKEVFILT:
1281 ev_pcb = (struct kern_event_pcb *) so->so_pcb;
1282 ev_pcb->vendor_code_filter = kev_req->vendor_code;
1283 ev_pcb->class_filter = kev_req->kev_class;
1284 ev_pcb->subclass_filter = kev_req->kev_subclass;
1285 break;
1286
1287 case SIOCGKEVFILT:
1288 ev_pcb = (struct kern_event_pcb *) so->so_pcb;
1289 kev_req->vendor_code = ev_pcb->vendor_code_filter;
1290 kev_req->kev_class = ev_pcb->class_filter;
1291 kev_req->kev_subclass = ev_pcb->subclass_filter;
1292 break;
1293
1294 default:
1295 return EOPNOTSUPP;
1296 }
1297
1298 return 0;
1299}
1300
1301
1302struct pr_usrreqs event_usrreqs = {
1303 pru_abort_notsupp, pru_accept_notsupp, kev_attach, pru_bind_notsupp, pru_connect_notsupp,
1304 pru_connect2_notsupp, kev_control, kev_detach, pru_disconnect_notsupp,
1305 pru_listen_notsupp, pru_peeraddr_notsupp, pru_rcvd_notsupp, pru_rcvoob_notsupp,
1306 pru_send_notsupp, pru_sense_null, pru_shutdown_notsupp, pru_sockaddr_notsupp,
1307 pru_sosend_notsupp, soreceive, sopoll
1308};
1309
1310
1311