summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/syscount.c144
-rw-r--r--tests/t_event.c37
2 files changed, 181 insertions, 0 deletions
diff --git a/tests/syscount.c b/tests/syscount.c
new file mode 100644
index 0000000..ec45c15
--- /dev/null
+++ b/tests/syscount.c
@@ -0,0 +1,144 @@
1/* Counts the system calls a run makes, by standing in front of libc.
2
3 cc -O2 -shared -fPIC -o syscount.so tests/syscount.c -ldl
4 LD_PRELOAD=./syscount.so ./opentracker -f conf (DYLD_INSERT_LIBRARIES on macOS)
5
6 The tally goes to stderr when the process exits. Reading the source tells
7 you which calls a path should make; this tells you which it does make,
8 which is not always the same thing. */
9
10#define _GNU_SOURCE
11#include <dlfcn.h>
12#include <stdarg.h>
13#include <stdatomic.h>
14#include <stdio.h>
15#include <sys/socket.h>
16#include <sys/types.h>
17#include <unistd.h>
18
19#ifdef __linux__
20#include <sys/epoll.h>
21#endif
22
23#define COUNTER(name) static _Atomic long g_##name
24#define BUMP(name) atomic_fetch_add_explicit(&g_##name, 1, memory_order_relaxed)
25#define REPORT(name) fprintf(stderr, " %-14s %10ld\n", #name, atomic_load(&g_##name))
26
27COUNTER(accept);
28COUNTER(accept4);
29COUNTER(read);
30COUNTER(write);
31COUNTER(close);
32COUNTER(fcntl);
33COUNTER(recvfrom);
34COUNTER(sendto);
35COUNTER(epoll_ctl);
36COUNTER(epoll_wait);
37
38typedef int (*fn_accept)(int, struct sockaddr *, socklen_t *);
39typedef int (*fn_accept4)(int, struct sockaddr *, socklen_t *, int);
40typedef ssize_t (*fn_read)(int, void *, size_t);
41typedef ssize_t (*fn_write)(int, const void *, size_t);
42typedef int (*fn_close)(int);
43typedef int (*fn_fcntl)(int, int, ...);
44typedef ssize_t (*fn_recvfrom)(int, void *, size_t, int, struct sockaddr *, socklen_t *);
45typedef ssize_t (*fn_sendto)(int, const void *, size_t, int, const struct sockaddr *, socklen_t);
46
47static fn_accept real_accept;
48static fn_accept4 real_accept4;
49static fn_read real_read;
50static fn_write real_write;
51static fn_close real_close;
52static fn_fcntl real_fcntl;
53static fn_recvfrom real_recvfrom;
54static fn_sendto real_sendto;
55
56/* Resolving lazily keeps the library out of the way until something is
57 actually called, which matters because dlsym itself allocates */
58#define WRAP(name) \
59 if (!real_##name) \
60 real_##name = (fn_##name)dlsym(RTLD_NEXT, #name); \
61 BUMP(name)
62
63int accept(int s, struct sockaddr *addr, socklen_t *len) {
64 WRAP(accept);
65 return real_accept(s, addr, len);
66}
67
68#ifdef SOCK_NONBLOCK
69int accept4(int s, struct sockaddr *addr, socklen_t *len, int flags) {
70 WRAP(accept4);
71 return real_accept4(s, addr, len, flags);
72}
73#endif
74
75ssize_t read(int fd, void *buf, size_t count) {
76 WRAP(read);
77 return real_read(fd, buf, count);
78}
79
80ssize_t write(int fd, const void *buf, size_t count) {
81 WRAP(write);
82 return real_write(fd, buf, count);
83}
84
85int close(int fd) {
86 WRAP(close);
87 return real_close(fd);
88}
89
90int fcntl(int fd, int cmd, ...) {
91 va_list args;
92 long arg;
93
94 va_start(args, cmd);
95 arg = va_arg(args, long);
96 va_end(args);
97 WRAP(fcntl);
98 return real_fcntl(fd, cmd, arg);
99}
100
101ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) {
102 WRAP(recvfrom);
103 return real_recvfrom(s, buf, len, flags, from, fromlen);
104}
105
106ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) {
107 WRAP(sendto);
108 return real_sendto(s, buf, len, flags, to, tolen);
109}
110
111#ifdef __linux__
112typedef int (*fn_epoll_ctl)(int, int, int, struct epoll_event *);
113typedef int (*fn_epoll_wait)(int, struct epoll_event *, int, int);
114static fn_epoll_ctl real_epoll_ctl;
115static fn_epoll_wait real_epoll_wait;
116
117int epoll_ctl(int ep, int op, int fd, struct epoll_event *ev) {
118 WRAP(epoll_ctl);
119 return real_epoll_ctl(ep, op, fd, ev);
120}
121
122int epoll_wait(int ep, struct epoll_event *events, int max, int timeout) {
123 WRAP(epoll_wait);
124 return real_epoll_wait(ep, events, max, timeout);
125}
126#endif
127
128__attribute__((destructor)) static void report(void) {
129 fprintf(stderr, "\n system calls this run\n");
130 REPORT(accept);
131#ifdef SOCK_NONBLOCK
132 REPORT(accept4);
133#endif
134 REPORT(read);
135 REPORT(write);
136 REPORT(close);
137 REPORT(fcntl);
138 REPORT(recvfrom);
139 REPORT(sendto);
140#ifdef __linux__
141 REPORT(epoll_ctl);
142 REPORT(epoll_wait);
143#endif
144}
diff --git a/tests/t_event.c b/tests/t_event.c
index 5509f19..ad3948f 100644
--- a/tests/t_event.c
+++ b/tests/t_event.c
@@ -4,6 +4,7 @@
4 $id$ */ 4 $id$ */
5 5
6/* System */ 6/* System */
7#include <fcntl.h>
7#include <string.h> 8#include <string.h>
8#include <sys/socket.h> 9#include <sys/socket.h>
9#include <sys/time.h> 10#include <sys/time.h>
@@ -205,6 +206,41 @@ static void case_unknown_descriptor(void) {
205 CHECK_INT(event_del(4096), -1); 206 CHECK_INT(event_del(4096), -1);
206} 207}
207 208
209/* event_close exists so that the mechanisms which drop a closed descriptor
210 by themselves are not asked to do it twice. The one that keeps its own
211 list has to be told, and forgetting would leave the entry there to be
212 reported for ever, so what is checked here is the silence afterwards. */
213static void case_close_takes_it_out(void) {
214 int other[2], closed, count, i, strays = 0;
215
216 test_case("a closed descriptor is gone from the set and really closed");
217 pair_open();
218 CHECK(sv[0] != -1);
219 CHECK_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, other), 0);
220 CHECK_INT(event_add(sv[0], EVENT_IN, 1), 0);
221 CHECK_INT(event_add(other[0], EVENT_IN, 2), 0);
222
223 closed = sv[0];
224 CHECK_INT(event_close(closed), 0);
225 sv[0] = -1;
226 CHECK_INT(fcntl(closed, F_GETFD), -1);
227
228 /* The survivor is made ready so the wait has something to come back with,
229 and anything left over from the closed one shows up beside it */
230 CHECK_INT((int)write(other[1], "x", 1), 1);
231 count = event_wait(ready, EVENTS, 200);
232 CHECK(count >= 1);
233 for (i = 0; i < count; ++i)
234 if (ready[i].fd != other[0])
235 ++strays;
236 CHECK_INT(strays, 0);
237
238 event_del(other[0]);
239 close(other[0]);
240 close(other[1]);
241 pair_close();
242}
243
208void test_event(void) { 244void test_event(void) {
209 CHECK_INT(event_init(), 0); 245 CHECK_INT(event_init(), 0);
210 CHECK(event_mechanism() != NULL); 246 CHECK(event_mechanism() != NULL);
@@ -217,6 +253,7 @@ void test_event(void) {
217 case_delete_from_the_middle(); 253 case_delete_from_the_middle();
218 case_timeout(); 254 case_timeout();
219 case_unknown_descriptor(); 255 case_unknown_descriptor();
256 case_close_takes_it_out();
220 257
221 event_deinit(); 258 event_deinit();
222} 259}