This source file includes following definitions.
- kqueue_init
- filt_fileattach
- kqueue_kqfilter
- filt_kqdetach
- filt_kqueue
- filt_procattach
- filt_procdetach
- filt_proc
- filt_timerexpire
- filt_timerattach
- filt_timerdetach
- filt_timer
- filt_seltrue
- sys_kqueue
- sys_kevent
- kqueue_register
- kqueue_scan
- kqueue_read
- kqueue_write
- kqueue_ioctl
- kqueue_poll
- kqueue_stat
- kqueue_close
- kqueue_wakeup
- knote
- knote_remove
- knote_fdclose
- knote_attach
- knote_drop
- knote_enqueue
- knote_dequeue
- klist_invalidate
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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/malloc.h>
36 #include <sys/unistd.h>
37 #include <sys/file.h>
38 #include <sys/filedesc.h>
39 #include <sys/fcntl.h>
40 #include <sys/selinfo.h>
41 #include <sys/queue.h>
42 #include <sys/event.h>
43 #include <sys/eventvar.h>
44 #include <sys/pool.h>
45 #include <sys/protosw.h>
46 #include <sys/socket.h>
47 #include <sys/socketvar.h>
48 #include <sys/stat.h>
49 #include <sys/uio.h>
50 #include <sys/mount.h>
51 #include <sys/poll.h>
52 #include <sys/syscallargs.h>
53 #include <sys/timeout.h>
54
55 int kqueue_scan(struct file *fp, int maxevents,
56 struct kevent *ulistp, const struct timespec *timeout,
57 struct proc *p, int *retval);
58
59 int kqueue_read(struct file *fp, off_t *poff, struct uio *uio,
60 struct ucred *cred);
61 int kqueue_write(struct file *fp, off_t *poff, struct uio *uio,
62 struct ucred *cred);
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 kqueue_read,
73 kqueue_write,
74 kqueue_ioctl,
75 kqueue_poll,
76 kqueue_kqfilter,
77 kqueue_stat,
78 kqueue_close
79 };
80
81 void knote_attach(struct knote *kn, struct filedesc *fdp);
82 void knote_drop(struct knote *kn, struct proc *p, struct filedesc *fdp);
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
99 struct filterops kqread_filtops =
100 { 1, NULL, filt_kqdetach, filt_kqueue };
101 struct filterops proc_filtops =
102 { 0, filt_procattach, filt_procdetach, filt_proc };
103 struct filterops file_filtops =
104 { 1, filt_fileattach, NULL, NULL };
105 struct filterops timer_filtops =
106 { 0, filt_timerattach, filt_timerdetach, filt_timer };
107
108 struct pool knote_pool;
109 struct pool kqueue_pool;
110 int kq_ntimeouts = 0;
111 int kq_timeoutmax = (4 * 1024);
112
113 #define KNOTE_ACTIVATE(kn) do { \
114 kn->kn_status |= KN_ACTIVE; \
115 if ((kn->kn_status & (KN_QUEUED | KN_DISABLED)) == 0) \
116 knote_enqueue(kn); \
117 } while(0)
118
119 #define KN_HASHSIZE 64
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
129
130 struct filterops *sysfilt_ops[] = {
131 &file_filtops,
132 &file_filtops,
133 NULL,
134 &file_filtops,
135 &proc_filtops,
136 &sig_filtops,
137 &timer_filtops,
138 };
139
140 void kqueue_init(void);
141
142 void
143 kqueue_init(void)
144 {
145
146 pool_init(&kqueue_pool, sizeof(struct kqueue), 0, 0, 0, "kqueuepl",
147 &pool_allocator_nointr);
148 pool_init(&knote_pool, sizeof(struct knote), 0, 0, 0, "knotepl",
149 &pool_allocator_nointr);
150 }
151
152 int
153 filt_fileattach(struct knote *kn)
154 {
155 struct file *fp = kn->kn_fp;
156
157 return ((*fp->f_ops->fo_kqfilter)(fp, kn));
158 }
159
160 int
161 kqueue_kqfilter(struct file *fp, struct knote *kn)
162 {
163 struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data;
164
165 if (kn->kn_filter != EVFILT_READ)
166 return (1);
167
168 kn->kn_fop = &kqread_filtops;
169 SLIST_INSERT_HEAD(&kq->kq_sel.si_note, kn, kn_selnext);
170 return (0);
171 }
172
173 void
174 filt_kqdetach(struct knote *kn)
175 {
176 struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data;
177
178 SLIST_REMOVE(&kq->kq_sel.si_note, kn, knote, kn_selnext);
179 }
180
181
182 int
183 filt_kqueue(struct knote *kn, long hint)
184 {
185 struct kqueue *kq = (struct kqueue *)kn->kn_fp->f_data;
186
187 kn->kn_data = kq->kq_count;
188 return (kn->kn_data > 0);
189 }
190
191 int
192 filt_procattach(struct knote *kn)
193 {
194 struct proc *p;
195
196 p = pfind(kn->kn_id);
197 if (p == NULL)
198 return (ESRCH);
199
200
201
202
203
204 if ((p->p_cred->p_ruid != curproc->p_cred->p_ruid ||
205 (p->p_flag & P_SUGID)) && suser(curproc, 0) != 0)
206 return (EACCES);
207
208 kn->kn_ptr.p_proc = p;
209 kn->kn_flags |= EV_CLEAR;
210
211
212
213
214 if (kn->kn_flags & EV_FLAG1) {
215 kn->kn_data = kn->kn_sdata;
216 kn->kn_fflags = NOTE_CHILD;
217 kn->kn_flags &= ~EV_FLAG1;
218 }
219
220
221 SLIST_INSERT_HEAD(&p->p_klist, kn, kn_selnext);
222
223 return (0);
224 }
225
226
227
228
229
230
231
232
233
234 void
235 filt_procdetach(struct knote *kn)
236 {
237 struct proc *p = kn->kn_ptr.p_proc;
238
239 if (kn->kn_status & KN_DETACHED)
240 return;
241
242
243 SLIST_REMOVE(&p->p_klist, kn, knote, kn_selnext);
244 }
245
246 int
247 filt_proc(struct knote *kn, long hint)
248 {
249 u_int event;
250
251
252
253
254 event = (u_int)hint & NOTE_PCTRLMASK;
255
256
257
258
259 if (kn->kn_sfflags & event)
260 kn->kn_fflags |= event;
261
262
263
264
265 if (event == NOTE_EXIT) {
266 kn->kn_status |= KN_DETACHED;
267 kn->kn_flags |= (EV_EOF | EV_ONESHOT);
268 return (1);
269 }
270
271
272
273
274
275
276 if ((event == NOTE_FORK) && (kn->kn_sfflags & NOTE_TRACK)) {
277 struct kevent kev;
278 int error;
279
280
281
282
283 kev.ident = hint & NOTE_PDATAMASK;
284 kev.filter = kn->kn_filter;
285 kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1;
286 kev.fflags = kn->kn_sfflags;
287 kev.data = kn->kn_id;
288 kev.udata = kn->kn_kevent.udata;
289 error = kqueue_register(kn->kn_kq, &kev, NULL);
290 if (error)
291 kn->kn_fflags |= NOTE_TRACKERR;
292 }
293
294 return (kn->kn_fflags != 0);
295 }
296
297 void
298 filt_timerexpire(void *knx)
299 {
300 struct knote *kn = knx;
301 struct timeval tv;
302 int tticks;
303
304 kn->kn_data++;
305 KNOTE_ACTIVATE(kn);
306
307 if ((kn->kn_flags & EV_ONESHOT) == 0) {
308 tv.tv_sec = kn->kn_sdata / 1000;
309 tv.tv_usec = (kn->kn_sdata % 1000) * 1000;
310 tticks = tvtohz(&tv);
311 timeout_add((struct timeout *)kn->kn_hook, tticks);
312 }
313 }
314
315
316
317
318
319 int
320 filt_timerattach(struct knote *kn)
321 {
322 struct timeout *to;
323 struct timeval tv;
324 int tticks;
325
326 if (kq_ntimeouts > kq_timeoutmax)
327 return (ENOMEM);
328 kq_ntimeouts++;
329
330 tv.tv_sec = kn->kn_sdata / 1000;
331 tv.tv_usec = (kn->kn_sdata % 1000) * 1000;
332 tticks = tvtohz(&tv);
333
334 kn->kn_flags |= EV_CLEAR;
335 MALLOC(to, struct timeout *, sizeof(*to), M_KEVENT, 0);
336 timeout_set(to, filt_timerexpire, kn);
337 timeout_add(to, tticks);
338 kn->kn_hook = to;
339
340 return (0);
341 }
342
343 void
344 filt_timerdetach(struct knote *kn)
345 {
346 struct timeout *to;
347
348 to = (struct timeout *)kn->kn_hook;
349 timeout_del(to);
350 FREE(to, M_KEVENT);
351 kq_ntimeouts--;
352 }
353
354 int
355 filt_timer(struct knote *kn, long hint)
356 {
357 return (kn->kn_data != 0);
358 }
359
360
361
362
363
364
365
366 int
367 filt_seltrue(struct knote *kn, long hint)
368 {
369
370
371
372
373
374
375 kn->kn_data = 0;
376 return (1);
377 }
378
379 int
380 sys_kqueue(struct proc *p, void *v, register_t *retval)
381 {
382 struct filedesc *fdp = p->p_fd;
383 struct kqueue *kq;
384 struct file *fp;
385 int fd, error;
386
387 error = falloc(p, &fp, &fd);
388 if (error)
389 return (error);
390 fp->f_flag = FREAD | FWRITE;
391 fp->f_type = DTYPE_KQUEUE;
392 fp->f_ops = &kqueueops;
393 kq = pool_get(&kqueue_pool, PR_WAITOK);
394 bzero(kq, sizeof(*kq));
395 TAILQ_INIT(&kq->kq_head);
396 fp->f_data = (caddr_t)kq;
397 *retval = fd;
398 if (fdp->fd_knlistsize < 0)
399 fdp->fd_knlistsize = 0;
400 kq->kq_fdp = fdp;
401 FILE_SET_MATURE(fp);
402 return (0);
403 }
404
405 int
406 sys_kevent(struct proc *p, void *v, register_t *retval)
407 {
408 struct filedesc* fdp = p->p_fd;
409 struct sys_kevent_args
410
411
412
413
414
415
416 *uap = v;
417 struct kevent *kevp;
418 struct kqueue *kq;
419 struct file *fp;
420 struct timespec ts;
421 int i, n, nerrors, error;
422
423 if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL ||
424 (fp->f_type != DTYPE_KQUEUE))
425 return (EBADF);
426
427 FREF(fp);
428
429 if (SCARG(uap, timeout) != NULL) {
430 error = copyin(SCARG(uap, timeout), &ts, sizeof(ts));
431 if (error)
432 goto done;
433 SCARG(uap, timeout) = &ts;
434 }
435
436 kq = (struct kqueue *)fp->f_data;
437 nerrors = 0;
438
439 while (SCARG(uap, nchanges) > 0) {
440 n = SCARG(uap, nchanges) > KQ_NEVENTS
441 ? KQ_NEVENTS : SCARG(uap, nchanges);
442 error = copyin(SCARG(uap, changelist), kq->kq_kev,
443 n * sizeof(struct kevent));
444 if (error)
445 goto done;
446 for (i = 0; i < n; i++) {
447 kevp = &kq->kq_kev[i];
448 kevp->flags &= ~EV_SYSFLAGS;
449 error = kqueue_register(kq, kevp, p);
450 if (error) {
451 if (SCARG(uap, nevents) != 0) {
452 kevp->flags = EV_ERROR;
453 kevp->data = error;
454 (void) copyout((caddr_t)kevp,
455 (caddr_t)SCARG(uap, eventlist),
456 sizeof(*kevp));
457 SCARG(uap, eventlist)++;
458 SCARG(uap, nevents)--;
459 nerrors++;
460 } else {
461 goto done;
462 }
463 }
464 }
465 SCARG(uap, nchanges) -= n;
466 SCARG(uap, changelist) += n;
467 }
468 if (nerrors) {
469 *retval = nerrors;
470 error = 0;
471 goto done;
472 }
473
474 error = kqueue_scan(fp, SCARG(uap, nevents), SCARG(uap, eventlist),
475 SCARG(uap, timeout), p, &n);
476 *retval = n;
477 done:
478 FRELE(fp);
479 return (error);
480 }
481
482 int
483 kqueue_register(struct kqueue *kq, struct kevent *kev, struct proc *p)
484 {
485 struct filedesc *fdp = kq->kq_fdp;
486 struct filterops *fops = NULL;
487 struct file *fp = NULL;
488 struct knote *kn = NULL;
489 int s, error = 0;
490
491 if (kev->filter < 0) {
492 if (kev->filter + EVFILT_SYSCOUNT < 0)
493 return (EINVAL);
494 fops = sysfilt_ops[~kev->filter];
495 }
496
497 if (fops == NULL) {
498
499
500
501
502
503 return (EINVAL);
504 }
505
506 if (fops->f_isfd) {
507
508 if ((fp = fd_getfile(fdp, kev->ident)) == NULL)
509 return (EBADF);
510 FREF(fp);
511 fp->f_count++;
512
513 if (kev->ident < fdp->fd_knlistsize) {
514 SLIST_FOREACH(kn, &fdp->fd_knlist[kev->ident], kn_link)
515 if (kq == kn->kn_kq &&
516 kev->filter == kn->kn_filter)
517 break;
518 }
519 } else {
520 if (fdp->fd_knhashmask != 0) {
521 struct klist *list;
522
523 list = &fdp->fd_knhash[
524 KN_HASH((u_long)kev->ident, fdp->fd_knhashmask)];
525 SLIST_FOREACH(kn, list, kn_link)
526 if (kev->ident == kn->kn_id &&
527 kq == kn->kn_kq &&
528 kev->filter == kn->kn_filter)
529 break;
530 }
531 }
532
533 if (kn == NULL && ((kev->flags & EV_ADD) == 0)) {
534 error = ENOENT;
535 goto done;
536 }
537
538
539
540
541 if (kev->flags & EV_ADD) {
542
543 if (kn == NULL) {
544 kn = knote_alloc();
545 if (kn == NULL) {
546 error = ENOMEM;
547 goto done;
548 }
549 kn->kn_fp = fp;
550 kn->kn_kq = kq;
551 kn->kn_fop = fops;
552
553
554
555
556
557 if (fp != NULL)
558 FRELE(fp);
559 fp = NULL;
560
561 kn->kn_sfflags = kev->fflags;
562 kn->kn_sdata = kev->data;
563 kev->fflags = 0;
564 kev->data = 0;
565 kn->kn_kevent = *kev;
566
567 knote_attach(kn, fdp);
568 if ((error = fops->f_attach(kn)) != 0) {
569 knote_drop(kn, p, fdp);
570 goto done;
571 }
572 } else {
573
574
575
576
577
578 kn->kn_sfflags = kev->fflags;
579 kn->kn_sdata = kev->data;
580 kn->kn_kevent.udata = kev->udata;
581 }
582
583 s = splhigh();
584 if (kn->kn_fop->f_event(kn, 0))
585 KNOTE_ACTIVATE(kn);
586 splx(s);
587
588 } else if (kev->flags & EV_DELETE) {
589 kn->kn_fop->f_detach(kn);
590 knote_drop(kn, p, p->p_fd);
591 goto done;
592 }
593
594 if ((kev->flags & EV_DISABLE) &&
595 ((kn->kn_status & KN_DISABLED) == 0)) {
596 s = splhigh();
597 kn->kn_status |= KN_DISABLED;
598 splx(s);
599 }
600
601 if ((kev->flags & EV_ENABLE) && (kn->kn_status & KN_DISABLED)) {
602 s = splhigh();
603 kn->kn_status &= ~KN_DISABLED;
604 if ((kn->kn_status & KN_ACTIVE) &&
605 ((kn->kn_status & KN_QUEUED) == 0))
606 knote_enqueue(kn);
607 splx(s);
608 }
609
610 done:
611 if (fp != NULL)
612 closef(fp, p);
613 return (error);
614 }
615
616 int
617 kqueue_scan(struct file *fp, int maxevents, struct kevent *ulistp,
618 const struct timespec *tsp, struct proc *p, int *retval)
619 {
620 struct kqueue *kq = (struct kqueue *)fp->f_data;
621 struct kevent *kevp;
622 struct timeval atv, rtv, ttv;
623 struct knote *kn, marker;
624 int s, count, timeout, nkev = 0, error = 0;
625
626 count = maxevents;
627 if (count == 0)
628 goto done;
629
630 if (tsp != NULL) {
631 TIMESPEC_TO_TIMEVAL(&atv, tsp);
632 if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) {
633
634 timeout = -1;
635 goto start;
636 }
637 if (itimerfix(&atv)) {
638 error = EINVAL;
639 goto done;
640 }
641
642 timeout = atv.tv_sec > 24 * 60 * 60 ?
643 24 * 60 * 60 * hz : tvtohz(&atv);
644
645 getmicrouptime(&rtv);
646 timeradd(&atv, &rtv, &atv);
647 } else {
648 atv.tv_sec = 0;
649 atv.tv_usec = 0;
650 timeout = 0;
651 }
652 goto start;
653
654 retry:
655 if (atv.tv_sec || atv.tv_usec) {
656 getmicrouptime(&rtv);
657 if (timercmp(&rtv, &atv, >=))
658 goto done;
659 ttv = atv;
660 timersub(&ttv, &rtv, &ttv);
661 timeout = ttv.tv_sec > 24 * 60 * 60 ?
662 24 * 60 * 60 * hz : tvtohz(&ttv);
663 }
664
665 start:
666 kevp = kq->kq_kev;
667 s = splhigh();
668 if (kq->kq_count == 0) {
669 if (timeout < 0) {
670 error = EWOULDBLOCK;
671 } else {
672 kq->kq_state |= KQ_SLEEP;
673 error = tsleep(kq, PSOCK | PCATCH, "kqread", timeout);
674 }
675 splx(s);
676 if (error == 0)
677 goto retry;
678
679 if (error == ERESTART)
680 error = EINTR;
681 else if (error == EWOULDBLOCK)
682 error = 0;
683 goto done;
684 }
685
686 TAILQ_INSERT_TAIL(&kq->kq_head, &marker, kn_tqe);
687 while (count) {
688 kn = TAILQ_FIRST(&kq->kq_head);
689 TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
690 if (kn == &marker) {
691 splx(s);
692 if (count == maxevents)
693 goto retry;
694 goto done;
695 }
696 if (kn->kn_status & KN_DISABLED) {
697 kn->kn_status &= ~KN_QUEUED;
698 kq->kq_count--;
699 continue;
700 }
701 if ((kn->kn_flags & EV_ONESHOT) == 0 &&
702 kn->kn_fop->f_event(kn, 0) == 0) {
703 kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
704 kq->kq_count--;
705 continue;
706 }
707 *kevp = kn->kn_kevent;
708 kevp++;
709 nkev++;
710 if (kn->kn_flags & EV_ONESHOT) {
711 kn->kn_status &= ~KN_QUEUED;
712 kq->kq_count--;
713 splx(s);
714 kn->kn_fop->f_detach(kn);
715 knote_drop(kn, p, p->p_fd);
716 s = splhigh();
717 } else if (kn->kn_flags & EV_CLEAR) {
718 kn->kn_data = 0;
719 kn->kn_fflags = 0;
720 kn->kn_status &= ~(KN_QUEUED | KN_ACTIVE);
721 kq->kq_count--;
722 } else {
723 TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
724 }
725 count--;
726 if (nkev == KQ_NEVENTS) {
727 splx(s);
728 error = copyout((caddr_t)&kq->kq_kev, (caddr_t)ulistp,
729 sizeof(struct kevent) * nkev);
730 ulistp += nkev;
731 nkev = 0;
732 kevp = kq->kq_kev;
733 s = splhigh();
734 if (error)
735 break;
736 }
737 }
738 TAILQ_REMOVE(&kq->kq_head, &marker, kn_tqe);
739 splx(s);
740 done:
741 if (nkev != 0)
742 error = copyout((caddr_t)&kq->kq_kev, (caddr_t)ulistp,
743 sizeof(struct kevent) * nkev);
744 *retval = maxevents - count;
745 return (error);
746 }
747
748
749
750
751
752
753 int
754 kqueue_read(struct file *fp, off_t *poff, struct uio *uio, struct ucred *cred)
755 {
756 return (ENXIO);
757 }
758
759
760 int
761 kqueue_write(struct file *fp, off_t *poff, struct uio *uio, struct ucred *cred)
762
763 {
764 return (ENXIO);
765 }
766
767
768 int
769 kqueue_ioctl(struct file *fp, u_long com, caddr_t data, struct proc *p)
770 {
771 return (ENOTTY);
772 }
773
774
775 int
776 kqueue_poll(struct file *fp, int events, struct proc *p)
777 {
778 struct kqueue *kq = (struct kqueue *)fp->f_data;
779 int revents = 0;
780 int s = splhigh();
781
782 if (events & (POLLIN | POLLRDNORM)) {
783 if (kq->kq_count) {
784 revents |= events & (POLLIN | POLLRDNORM);
785 } else {
786 selrecord(p, &kq->kq_sel);
787 kq->kq_state |= KQ_SEL;
788 }
789 }
790 splx(s);
791 return (revents);
792 }
793
794
795 int
796 kqueue_stat(struct file *fp, struct stat *st, struct proc *p)
797 {
798 struct kqueue *kq = (struct kqueue *)fp->f_data;
799
800 bzero((void *)st, sizeof(*st));
801 st->st_size = kq->kq_count;
802 st->st_blksize = sizeof(struct kevent);
803 st->st_mode = S_IFIFO;
804 return (0);
805 }
806
807
808 int
809 kqueue_close(struct file *fp, struct proc *p)
810 {
811 struct kqueue *kq = (struct kqueue *)fp->f_data;
812 struct filedesc *fdp = p->p_fd;
813 struct knote **knp, *kn, *kn0;
814 int i;
815
816 for (i = 0; i < fdp->fd_knlistsize; i++) {
817 knp = &SLIST_FIRST(&fdp->fd_knlist[i]);
818 kn = *knp;
819 while (kn != NULL) {
820 kn0 = SLIST_NEXT(kn, kn_link);
821 if (kq == kn->kn_kq) {
822 FREF(kn->kn_fp);
823 kn->kn_fop->f_detach(kn);
824 closef(kn->kn_fp, p);
825 knote_free(kn);
826 *knp = kn0;
827 } else {
828 knp = &SLIST_NEXT(kn, kn_link);
829 }
830 kn = kn0;
831 }
832 }
833 if (fdp->fd_knhashmask != 0) {
834 for (i = 0; i < fdp->fd_knhashmask + 1; i++) {
835 knp = &SLIST_FIRST(&fdp->fd_knhash[i]);
836 kn = *knp;
837 while (kn != NULL) {
838 kn0 = SLIST_NEXT(kn, kn_link);
839 if (kq == kn->kn_kq) {
840 kn->kn_fop->f_detach(kn);
841
842 knote_free(kn);
843 *knp = kn0;
844 } else {
845 knp = &SLIST_NEXT(kn, kn_link);
846 }
847 kn = kn0;
848 }
849 }
850 }
851 pool_put(&kqueue_pool, kq);
852 fp->f_data = NULL;
853
854 return (0);
855 }
856
857 void
858 kqueue_wakeup(struct kqueue *kq)
859 {
860
861 if (kq->kq_state & KQ_SLEEP) {
862 kq->kq_state &= ~KQ_SLEEP;
863 wakeup(kq);
864 }
865 if (kq->kq_state & KQ_SEL) {
866 kq->kq_state &= ~KQ_SEL;
867 selwakeup(&kq->kq_sel);
868 }
869 KNOTE(&kq->kq_sel.si_note, 0);
870 }
871
872
873
874
875 void
876 knote(struct klist *list, long hint)
877 {
878 struct knote *kn;
879
880 SLIST_FOREACH(kn, list, kn_selnext)
881 if (kn->kn_fop->f_event(kn, hint))
882 KNOTE_ACTIVATE(kn);
883 }
884
885
886
887
888 void
889 knote_remove(struct proc *p, struct klist *list)
890 {
891 struct knote *kn;
892
893 while ((kn = SLIST_FIRST(list)) != NULL) {
894 kn->kn_fop->f_detach(kn);
895 knote_drop(kn, p, p->p_fd);
896 }
897 }
898
899
900
901
902 void
903 knote_fdclose(struct proc *p, int fd)
904 {
905 struct filedesc *fdp = p->p_fd;
906 struct klist *list = &fdp->fd_knlist[fd];
907
908 knote_remove(p, list);
909 }
910
911 void
912 knote_attach(struct knote *kn, struct filedesc *fdp)
913 {
914 struct klist *list;
915 int size;
916
917 if (! kn->kn_fop->f_isfd) {
918 if (fdp->fd_knhashmask == 0)
919 fdp->fd_knhash = hashinit(KN_HASHSIZE, M_TEMP,
920 M_WAITOK, &fdp->fd_knhashmask);
921 list = &fdp->fd_knhash[KN_HASH(kn->kn_id, fdp->fd_knhashmask)];
922 goto done;
923 }
924
925 if (fdp->fd_knlistsize <= kn->kn_id) {
926 size = fdp->fd_knlistsize;
927 while (size <= kn->kn_id)
928 size += KQEXTENT;
929 list = malloc(size * sizeof(struct klist *), M_TEMP, M_WAITOK);
930 bcopy((caddr_t)fdp->fd_knlist, (caddr_t)list,
931 fdp->fd_knlistsize * sizeof(struct klist *));
932 bzero((caddr_t)list +
933 fdp->fd_knlistsize * sizeof(struct klist *),
934 (size - fdp->fd_knlistsize) * sizeof(struct klist *));
935 if (fdp->fd_knlist != NULL)
936 free(fdp->fd_knlist, M_TEMP);
937 fdp->fd_knlistsize = size;
938 fdp->fd_knlist = list;
939 }
940 list = &fdp->fd_knlist[kn->kn_id];
941 done:
942 SLIST_INSERT_HEAD(list, kn, kn_link);
943 kn->kn_status = 0;
944 }
945
946
947
948
949
950 void
951 knote_drop(struct knote *kn, struct proc *p, struct filedesc *fdp)
952 {
953 struct klist *list;
954
955 if (kn->kn_fop->f_isfd)
956 list = &fdp->fd_knlist[kn->kn_id];
957 else
958 list = &fdp->fd_knhash[KN_HASH(kn->kn_id, fdp->fd_knhashmask)];
959
960 SLIST_REMOVE(list, kn, knote, kn_link);
961 if (kn->kn_status & KN_QUEUED)
962 knote_dequeue(kn);
963 if (kn->kn_fop->f_isfd) {
964 FREF(kn->kn_fp);
965 closef(kn->kn_fp, p);
966 }
967 knote_free(kn);
968 }
969
970
971 void
972 knote_enqueue(struct knote *kn)
973 {
974 struct kqueue *kq = kn->kn_kq;
975 int s = splhigh();
976
977 KASSERT((kn->kn_status & KN_QUEUED) == 0);
978
979 TAILQ_INSERT_TAIL(&kq->kq_head, kn, kn_tqe);
980 kn->kn_status |= KN_QUEUED;
981 kq->kq_count++;
982 splx(s);
983 kqueue_wakeup(kq);
984 }
985
986 void
987 knote_dequeue(struct knote *kn)
988 {
989 struct kqueue *kq = kn->kn_kq;
990 int s = splhigh();
991
992 KASSERT(kn->kn_status & KN_QUEUED);
993
994 TAILQ_REMOVE(&kq->kq_head, kn, kn_tqe);
995 kn->kn_status &= ~KN_QUEUED;
996 kq->kq_count--;
997 splx(s);
998 }
999
1000 void
1001 klist_invalidate(struct klist *list)
1002 {
1003 struct knote *kn;
1004
1005 SLIST_FOREACH(kn, list, kn_selnext) {
1006 kn->kn_status |= KN_DETACHED;
1007 kn->kn_flags |= EV_EOF | EV_ONESHOT;
1008 }
1009 }