Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/kqueue/libkqueue/main.c
39566 views
1
/*
2
* Copyright (c) 2009 Mark Heily <[email protected]>
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 <sys/types.h>
18
19
#include "config.h"
20
#include "common.h"
21
22
int kqfd;
23
static char *cur_test_id = NULL;
24
static int testnum = 1;
25
26
/* Checks if any events are pending, which is an error. */
27
void
28
_test_no_kevents(const char *file, int line)
29
{
30
int nfds;
31
struct timespec timeo;
32
struct kevent kev;
33
char *kev_str;
34
35
puts("confirming that there are no events pending");
36
memset(&timeo, 0, sizeof(timeo));
37
nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);
38
if (nfds != 0) {
39
printf("\n[%s:%d]: Unexpected event:", file, line);
40
kev_str = kevent_to_str(&kev);
41
puts(kev_str);
42
free(kev_str);
43
errx(1, "%d event(s) pending, but none expected:", nfds);
44
}
45
}
46
47
/* Checks if any events are pending, which is an error. Do not print
48
* out anything unless events are found.
49
*/
50
void
51
test_no_kevents_quietly(void)
52
{
53
int nfds;
54
struct timespec timeo;
55
struct kevent kev;
56
char *kev_str;
57
58
memset(&timeo, 0, sizeof(timeo));
59
nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);
60
if (nfds != 0) {
61
puts("\nUnexpected event:");
62
kev_str = kevent_to_str(&kev);
63
puts(kev_str);
64
free(kev_str);
65
errx(1, "%d event(s) pending, but none expected:", nfds);
66
}
67
}
68
69
/* Retrieve a single kevent */
70
struct kevent *
71
kevent_get(int fd)
72
{
73
int nfds;
74
struct kevent *kev;
75
76
if ((kev = calloc(1, sizeof(*kev))) == NULL)
77
err(1, "out of memory");
78
79
nfds = kevent(fd, NULL, 0, kev, 1, NULL);
80
if (nfds < 1)
81
err(1, "kevent(2)");
82
83
return (kev);
84
}
85
86
/* Retrieve a single kevent, specifying a maximum time to wait for it. */
87
struct kevent *
88
kevent_get_timeout(int fd, int seconds)
89
{
90
int nfds;
91
struct kevent *kev;
92
struct timespec timeout = {seconds, 0};
93
94
if ((kev = calloc(1, sizeof(*kev))) == NULL)
95
err(1, "out of memory");
96
97
nfds = kevent(fd, NULL, 0, kev, 1, &timeout);
98
if (nfds < 0) {
99
err(1, "kevent(2)");
100
} else if (nfds == 0) {
101
free(kev);
102
kev = NULL;
103
}
104
105
return (kev);
106
}
107
108
static char *
109
kevent_fflags_dump(struct kevent *kev)
110
{
111
char *buf;
112
113
#define KEVFFL_DUMP(attrib) \
114
if (kev->fflags & attrib) \
115
strncat(buf, #attrib" ", 64);
116
117
if ((buf = calloc(1, 1024)) == NULL)
118
abort();
119
120
/* Not every filter has meaningful fflags */
121
if (kev->filter == EVFILT_PROC) {
122
snprintf(buf, 1024, "fflags = %x (", kev->fflags);
123
KEVFFL_DUMP(NOTE_EXIT);
124
KEVFFL_DUMP(NOTE_FORK);
125
KEVFFL_DUMP(NOTE_EXEC);
126
KEVFFL_DUMP(NOTE_CHILD);
127
KEVFFL_DUMP(NOTE_TRACKERR);
128
KEVFFL_DUMP(NOTE_TRACK);
129
buf[strlen(buf) - 1] = ')';
130
} else if (kev->filter == EVFILT_PROCDESC) {
131
snprintf(buf, 1024, "fflags = %x (", kev->fflags);
132
KEVFFL_DUMP(NOTE_EXIT);
133
KEVFFL_DUMP(NOTE_FORK);
134
KEVFFL_DUMP(NOTE_EXEC);
135
buf[strlen(buf) - 1] = ')';
136
} else if (kev->filter == EVFILT_VNODE) {
137
snprintf(buf, 1024, "fflags = %x (", kev->fflags);
138
KEVFFL_DUMP(NOTE_DELETE);
139
KEVFFL_DUMP(NOTE_WRITE);
140
KEVFFL_DUMP(NOTE_EXTEND);
141
#if HAVE_NOTE_TRUNCATE
142
KEVFFL_DUMP(NOTE_TRUNCATE);
143
#endif
144
KEVFFL_DUMP(NOTE_ATTRIB);
145
KEVFFL_DUMP(NOTE_LINK);
146
KEVFFL_DUMP(NOTE_RENAME);
147
#if HAVE_NOTE_REVOKE
148
KEVFFL_DUMP(NOTE_REVOKE);
149
#endif
150
buf[strlen(buf) - 1] = ')';
151
} else {
152
snprintf(buf, 1024, "fflags = %x", kev->fflags);
153
}
154
155
return (buf);
156
}
157
158
static char *
159
kevent_flags_dump(struct kevent *kev)
160
{
161
char *buf;
162
163
#define KEVFL_DUMP(attrib) \
164
if (kev->flags & attrib) \
165
strncat(buf, #attrib" ", 64);
166
167
if ((buf = calloc(1, 1024)) == NULL)
168
abort();
169
170
snprintf(buf, 1024, "flags = %d (", kev->flags);
171
KEVFL_DUMP(EV_ADD);
172
KEVFL_DUMP(EV_ENABLE);
173
KEVFL_DUMP(EV_DISABLE);
174
KEVFL_DUMP(EV_DELETE);
175
KEVFL_DUMP(EV_ONESHOT);
176
KEVFL_DUMP(EV_CLEAR);
177
KEVFL_DUMP(EV_EOF);
178
KEVFL_DUMP(EV_ERROR);
179
#if HAVE_EV_DISPATCH
180
KEVFL_DUMP(EV_DISPATCH);
181
#endif
182
#if HAVE_EV_RECEIPT
183
KEVFL_DUMP(EV_RECEIPT);
184
#endif
185
buf[strlen(buf) - 1] = ')';
186
187
return (buf);
188
}
189
190
/* Copied from ../kevent.c kevent_dump() and improved */
191
char *
192
kevent_to_str(struct kevent *kev)
193
{
194
char buf[512];
195
char *flags_str = kevent_flags_dump(kev);
196
char *fflags_str = kevent_fflags_dump(kev);
197
198
snprintf(&buf[0], sizeof(buf),
199
"[ident=%ju, filter=%d, %s, %s, data=%jd, udata=%p, "
200
"ext=[%jx %jx %jx %jx]",
201
(uintmax_t) kev->ident,
202
kev->filter,
203
flags_str,
204
fflags_str,
205
(uintmax_t)kev->data,
206
kev->udata,
207
(uintmax_t)kev->ext[0],
208
(uintmax_t)kev->ext[1],
209
(uintmax_t)kev->ext[2],
210
(uintmax_t)kev->ext[3]);
211
212
free(flags_str);
213
free(fflags_str);
214
215
return (strdup(buf));
216
}
217
218
void
219
kevent_add(int fd, struct kevent *kev,
220
uintptr_t ident,
221
short filter,
222
u_short flags,
223
u_int fflags,
224
intptr_t data,
225
void *udata)
226
{
227
char *kev_str;
228
229
EV_SET(kev, ident, filter, flags, fflags, data, udata);
230
if (kevent(fd, kev, 1, NULL, 0, NULL) < 0) {
231
kev_str = kevent_to_str(kev);
232
printf("Unable to add the following kevent:\n%s\n",
233
kev_str);
234
free(kev_str);
235
err(1, "kevent(): %s", strerror(errno));
236
}
237
}
238
239
void
240
_kevent_cmp(struct kevent *k1, struct kevent *k2, const char *file, int line)
241
{
242
char *kev1_str;
243
char *kev2_str;
244
245
/* XXX-
246
Workaround for inconsistent implementation of kevent(2)
247
*/
248
#ifdef __FreeBSD__
249
if (k1->flags & EV_ADD)
250
k2->flags |= EV_ADD;
251
#endif
252
if (k1->ident != k2->ident || k1->filter != k2->filter ||
253
k1->flags != k2->flags || k1->fflags != k2->fflags ||
254
k1->data != k2->data || k1->udata != k2->udata ||
255
k1->ext[0] != k2->ext[0] || k1->ext[1] != k2->ext[1] ||
256
k1->ext[0] != k2->ext[2] || k1->ext[0] != k2->ext[3]) {
257
kev1_str = kevent_to_str(k1);
258
kev2_str = kevent_to_str(k2);
259
printf("[%s:%d]: kevent_cmp: mismatch:\n %s !=\n %s\n",
260
file, line, kev1_str, kev2_str);
261
free(kev1_str);
262
free(kev2_str);
263
abort();
264
}
265
}
266
267
void
268
test_begin(const char *func)
269
{
270
if (cur_test_id)
271
free(cur_test_id);
272
cur_test_id = strdup(func);
273
if (!cur_test_id)
274
err(1, "strdup failed");
275
276
printf("\n\nTest %d: %s\n", testnum++, func);
277
}
278
279
void
280
success(void)
281
{
282
printf("%-70s %s\n", cur_test_id, "passed");
283
free(cur_test_id);
284
cur_test_id = NULL;
285
}
286
287
static void
288
test_kqueue(void)
289
{
290
test_begin("kqueue()");
291
if ((kqfd = kqueue()) < 0)
292
err(1, "kqueue()");
293
test_no_kevents();
294
success();
295
}
296
297
static void
298
test_kqueue_close(void)
299
{
300
test_begin("close(kq)");
301
if (close(kqfd) < 0)
302
err(1, "close()");
303
success();
304
}
305
306
int
307
main(int argc, char **argv)
308
{
309
int test_proc = 1;
310
int test_socket = 1;
311
int test_signal = 1;
312
int test_vnode = 1;
313
int test_timer = 1;
314
#ifdef __FreeBSD__
315
int test_user = 1;
316
#else
317
/* XXX-FIXME temporary */
318
int test_user = 0;
319
#endif
320
321
while (argc) {
322
if (strcmp(argv[0], "--no-proc") == 0)
323
test_proc = 0;
324
if (strcmp(argv[0], "--no-socket") == 0)
325
test_socket = 0;
326
if (strcmp(argv[0], "--no-timer") == 0)
327
test_timer = 0;
328
if (strcmp(argv[0], "--no-signal") == 0)
329
test_signal = 0;
330
if (strcmp(argv[0], "--no-vnode") == 0)
331
test_vnode = 0;
332
if (strcmp(argv[0], "--no-user") == 0)
333
test_user = 0;
334
argv++;
335
argc--;
336
}
337
338
/*
339
* Some tests fork. If output is fully buffered,
340
* the children inherit some buffered data and flush
341
* it when they exit, causing some data to be printed twice.
342
* Use line buffering to avoid this problem.
343
*/
344
setlinebuf(stdout);
345
setlinebuf(stderr);
346
347
test_kqueue();
348
test_kqueue_close();
349
350
if (test_socket)
351
test_evfilt_read();
352
if (test_signal)
353
test_evfilt_signal();
354
if (test_vnode)
355
test_evfilt_vnode();
356
#if HAVE_EVFILT_USER
357
if (test_user)
358
test_evfilt_user();
359
#endif
360
if (test_timer)
361
test_evfilt_timer();
362
if (test_proc)
363
test_evfilt_proc();
364
365
printf("\n---\n"
366
"+OK All %d tests completed.\n", testnum - 1);
367
return (0);
368
}
369
370