1/*
2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "common.h"
18
19static int __thread kqfd;
20
21void
22test_kevent_signal_add(void)
23{
24    struct kevent kev;
25
26    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
27}
28
29void
30test_kevent_signal_get(void)
31{
32    struct kevent kev;
33
34    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
35
36    if (kill(getpid(), SIGUSR1) < 0)
37        die("kill");
38
39    kev.flags |= EV_CLEAR;
40    kev.data = 1;
41    kevent_cmp(&kev, kevent_get(kqfd));
42}
43
44void
45test_kevent_signal_disable(void)
46{
47    struct kevent kev;
48
49    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
50
51    if (kill(getpid(), SIGUSR1) < 0)
52        die("kill");
53
54    test_no_kevents(kqfd);
55}
56
57void
58test_kevent_signal_enable(void)
59{
60    struct kevent kev;
61
62    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
63
64    if (kill(getpid(), SIGUSR1) < 0)
65        die("kill");
66
67    kev.flags = EV_ADD | EV_CLEAR;
68#if LIBKQUEUE
69    kev.data = 1; /* WORKAROUND */
70#else
71    kev.data = 2; // one extra time from test_kevent_signal_disable()
72#endif
73    kevent_cmp(&kev, kevent_get(kqfd));
74
75    /* Delete the watch */
76    kev.flags = EV_DELETE;
77    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
78        die("kevent");
79}
80
81void
82test_kevent_signal_del(void)
83{
84    struct kevent kev;
85
86    /* Delete the kevent */
87    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
88
89    signal(SIGUSR1, SIG_IGN);
90    if (kill(getpid(), SIGUSR1) < 0)
91        die("kill");
92
93    test_no_kevents(kqfd);
94}
95
96void
97test_kevent_signal_oneshot(void)
98{
99    struct kevent kev;
100
101    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
102
103    if (kill(getpid(), SIGUSR1) < 0)
104        die("kill");
105
106    kev.flags |= EV_CLEAR;
107    kev.data = 1;
108    kevent_cmp(&kev, kevent_get(kqfd));
109
110    /* Send another one and make sure we get no events */
111    test_no_kevents(kqfd);
112    if (kill(getpid(), SIGUSR1) < 0)
113        die("kill");
114    test_no_kevents(kqfd);
115}
116
117void
118test_kevent_signal_modify(void)
119{
120    struct kevent kev;
121
122    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
123    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, ((void *)-1));
124
125    if (kill(getpid(), SIGUSR1) < 0)
126        die("kill");
127
128    kev.flags |= EV_CLEAR;
129    kev.data = 1;
130    kevent_cmp(&kev, kevent_get(kqfd));
131}
132
133#if HAVE_EV_DISPATCH
134void
135test_kevent_signal_dispatch(void)
136{
137    struct kevent kev;
138
139    test_no_kevents(kqfd);
140
141    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_CLEAR | EV_DISPATCH, 0, 0, NULL);
142
143    /* Get one event */
144    if (kill(getpid(), SIGUSR1) < 0)
145        die("kill");
146    kev.data = 1;
147    kevent_cmp(&kev, kevent_get(kqfd));
148
149    /* Confirm that the knote is disabled */
150    if (kill(getpid(), SIGUSR1) < 0)
151        die("kill");
152    test_no_kevents(kqfd);
153
154    /* Enable the knote and make sure no events are pending */
155    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE | EV_DISPATCH, 0, 0, NULL);
156    test_no_kevents(kqfd);
157
158    /* Get the next event */
159    if (kill(getpid(), SIGUSR1) < 0)
160        die("kill");
161    kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
162    kev.data = 1;
163    kevent_cmp(&kev, kevent_get(kqfd));
164
165    /* Remove the knote and ensure the event no longer fires */
166    kevent_add(kqfd, &kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
167    if (kill(getpid(), SIGUSR1) < 0)
168        die("kill");
169    test_no_kevents(kqfd);
170}
171#endif  /* HAVE_EV_DISPATCH */
172
173void
174test_evfilt_signal(int _kqfd)
175{
176    signal(SIGUSR1, SIG_IGN);
177
178	kqfd = _kqfd;
179    test(kevent_signal_add);
180    test(kevent_signal_del);
181    test(kevent_signal_get);
182    test(kevent_signal_disable);
183    test(kevent_signal_enable);
184    test(kevent_signal_oneshot);
185    test(kevent_signal_modify);
186#if HAVE_EV_DISPATCH
187    test(kevent_signal_dispatch);
188#endif
189}
190