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
19
20static void
21test_kevent_signal_add(void)
22{
23    const char *test_id = "kevent(EVFILT_SIGNAL, EV_ADD)";
24    struct kevent kev;
25
26    test_begin(test_id);
27
28    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
29    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
30        err(1, "%s", test_id);
31
32    success();
33}
34
35static void
36test_kevent_signal_get(void)
37{
38    const char *test_id = "kevent(EVFILT_SIGNAL, wait)";
39    struct kevent kev;
40
41    test_begin(test_id);
42
43    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
44    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
45        err(1, "%s", test_id);
46
47    /* Block SIGUSR1, then send it to ourselves */
48    sigset_t mask;
49    sigemptyset(&mask);
50    sigaddset(&mask, SIGUSR1);
51    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
52        err(1, "sigprocmask");
53    if (kill(getpid(), SIGUSR1) < 0)
54        err(1, "kill");
55
56    kev.flags |= EV_CLEAR;
57    kev.data = 1;
58    kevent_cmp(&kev, kevent_get(kqfd));
59
60    success();
61}
62
63static void
64test_kevent_signal_disable(void)
65{
66    const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)";
67    struct kevent kev;
68
69    test_begin(test_id);
70
71    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL);
72    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
73        err(1, "%s", test_id);
74
75    /* Block SIGUSR1, then send it to ourselves */
76    sigset_t mask;
77    sigemptyset(&mask);
78    sigaddset(&mask, SIGUSR1);
79    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
80        err(1, "sigprocmask");
81    if (kill(getpid(), SIGUSR1) < 0)
82        err(1, "kill");
83
84    test_no_kevents();
85
86    success();
87}
88
89static void
90test_kevent_signal_enable(void)
91{
92    const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)";
93    struct kevent kev;
94
95    test_begin(test_id);
96
97    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL);
98    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
99        err(1, "%s", test_id);
100
101    /* Block SIGUSR1, then send it to ourselves */
102    sigset_t mask;
103    sigemptyset(&mask);
104    sigaddset(&mask, SIGUSR1);
105    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
106        err(1, "sigprocmask");
107    if (kill(getpid(), SIGUSR1) < 0)
108        err(1, "kill");
109
110    kev.flags = EV_ADD | EV_CLEAR;
111#if LIBKQUEUE
112    kev.data = 1; /* WORKAROUND */
113#else
114    kev.data = 2; // one extra time from test_kevent_signal_disable()
115#endif
116    kevent_cmp(&kev, kevent_get(kqfd));
117
118    /* Delete the watch */
119    kev.flags = EV_DELETE;
120    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
121        err(1, "%s", test_id);
122
123    success();
124}
125
126static void
127test_kevent_signal_del(void)
128{
129    const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)";
130    struct kevent kev;
131
132    test_begin(test_id);
133
134    /* Delete the kevent */
135    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL);
136    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
137        err(1, "%s", test_id);
138
139    /* Block SIGUSR1, then send it to ourselves */
140    sigset_t mask;
141    sigemptyset(&mask);
142    sigaddset(&mask, SIGUSR1);
143    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
144        err(1, "sigprocmask");
145    if (kill(getpid(), SIGUSR1) < 0)
146        err(1, "kill");
147
148    test_no_kevents();
149    success();
150}
151
152static void
153test_kevent_signal_oneshot(void)
154{
155    const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)";
156    struct kevent kev;
157
158    test_begin(test_id);
159
160    EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL);
161    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
162        err(1, "%s", test_id);
163
164    /* Block SIGUSR1, then send it to ourselves */
165    sigset_t mask;
166    sigemptyset(&mask);
167    sigaddset(&mask, SIGUSR1);
168    if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1)
169        err(1, "sigprocmask");
170    if (kill(getpid(), SIGUSR1) < 0)
171        err(1, "kill");
172
173    kev.flags |= EV_CLEAR;
174    kev.data = 1;
175    kevent_cmp(&kev, kevent_get(kqfd));
176
177    /* Send another one and make sure we get no events */
178    if (kill(getpid(), SIGUSR1) < 0)
179        err(1, "kill");
180    test_no_kevents();
181
182    success();
183}
184
185void
186test_evfilt_signal(void)
187{
188    kqfd = kqueue();
189    test_kevent_signal_add();
190    test_kevent_signal_del();
191    test_kevent_signal_get();
192    test_kevent_signal_disable();
193    test_kevent_signal_enable();
194    test_kevent_signal_oneshot();
195    close(kqfd);
196}
197