kern_event.c (1c0336c1c15b6db161745ec494aba4d69e865d78) kern_event.c (95c05062ec15cf323488d4c5e1986f5866bf7464)
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
5 * Copyright 2004 John-Mark Gurney <jmg@FreeBSD.org>
6 * Copyright (c) 2009 Apple, Inc.
7 * All rights reserved.
8 *

--- 148 unchanged lines hidden (view full) ---

157static int filt_kqueue(struct knote *kn, long hint);
158static int filt_procattach(struct knote *kn);
159static void filt_procdetach(struct knote *kn);
160static int filt_proc(struct knote *kn, long hint);
161static int filt_fileattach(struct knote *kn);
162static void filt_timerexpire(void *knx);
163static int filt_timerattach(struct knote *kn);
164static void filt_timerdetach(struct knote *kn);
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1999,2000,2001 Jonathan Lemon <jlemon@FreeBSD.org>
5 * Copyright 2004 John-Mark Gurney <jmg@FreeBSD.org>
6 * Copyright (c) 2009 Apple, Inc.
7 * All rights reserved.
8 *

--- 148 unchanged lines hidden (view full) ---

157static int filt_kqueue(struct knote *kn, long hint);
158static int filt_procattach(struct knote *kn);
159static void filt_procdetach(struct knote *kn);
160static int filt_proc(struct knote *kn, long hint);
161static int filt_fileattach(struct knote *kn);
162static void filt_timerexpire(void *knx);
163static int filt_timerattach(struct knote *kn);
164static void filt_timerdetach(struct knote *kn);
165static void filt_timerstart(struct knote *kn, sbintime_t to);
166static void filt_timertouch(struct knote *kn, struct kevent *kev,
167 u_long type);
168static int filt_timervalidate(struct knote *kn, sbintime_t *to);
165static int filt_timer(struct knote *kn, long hint);
166static int filt_userattach(struct knote *kn);
167static void filt_userdetach(struct knote *kn);
168static int filt_user(struct knote *kn, long hint);
169static void filt_usertouch(struct knote *kn, struct kevent *kev,
170 u_long type);
171
172static struct filterops file_filtops = {

--- 12 unchanged lines hidden (view full) ---

185 .f_detach = filt_procdetach,
186 .f_event = filt_proc,
187};
188static struct filterops timer_filtops = {
189 .f_isfd = 0,
190 .f_attach = filt_timerattach,
191 .f_detach = filt_timerdetach,
192 .f_event = filt_timer,
169static int filt_timer(struct knote *kn, long hint);
170static int filt_userattach(struct knote *kn);
171static void filt_userdetach(struct knote *kn);
172static int filt_user(struct knote *kn, long hint);
173static void filt_usertouch(struct knote *kn, struct kevent *kev,
174 u_long type);
175
176static struct filterops file_filtops = {

--- 12 unchanged lines hidden (view full) ---

189 .f_detach = filt_procdetach,
190 .f_event = filt_proc,
191};
192static struct filterops timer_filtops = {
193 .f_isfd = 0,
194 .f_attach = filt_timerattach,
195 .f_detach = filt_timerdetach,
196 .f_event = filt_timer,
197 .f_touch = filt_timertouch,
193};
194static struct filterops user_filtops = {
195 .f_attach = filt_userattach,
196 .f_detach = filt_userdetach,
197 .f_event = filt_user,
198 .f_touch = filt_usertouch,
199};
200

--- 493 unchanged lines hidden (view full) ---

694 callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
695 PCPU_GET(cpuid), C_ABSOLUTE);
696}
697
698/*
699 * data contains amount of time to sleep
700 */
701static int
198};
199static struct filterops user_filtops = {
200 .f_attach = filt_userattach,
201 .f_detach = filt_userdetach,
202 .f_event = filt_user,
203 .f_touch = filt_usertouch,
204};
205

--- 493 unchanged lines hidden (view full) ---

699 callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
700 PCPU_GET(cpuid), C_ABSOLUTE);
701}
702
703/*
704 * data contains amount of time to sleep
705 */
706static int
702filt_timerattach(struct knote *kn)
707filt_timervalidate(struct knote *kn, sbintime_t *to)
703{
708{
704 struct kq_timer_cb_data *kc;
705 struct bintime bt;
709 struct bintime bt;
706 sbintime_t to, sbt;
707 unsigned int ncallouts;
710 sbintime_t sbt;
708
709 if (kn->kn_sdata < 0)
710 return (EINVAL);
711 if (kn->kn_sdata == 0 && (kn->kn_flags & EV_ONESHOT) == 0)
712 kn->kn_sdata = 1;
711
712 if (kn->kn_sdata < 0)
713 return (EINVAL);
714 if (kn->kn_sdata == 0 && (kn->kn_flags & EV_ONESHOT) == 0)
715 kn->kn_sdata = 1;
713 /* Only precision unit are supported in flags so far */
716 /*
717 * The only fflags values supported are the timer unit
718 * (precision) and the absolute time indicator.
719 */
714 if ((kn->kn_sfflags & ~(NOTE_TIMER_PRECMASK | NOTE_ABSTIME)) != 0)
715 return (EINVAL);
716
720 if ((kn->kn_sfflags & ~(NOTE_TIMER_PRECMASK | NOTE_ABSTIME)) != 0)
721 return (EINVAL);
722
717 to = timer2sbintime(kn->kn_sdata, kn->kn_sfflags);
723 *to = timer2sbintime(kn->kn_sdata, kn->kn_sfflags);
718 if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
719 getboottimebin(&bt);
720 sbt = bttosbt(bt);
724 if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
725 getboottimebin(&bt);
726 sbt = bttosbt(bt);
721 to -= sbt;
727 *to -= sbt;
722 }
728 }
723 if (to < 0)
729 if (*to < 0)
724 return (EINVAL);
730 return (EINVAL);
731 return (0);
732}
725
733
734static int
735filt_timerattach(struct knote *kn)
736{
737 struct kq_timer_cb_data *kc;
738 sbintime_t to;
739 unsigned int ncallouts;
740 int error;
741
742 error = filt_timervalidate(kn, &to);
743 if (error != 0)
744 return (error);
745
726 do {
727 ncallouts = kq_ncallouts;
728 if (ncallouts >= kq_calloutmax)
729 return (ENOMEM);
730 } while (!atomic_cmpset_int(&kq_ncallouts, ncallouts, ncallouts + 1));
731
732 if ((kn->kn_sfflags & NOTE_ABSTIME) == 0)
733 kn->kn_flags |= EV_CLEAR; /* automatically set */
734 kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */
735 kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK);
736 callout_init(&kc->c, 1);
746 do {
747 ncallouts = kq_ncallouts;
748 if (ncallouts >= kq_calloutmax)
749 return (ENOMEM);
750 } while (!atomic_cmpset_int(&kq_ncallouts, ncallouts, ncallouts + 1));
751
752 if ((kn->kn_sfflags & NOTE_ABSTIME) == 0)
753 kn->kn_flags |= EV_CLEAR; /* automatically set */
754 kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */
755 kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK);
756 callout_init(&kc->c, 1);
757 filt_timerstart(kn, to);
758
759 return (0);
760}
761
762static void
763filt_timerstart(struct knote *kn, sbintime_t to)
764{
765 struct kq_timer_cb_data *kc;
766
767 kc = kn->kn_ptr.p_v;
737 if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
738 kc->next = to;
739 kc->to = 0;
740 } else {
741 kc->next = to + sbinuptime();
742 kc->to = to;
743 }
744 callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
745 PCPU_GET(cpuid), C_ABSOLUTE);
768 if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) {
769 kc->next = to;
770 kc->to = 0;
771 } else {
772 kc->next = to + sbinuptime();
773 kc->to = to;
774 }
775 callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
776 PCPU_GET(cpuid), C_ABSOLUTE);
746
747 return (0);
748}
749
750static void
751filt_timerdetach(struct knote *kn)
752{
753 struct kq_timer_cb_data *kc;
754 unsigned int old __unused;
755
756 kc = kn->kn_ptr.p_v;
757 callout_drain(&kc->c);
758 free(kc, M_KQUEUE);
759 old = atomic_fetchadd_int(&kq_ncallouts, -1);
760 KASSERT(old > 0, ("Number of callouts cannot become negative"));
761 kn->kn_status |= KN_DETACHED; /* knlist_remove sets it */
762}
763
777}
778
779static void
780filt_timerdetach(struct knote *kn)
781{
782 struct kq_timer_cb_data *kc;
783 unsigned int old __unused;
784
785 kc = kn->kn_ptr.p_v;
786 callout_drain(&kc->c);
787 free(kc, M_KQUEUE);
788 old = atomic_fetchadd_int(&kq_ncallouts, -1);
789 KASSERT(old > 0, ("Number of callouts cannot become negative"));
790 kn->kn_status |= KN_DETACHED; /* knlist_remove sets it */
791}
792
793static void
794filt_timertouch(struct knote *kn, struct kevent *kev, u_long type)
795{
796 struct kq_timer_cb_data *kc;
797 struct kqueue *kq;
798 sbintime_t to;
799 int error;
800
801 switch (type) {
802 case EVENT_REGISTER:
803 /* Handle re-added timers that update data/fflags */
804 if (kev->flags & EV_ADD) {
805 kc = kn->kn_ptr.p_v;
806
807 /* Drain any existing callout. */
808 callout_drain(&kc->c);
809
810 /* Throw away any existing undelivered record
811 * of the timer expiration. This is done under
812 * the presumption that if a process is
813 * re-adding this timer with new parameters,
814 * it is no longer interested in what may have
815 * happened under the old parameters. If it is
816 * interested, it can wait for the expiration,
817 * delete the old timer definition, and then
818 * add the new one.
819 *
820 * This has to be done while the kq is locked:
821 * - if enqueued, dequeue
822 * - make it no longer active
823 * - clear the count of expiration events
824 */
825 kq = kn->kn_kq;
826 KQ_LOCK(kq);
827 if (kn->kn_status & KN_QUEUED)
828 knote_dequeue(kn);
829
830 kn->kn_status &= ~KN_ACTIVE;
831 kn->kn_data = 0;
832 KQ_UNLOCK(kq);
833
834 /* Reschedule timer based on new data/fflags */
835 kn->kn_sfflags = kev->fflags;
836 kn->kn_sdata = kev->data;
837 error = filt_timervalidate(kn, &to);
838 if (error != 0) {
839 kn->kn_flags |= EV_ERROR;
840 kn->kn_data = error;
841 } else
842 filt_timerstart(kn, to);
843 }
844 break;
845
846 case EVENT_PROCESS:
847 *kev = kn->kn_kevent;
848 if (kn->kn_flags & EV_CLEAR) {
849 kn->kn_data = 0;
850 kn->kn_fflags = 0;
851 }
852 break;
853
854 default:
855 panic("filt_timertouch() - invalid type (%ld)", type);
856 break;
857 }
858}
859
764static int
765filt_timer(struct knote *kn, long hint)
766{
767
768 return (kn->kn_data != 0);
769}
770
771static int

--- 1867 unchanged lines hidden ---
860static int
861filt_timer(struct knote *kn, long hint)
862{
863
864 return (kn->kn_data != 0);
865}
866
867static int

--- 1867 unchanged lines hidden ---