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