summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDirk Engling <erdgeist@erdgeist.org>2026-10-26 20:03:22 +0100
committerDirk Engling <erdgeist@erdgeist.org>2026-10-26 20:03:22 +0100
commit2d6b6d4da1d9732b2b02989a4374d356ff840d1b (patch)
tree50ff9d2fba93934d1572706f10593aec0ea57e07
parentf2f5b0450d4b7269bafdfb1bd1788303f6d8ce7b (diff)
Replace libowfat's event waiter with our own abstraction
It's with a heavy heart that I remove libowfat as my event library from opentracker. libowfat is what taught opentracker to walk and then fly. The tracker was literally standing on the shoulder of giants when I started writing it in 2006. For its time, the event abstraction was unparalleled and it has held up for many years, and it served the bittorrent community greatly. https://erdgeist.org/gitweb/opentracker/commit/?id=ad472597c569568bad0526d116b601dfcb36638c Unfortunately, it is very likely that libowfat will not be maintained anymore for the foreseeable future, it is already not easy to get its source from upstream and opentracker started receiving bug reports that I can not reasonably answer or patch. Before the project gets more dependent on the limitations of libowfat's current state, I need to teach opentracker to stand on its own feet and fly by itself. I've learned a great deal in the process and have even more respect now for what libowfat pioneered. The path for opentracker is cleared now. Ground work has already been laid in the migration process to support multi threaded http processing while keeping the aggressive reduction of syscalls alive that made the libowfat+opentracker combo so scalable. Here be some dragons, though: Even though there is a unit test suite now, the event loop's rewrite has not been battle tested yet. So you might want to hold up for a bit before jumping on the solo band wagon. What awaits at the end will be a long overdue v1.0, which will be named in honour of Felix.
-rw-r--r--Makefile17
-rw-r--r--opentracker.c95
-rw-r--r--ot_accesslist.c2
-rw-r--r--ot_clean.c3
-rw-r--r--ot_event.c20
-rw-r--r--ot_event.h2
-rw-r--r--ot_fdstate.c6
-rw-r--r--ot_fdstate.h4
-rw-r--r--ot_fullscrape.c3
-rw-r--r--ot_http.c39
-rw-r--r--ot_http.h6
-rw-r--r--ot_iovec.c2
-rw-r--r--ot_livesync.h1
-rw-r--r--ot_mutex.c9
-rw-r--r--ot_socket.c6
-rw-r--r--ot_socket.h1
-rw-r--r--ot_stats.c3
-rw-r--r--ot_sync.c3
-rw-r--r--ot_udp.c3
-rw-r--r--tests/t_event.c56
20 files changed, 159 insertions, 122 deletions
diff --git a/Makefile b/Makefile
index a373633..87225f7 100644
--- a/Makefile
+++ b/Makefile
@@ -64,8 +64,13 @@ GIT_VERSION=`sh -c 'command -v git >/dev/null && test -d .git && git rev-parse H
64OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage 64OPTS_debug=-D_DEBUG -g -ggdb # -pg -fprofile-arcs -ftest-coverage
65OPTS_production=-O3 65OPTS_production=-O3
66 66
67CFLAGS+=-I$(LIBOWFAT_HEADERS) -DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread -Wextra -Wwrite-strings #-ansi -pedantic 67CFLAGS+=-DGIT_VERSION=$(GIT_VERSION) -Wall -pipe -pthread -Wextra -Wwrite-strings #-ansi -pedantic
68LDFLAGS+=-L$(LIBOWFAT_LIBRARY) -lowfat -pthread 68LDFLAGS+=-pthread
69
70# Only the proxy, which has not been ported since the tracker went dual stack,
71# still wants libowfat.
72CFLAGS_libowfat=-I$(LIBOWFAT_HEADERS)
73LDFLAGS_libowfat=-L$(LIBOWFAT_LIBRARY) -lowfat
69 74
70BINARY =opentracker 75BINARY =opentracker
71HEADERS=trackerlogic.h ot_urlencoded.h ot_batch.h ot_buf.h ot_event.h ot_fdstate.h ot_hex.h ot_ip.h ot_config.h ot_scan.h ot_socket.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h 76HEADERS=trackerlogic.h ot_urlencoded.h ot_batch.h ot_buf.h ot_event.h ot_fdstate.h ot_hex.h ot_ip.h ot_config.h ot_scan.h ot_socket.h ot_mutex.h ot_random.h ot_stats.h ot_vector.h ot_clean.h ot_udp.h ot_iovec.h ot_fullscrape.h ot_accesslist.h ot_http.h ot_livesync.h ot_rijndael.h
@@ -84,8 +89,8 @@ all: $(BINARY) $(BINARY).debug
84CFLAGS_production = $(CFLAGS) $(OPTS_production) $(FEATURES) 89CFLAGS_production = $(CFLAGS) $(OPTS_production) $(FEATURES)
85CFLAGS_debug = $(CFLAGS) $(OPTS_debug) $(FEATURES) 90CFLAGS_debug = $(CFLAGS) $(OPTS_debug) $(FEATURES)
86 91
87CFLAGS_proxy = $(CFLAGS_production) -DWANT_SYNC_LIVE 92CFLAGS_proxy = $(CFLAGS_production) $(CFLAGS_libowfat) -DWANT_SYNC_LIVE
88CFLAGS_proxy_debug = $(CFLAGS_debug) -DWANT_SYNC_LIVE 93CFLAGS_proxy_debug = $(CFLAGS_debug) $(CFLAGS_libowfat) -DWANT_SYNC_LIVE
89 94
90$(BINARY): $(OBJECTS) 95$(BINARY): $(OBJECTS)
91 $(CC) -o $@ $(OBJECTS) $(LDFLAGS) 96 $(CC) -o $@ $(OBJECTS) $(LDFLAGS)
@@ -93,9 +98,9 @@ $(BINARY): $(OBJECTS)
93$(BINARY).debug: $(OBJECTS_debug) 98$(BINARY).debug: $(OBJECTS_debug)
94 $(CC) -o $@ $(OBJECTS_debug) $(LDFLAGS) 99 $(CC) -o $@ $(OBJECTS_debug) $(LDFLAGS)
95proxy: $(OBJECTS_proxy) 100proxy: $(OBJECTS_proxy)
96 $(CC) -o $@ $(OBJECTS_proxy) $(CFLAGS_production) $(LDFLAGS) 101 $(CC) -o $@ $(OBJECTS_proxy) $(CFLAGS_production) $(LDFLAGS) $(LDFLAGS_libowfat)
97proxy.debug: $(OBJECTS_proxy_debug) 102proxy.debug: $(OBJECTS_proxy_debug)
98 $(CC) -o $@ $(OBJECTS_proxy_debug) $(LDFLAGS) 103 $(CC) -o $@ $(OBJECTS_proxy_debug) $(LDFLAGS) $(LDFLAGS_libowfat)
99 104
100$(OBJECTS): $(HEADERS) 105$(OBJECTS): $(HEADERS)
101$(OBJECTS_debug): $(HEADERS) 106$(OBJECTS_debug): $(HEADERS)
diff --git a/opentracker.c b/opentracker.c
index 7de6c6a..21eeb42 100644
--- a/opentracker.c
+++ b/opentracker.c
@@ -21,9 +21,6 @@
21#include <syslog.h> 21#include <syslog.h>
22#endif 22#endif
23 23
24/* Libowfat */
25#include "io.h"
26
27/* Opentracker */ 24/* Opentracker */
28#include "ot_accesslist.h" 25#include "ot_accesslist.h"
29#include "ot_config.h" 26#include "ot_config.h"
@@ -34,6 +31,7 @@
34#include "ot_mutex.h" 31#include "ot_mutex.h"
35#include "ot_random.h" 32#include "ot_random.h"
36#include "ot_scan.h" 33#include "ot_scan.h"
34#include "ot_event.h"
37#include "ot_fdstate.h" 35#include "ot_fdstate.h"
38#include "ot_socket.h" 36#include "ot_socket.h"
39#include "ot_stats.h" 37#include "ot_stats.h"
@@ -130,14 +128,15 @@ static void handle_dead(const int64_t sock) {
130 } 128 }
131 /* The generation has to move before the kernel can reissue the number */ 129 /* The generation has to move before the kernel can reissue the number */
132 fdstate_close(sock); 130 fdstate_close(sock);
133 io_close(sock); 131 event_del((int)sock);
132 close((int)sock);
134} 133}
135 134
136static void handle_read(const int64_t sock, struct ot_workstruct *ws) { 135static void handle_read(const int64_t sock, struct ot_workstruct *ws) {
137 struct http_data *cookie = fdstate_cookie(sock); 136 struct http_data *cookie = fdstate_cookie(sock);
138 ssize_t byte_count = io_tryread(sock, ws->inbuf, G_INBUF_SIZE); 137 ssize_t byte_count = read((int)sock, ws->inbuf, G_INBUF_SIZE);
139 138
140 if (byte_count == 0 || byte_count == -3) { 139 if (byte_count == 0 || (byte_count == -1 && errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)) {
141 handle_dead(sock); 140 handle_dead(sock);
142 return; 141 return;
143 } 142 }
@@ -197,7 +196,7 @@ static void handle_write(const int64_t sock) {
197 196
198 /* In a chunked transfer, wait for the next piece once everything queued has gone out */ 197 /* In a chunked transfer, wait for the next piece once everything queued has gone out */
199 if (chunked) 198 if (chunked)
200 io_dontwantwrite(sock); 199 http_interest_drop(sock, cookie, EVENT_OUT);
201 else 200 else
202 handle_dead(sock); 201 handle_dead(sock);
203} 202}
@@ -210,25 +209,30 @@ static void handle_accept(const int64_t serversocket) {
210 209
211 while ((sock = socket_accept(serversocket, ip, &port)) != -1) { 210 while ((sock = socket_accept(serversocket, ip, &port)) != -1) {
212 211
213 /* Put fd into a non-blocking mode */ 212 socket_set_blocking((int)sock, 0);
214 io_nonblock(sock);
215 213
216 if (!io_fd(sock) || !(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) { 214 if (!(cookie = (struct http_data *)malloc(sizeof(struct http_data)))) {
217 io_close(sock); 215 close((int)sock);
218 continue; 216 continue;
219 } 217 }
220 memset(cookie, 0, sizeof(struct http_data)); 218 memset(cookie, 0, sizeof(struct http_data));
221 memcpy(cookie->ip, ip, sizeof(ot_ip6)); 219 memcpy(cookie->ip, ip, sizeof(ot_ip6));
220 cookie->interest = EVENT_IN;
222 221
223 fdstate_open(sock, cookie, g_now_seconds + OT_CLIENT_TIMEOUT); 222 if (event_add((int)sock, EVENT_IN, fdstate_open(sock, cookie, g_now_seconds + OT_CLIENT_TIMEOUT)) == -1) {
224 io_wantread(sock); 223 fdstate_close(sock);
224 free(cookie);
225 close((int)sock);
226 continue;
227 }
225 228
226 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip); 229 stats_issue_event(EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ip);
227
228 } 230 }
229 io_eagain(serversocket);
230} 231}
231 232
233/* How many ready descriptors one wait hands back at a time */
234#define OT_EVENT_BATCH 512
235
232static void *server_mainloop(void *args) { 236static void *server_mainloop(void *args) {
233 struct ot_workstruct ws; 237 struct ot_workstruct ws;
234 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL; 238 time_t next_timeout_check = g_now_seconds + OT_CLIENT_TIMEOUT_CHECKINTERVAL;
@@ -251,28 +255,42 @@ static void *server_mainloop(void *args) {
251 random_bytes(ws.rand48_state, sizeof(ws.rand48_state)); 255 random_bytes(ws.rand48_state, sizeof(ws.rand48_state));
252 256
253 for (;;) { 257 for (;;) {
254 int64_t sock; 258 ot_event ready[OT_EVENT_BATCH];
259 int64_t sock;
260 int count, i;
255 261
256 io_wait(); 262 count = event_wait(ready, OT_EVENT_BATCH, OT_CLIENT_TIMEOUT_CHECKINTERVAL * 1000);
263
264 for (i = 0; i < count; ++i) {
265 const void *cookie;
266
267 sock = ready[i].fd;
268 /* A descriptor closed earlier in this same batch may already have been
269 handed out again by accept, so an event is only ours if the
270 generation it was registered under is still the one in place */
271 if (fdstate_generation((int)sock) != ready[i].generation)
272 continue;
273 cookie = fdstate_cookie((int)sock);
257 274
258 while ((sock = io_canread()) != -1) {
259 const void *cookie = fdstate_cookie(sock);
260 if ((intptr_t)cookie == FLAG_TCP) 275 if ((intptr_t)cookie == FLAG_TCP)
261 handle_accept(sock); 276 handle_accept(sock);
262 else if ((intptr_t)cookie == FLAG_UDP) 277 else if ((intptr_t)cookie == FLAG_UDP)
263 handle_udp6(sock, &ws); 278 handle_udp6(sock, &ws);
264 else if ((intptr_t)cookie == FLAG_SELFPIPE) 279 else if ((intptr_t)cookie == FLAG_SELFPIPE)
265 io_tryread(sock, ws.inbuf, G_INBUF_SIZE); 280 while (read((int)sock, ws.inbuf, G_INBUF_SIZE) > 0)
266 else 281 ;
267 handle_read(sock, &ws); 282 else {
283 if (ready[i].what & EVENT_IN)
284 handle_read(sock, &ws);
285 /* The read may have closed it, so look again before writing */
286 if ((ready[i].what & EVENT_OUT) && fdstate_generation((int)sock) == ready[i].generation)
287 handle_write(sock);
288 }
268 } 289 }
269 290
270 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1) 291 while ((sock = mutex_workqueue_popresult(&iovec_entries, &iovector, &is_partial)) != -1)
271 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial); 292 http_sendiovecdata(sock, &ws, iovec_entries, iovector, is_partial);
272 293
273 while ((sock = io_canwrite()) != -1)
274 handle_write(sock);
275
276 if (g_now_seconds > next_timeout_check) { 294 if (g_now_seconds > next_timeout_check) {
277 int cursor = 0; 295 int cursor = 0;
278 296
@@ -319,11 +337,8 @@ static void listen_bind_one(ot_listen *entry) {
319 panic("socket_udp_bind"); 337 panic("socket_udp_bind");
320 } 338 }
321 339
322 if (!io_fd(entry->sock)) 340 if (event_add((int)entry->sock, EVENT_IN, fdstate_open(entry->sock, (void *)entry->proto, 0)) == -1)
323 panic("io_fd"); 341 panic("event_add");
324
325 fdstate_open(entry->sock, (void *)entry->proto, 0);
326 io_wantread(entry->sock);
327 342
328#ifdef _DEBUG 343#ifdef _DEBUG
329 fputs(" success.\n", stderr); 344 fputs(" success.\n", stderr);
@@ -352,7 +367,8 @@ static void listen_start_udp_workers(void) {
352 if (entry->proto != FLAG_UDP || entry->workers <= 0) 367 if (entry->proto != FLAG_UDP || entry->workers <= 0)
353 continue; 368 continue;
354 369
355 io_block(entry->sock); 370 socket_set_blocking((int)entry->sock, 1);
371 event_del((int)entry->sock);
356 udp_workers_install(entry->sock, (unsigned int)entry->workers); 372 udp_workers_install(entry->sock, (unsigned int)entry->workers);
357 } 373 }
358} 374}
@@ -453,6 +469,8 @@ int main(int argc, char **argv) {
453 random_init(); 469 random_init();
454 if (fdstate_init() == -1) 470 if (fdstate_init() == -1)
455 panic("fdstate_init"); 471 panic("fdstate_init");
472 if (event_init() == -1)
473 panic("event_init");
456 config_parse(argc, argv); 474 config_parse(argc, argv);
457 475
458 listen_bind_all(); 476 listen_bind_all();
@@ -471,15 +489,15 @@ int main(int argc, char **argv) {
471 pthread_create(&thread_id, NULL, time_caching_worker, NULL); 489 pthread_create(&thread_id, NULL, time_caching_worker, NULL);
472 490
473 /* Create our self pipe which allows us to interrupt mainloops 491 /* Create our self pipe which allows us to interrupt mainloops
474 io_wait in case some data is available to send out */ 492 wait in case some data is available to send out */
475 if (pipe(g_self_pipe) == -1) 493 if (pipe(g_self_pipe) == -1)
476 panic("selfpipe failed: "); 494 panic("selfpipe failed: ");
477 if (!io_fd(g_self_pipe[0])) 495 /* Both ends have to be non blocking: the loop drains the read end until it
478 panic("selfpipe io_fd failed: "); 496 is empty, and a worker nudging a full pipe has already made its point */
479 if (!io_fd(g_self_pipe[1])) 497 socket_set_blocking(g_self_pipe[0], 0);
480 panic("selfpipe io_fd failed: "); 498 socket_set_blocking(g_self_pipe[1], 0);
481 fdstate_open(g_self_pipe[0], (void *)FLAG_SELFPIPE, 0); 499 if (event_add(g_self_pipe[0], EVENT_IN, fdstate_open(g_self_pipe[0], (void *)FLAG_SELFPIPE, 0)) == -1)
482 io_wantread(g_self_pipe[0]); 500 panic("selfpipe event_add");
483 501
484 /* Init all sub systems. This call may fail with an exit() */ 502 /* Init all sub systems. This call may fail with an exit() */
485 trackerlogic_init(); 503 trackerlogic_init();
@@ -499,6 +517,7 @@ int main(int argc, char **argv) {
499 517
500 server_mainloop(0); 518 server_mainloop(0);
501 519
520 event_deinit();
502 fdstate_deinit(); 521 fdstate_deinit();
503 return 0; 522 return 0;
504} 523}
diff --git a/ot_accesslist.c b/ot_accesslist.c
index 79a11a5..724978e 100644
--- a/ot_accesslist.c
+++ b/ot_accesslist.c
@@ -21,8 +21,6 @@
21#include <errno.h> 21#include <errno.h>
22#endif 22#endif
23 23
24/* Libowfat */
25
26/* Opentracker */ 24/* Opentracker */
27#include "ot_accesslist.h" 25#include "ot_accesslist.h"
28#include "ot_hex.h" 26#include "ot_hex.h"
diff --git a/ot_clean.c b/ot_clean.c
index 825290d..bf0504c 100644
--- a/ot_clean.c
+++ b/ot_clean.c
@@ -8,9 +8,6 @@
8#include <string.h> 8#include <string.h>
9#include <unistd.h> 9#include <unistd.h>
10 10
11/* Libowfat */
12#include "io.h"
13
14/* Opentracker */ 11/* Opentracker */
15#include "ot_accesslist.h" 12#include "ot_accesslist.h"
16#include "ot_clean.h" 13#include "ot_clean.h"
diff --git a/ot_event.c b/ot_event.c
index d24227d..ce0feef 100644
--- a/ot_event.c
+++ b/ot_event.c
@@ -60,7 +60,7 @@ static int event_ctl(int op, int fd, int what, uint32_t generation) {
60 struct epoll_event ev; 60 struct epoll_event ev;
61 61
62 memset(&ev, 0, sizeof(ev)); 62 memset(&ev, 0, sizeof(ev));
63 ev.events = (what & EVENT_READ ? (uint32_t)EPOLLIN : 0) | (what & EVENT_WRITE ? (uint32_t)EPOLLOUT : 0); 63 ev.events = (what & EVENT_IN ? (uint32_t)EPOLLIN : 0) | (what & EVENT_OUT ? (uint32_t)EPOLLOUT : 0);
64 /* The generation rides along inside the kernel, so an event says which 64 /* The generation rides along inside the kernel, so an event says which
65 connection it belongs to without anybody looking it up */ 65 connection it belongs to without anybody looking it up */
66 ev.data.u64 = ((uint64_t)generation << 32) | (uint32_t)fd; 66 ev.data.u64 = ((uint64_t)generation << 32) | (uint32_t)fd;
@@ -92,8 +92,8 @@ int event_wait(ot_event *out, int max, int timeout_ms) {
92 out[i].generation = (uint32_t)(g_ready[i].data.u64 >> 32); 92 out[i].generation = (uint32_t)(g_ready[i].data.u64 >> 32);
93 /* A hangup or an error is reported as both, so whichever side the caller 93 /* A hangup or an error is reported as both, so whichever side the caller
94 was waiting on gets to notice */ 94 was waiting on gets to notice */
95 out[i].what = (events & (EPOLLIN | EPOLLHUP | EPOLLERR) ? EVENT_READ : 0) | 95 out[i].what = (events & (EPOLLIN | EPOLLHUP | EPOLLERR) ? EVENT_IN : 0) |
96 (events & (EPOLLOUT | EPOLLHUP | EPOLLERR) ? EVENT_WRITE : 0); 96 (events & (EPOLLOUT | EPOLLHUP | EPOLLERR) ? EVENT_OUT : 0);
97 } 97 }
98 return count; 98 return count;
99} 99}
@@ -138,9 +138,9 @@ static int event_change(int fd, int what, uint32_t generation, int deleting) {
138 int succeeded = 0, count, i; 138 int succeeded = 0, count, i;
139 139
140 EV_SET(&change[0], (uintptr_t)fd, EVFILT_READ, 140 EV_SET(&change[0], (uintptr_t)fd, EVFILT_READ,
141 EV_RECEIPT | ((deleting || !(what & EVENT_READ)) ? EV_DELETE : EV_ADD), 0, 0, udata); 141 EV_RECEIPT | ((deleting || !(what & EVENT_IN)) ? EV_DELETE : EV_ADD), 0, 0, udata);
142 EV_SET(&change[1], (uintptr_t)fd, EVFILT_WRITE, 142 EV_SET(&change[1], (uintptr_t)fd, EVFILT_WRITE,
143 EV_RECEIPT | ((deleting || !(what & EVENT_WRITE)) ? EV_DELETE : EV_ADD), 0, 0, udata); 143 EV_RECEIPT | ((deleting || !(what & EVENT_OUT)) ? EV_DELETE : EV_ADD), 0, 0, udata);
144 144
145 if ((count = kevent(g_kqueue, change, 2, result, 2, NULL)) == -1) 145 if ((count = kevent(g_kqueue, change, 2, result, 2, NULL)) == -1)
146 return -1; 146 return -1;
@@ -197,8 +197,8 @@ int event_wait(ot_event *out, int max, int timeout_ms) {
197 197
198 out[i].fd = (int)(uint32_t)udata; 198 out[i].fd = (int)(uint32_t)udata;
199 out[i].generation = (uint32_t)(udata >> 32); 199 out[i].generation = (uint32_t)(udata >> 32);
200 out[i].what = ((g_ready[i].filter == EVFILT_READ || eof) ? EVENT_READ : 0) | 200 out[i].what = ((g_ready[i].filter == EVFILT_READ || eof) ? EVENT_IN : 0) |
201 ((g_ready[i].filter == EVFILT_WRITE || eof) ? EVENT_WRITE : 0); 201 ((g_ready[i].filter == EVFILT_WRITE || eof) ? EVENT_OUT : 0);
202 } 202 }
203 return count; 203 return count;
204} 204}
@@ -232,7 +232,7 @@ void event_deinit(void) {
232} 232}
233 233
234static short event_to_poll(int what) { 234static short event_to_poll(int what) {
235 return (short)((what & EVENT_READ ? POLLIN : 0) | (what & EVENT_WRITE ? POLLOUT : 0)); 235 return (short)((what & EVENT_IN ? POLLIN : 0) | (what & EVENT_OUT ? POLLOUT : 0));
236} 236}
237 237
238static int event_room_for(int fd) { 238static int event_room_for(int fd) {
@@ -322,8 +322,8 @@ int event_wait(ot_event *out, int max, int timeout_ms) {
322 continue; 322 continue;
323 out[found].fd = g_pfds[i].fd; 323 out[found].fd = g_pfds[i].fd;
324 out[found].generation = g_generation[i]; 324 out[found].generation = g_generation[i];
325 out[found].what = (revents & (POLLIN | POLLHUP | POLLERR | POLLNVAL) ? EVENT_READ : 0) | 325 out[found].what = (revents & (POLLIN | POLLHUP | POLLERR | POLLNVAL) ? EVENT_IN : 0) |
326 (revents & (POLLOUT | POLLHUP | POLLERR | POLLNVAL) ? EVENT_WRITE : 0); 326 (revents & (POLLOUT | POLLHUP | POLLERR | POLLNVAL) ? EVENT_OUT : 0);
327 ++found; 327 ++found;
328 } 328 }
329 return found; 329 return found;
diff --git a/ot_event.h b/ot_event.h
index c1627ab..6023134 100644
--- a/ot_event.h
+++ b/ot_event.h
@@ -14,7 +14,7 @@
14 the connection it is holding from one for a connection that has since been 14 the connection it is holding from one for a connection that has since been
15 closed and had its number reused. */ 15 closed and had its number reused. */
16 16
17enum { EVENT_READ = 1, EVENT_WRITE = 2 }; 17enum { EVENT_IN = 1, EVENT_OUT = 2 };
18 18
19typedef struct { 19typedef struct {
20 int fd; 20 int fd;
diff --git a/ot_fdstate.c b/ot_fdstate.c
index 7f73d3d..537bcb0 100644
--- a/ot_fdstate.c
+++ b/ot_fdstate.c
@@ -99,6 +99,12 @@ uint32_t fdstate_open(int fd, void *cookie, ot_time expiry) {
99 return FD_GEN(word); 99 return FD_GEN(word);
100} 100}
101 101
102uint32_t fdstate_generation(int fd) {
103 ot_fdslot *slot = fdstate_slot(fd);
104
105 return slot ? FD_GEN(atomic_load_explicit(&slot->state, memory_order_relaxed)) : 0;
106}
107
102int fdstate_claim(int fd, uint32_t generation) { 108int fdstate_claim(int fd, uint32_t generation) {
103 ot_fdslot *slot = fdstate_slot(fd); 109 ot_fdslot *slot = fdstate_slot(fd);
104 uint64_t word; 110 uint64_t word;
diff --git a/ot_fdstate.h b/ot_fdstate.h
index 88f685d..c09f018 100644
--- a/ot_fdstate.h
+++ b/ot_fdstate.h
@@ -31,6 +31,10 @@ size_t fdstate_slots(void);
31 generation to quote when asking for it back. expiry of 0 never expires. */ 31 generation to quote when asking for it back. expiry of 0 never expires. */
32uint32_t fdstate_open(int fd, void *cookie, ot_time expiry); 32uint32_t fdstate_open(int fd, void *cookie, ot_time expiry);
33 33
34/* Which generation a descriptor currently carries, to check an event that
35 was handed out earlier against the connection living there now. */
36uint32_t fdstate_generation(int fd);
37
34/* Ask for exclusive use. Returns 0 if the descriptor has been recycled since 38/* Ask for exclusive use. Returns 0 if the descriptor has been recycled since
35 generation was handed out, or if somebody else is using it. */ 39 generation was handed out, or if somebody else is using it. */
36int fdstate_claim(int fd, uint32_t generation); 40int fdstate_claim(int fd, uint32_t generation);
diff --git a/ot_fullscrape.c b/ot_fullscrape.c
index 0dee5c2..2ba3b24 100644
--- a/ot_fullscrape.c
+++ b/ot_fullscrape.c
@@ -17,9 +17,6 @@
17#include <zstd.h> 17#include <zstd.h>
18#endif 18#endif
19 19
20/* Libowfat */
21#include "io.h"
22
23/* Opentracker */ 20/* Opentracker */
24#include "ot_hex.h" 21#include "ot_hex.h"
25#include "ot_fullscrape.h" 22#include "ot_fullscrape.h"
diff --git a/ot_http.c b/ot_http.c
index 3c135cb..5e10d59 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -14,9 +14,6 @@
14#include <sys/types.h> 14#include <sys/types.h>
15#include <unistd.h> 15#include <unistd.h>
16 16
17/* Libowfat */
18#include "io.h"
19
20/* Opentracker */ 17/* Opentracker */
21#include "ot_accesslist.h" 18#include "ot_accesslist.h"
22#include "ot_fullscrape.h" 19#include "ot_fullscrape.h"
@@ -25,6 +22,7 @@
25#include "ot_ip.h" 22#include "ot_ip.h"
26#include "ot_mutex.h" 23#include "ot_mutex.h"
27#include "ot_scan.h" 24#include "ot_scan.h"
25#include "ot_event.h"
28#include "ot_fdstate.h" 26#include "ot_fdstate.h"
29#include "ot_stats.h" 27#include "ot_stats.h"
30#include "ot_urlencoded.h" 28#include "ot_urlencoded.h"
@@ -43,7 +41,7 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
43 ssize_t written_size; 41 ssize_t written_size;
44 42
45 if (!cookie) { 43 if (!cookie) {
46 io_close(sock); 44 event_del((int)sock), close((int)sock);
47 return; 45 return;
48 } 46 }
49 47
@@ -67,7 +65,7 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
67 if ((written_size < 0) || ((written_size == ws->reply_size) && !ws->keep_alive)) { 65 if ((written_size < 0) || ((written_size == ws->reply_size) && !ws->keep_alive)) {
68 buf_reset(&cookie->request); 66 buf_reset(&cookie->request);
69 free(cookie); 67 free(cookie);
70 io_close(sock); 68 event_del((int)sock), close((int)sock);
71 return; 69 return;
72 } 70 }
73 71
@@ -77,7 +75,7 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
77 if (!(outbuf = malloc(ws->reply_size - written_size))) { 75 if (!(outbuf = malloc(ws->reply_size - written_size))) {
78 buf_reset(&cookie->request); 76 buf_reset(&cookie->request);
79 free(cookie); 77 free(cookie);
80 io_close(sock); 78 event_del((int)sock), close((int)sock);
81 return; 79 return;
82 } 80 }
83 81
@@ -88,7 +86,7 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
88 free(outbuf); 86 free(outbuf);
89 buf_reset(&cookie->request); 87 buf_reset(&cookie->request);
90 free(cookie); 88 free(cookie);
91 io_close(sock); 89 event_del((int)sock), close((int)sock);
92 return; 90 return;
93 } 91 }
94 } 92 }
@@ -98,9 +96,9 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
98 /* writeable short data sockets just have a tcp timeout */ 96 /* writeable short data sockets just have a tcp timeout */
99 if (!ws->keep_alive) { 97 if (!ws->keep_alive) {
100 fdstate_set_expiry(sock, 0); 98 fdstate_set_expiry(sock, 0);
101 io_dontwantread(sock); 99 http_interest_drop(sock, cookie, EVENT_IN);
102 } 100 }
103 io_wantwrite(sock); 101 http_interest_add(sock, cookie, EVENT_OUT);
104 } 102 }
105} 103}
106 104
@@ -113,6 +111,21 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
113#define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP) 111#define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP)
114#define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404) 112#define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404)
115#define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500) 113#define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500)
114static void http_interest(const int64_t sock, struct http_data *cookie, int what) {
115 if (cookie->interest == what)
116 return;
117 cookie->interest = what;
118 event_modify((int)sock, what, fdstate_generation((int)sock));
119}
120
121void http_interest_add(const int64_t sock, struct http_data *cookie, int what) {
122 http_interest(sock, cookie, cookie->interest | what);
123}
124
125void http_interest_drop(const int64_t sock, struct http_data *cookie, int what) {
126 http_interest(sock, cookie, cookie->interest & ~what);
127}
128
116ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) { 129ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) {
117 const char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", 130 const char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required",
118 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"}; 131 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"};
@@ -157,7 +170,7 @@ ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t
157 170
158 /* If we came here, wait for the answer is over */ 171 /* If we came here, wait for the answer is over */
159 if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) { 172 if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) {
160 io_dontwantread(sock); 173 http_interest_drop(sock, cookie, EVENT_IN);
161 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK; 174 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK;
162 } 175 }
163 176
@@ -208,7 +221,7 @@ ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t
208 } 221 }
209 222
210 fdstate_set_expiry(sock, g_now_seconds + OT_CLIENT_TIMEOUT_SEND); 223 fdstate_set_expiry(sock, g_now_seconds + OT_CLIENT_TIMEOUT_SEND);
211 io_wantwrite(sock); 224 http_interest_add(sock, cookie, EVENT_OUT);
212 return 0; 225 return 0;
213} 226}
214 227
@@ -303,7 +316,7 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
303 /* Clients waiting for us should not easily timeout */ 316 /* Clients waiting for us should not easily timeout */
304 fdstate_set_expiry(sock, 0); 317 fdstate_set_expiry(sock, 0);
305 fullscrape_deliver(sock, format); 318 fullscrape_deliver(sock, format);
306 io_dontwantread(sock); 319 http_interest_drop(sock, cookie, EVENT_IN);
307 return ws->reply_size = -2; 320 return ws->reply_size = -2;
308 } 321 }
309#endif 322#endif
@@ -396,7 +409,7 @@ static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct *
396 /* Clients waiting for us should not easily timeout */ 409 /* Clients waiting for us should not easily timeout */
397 fdstate_set_expiry(sock, 0); 410 fdstate_set_expiry(sock, 0);
398 fullscrape_deliver(sock, format); 411 fullscrape_deliver(sock, format);
399 io_dontwantread(sock); 412 http_interest_drop(sock, cookie, EVENT_IN);
400 return ws->reply_size = -2; 413 return ws->reply_size = -2;
401} 414}
402#endif 415#endif
diff --git a/ot_http.h b/ot_http.h
index 003b545..1631220 100644
--- a/ot_http.h
+++ b/ot_http.h
@@ -11,6 +11,7 @@
11#include <sys/uio.h> 11#include <sys/uio.h>
12 12
13#include "ot_batch.h" 13#include "ot_batch.h"
14#include "ot_event.h"
14#include "ot_buf.h" 15#include "ot_buf.h"
15#include "trackerlogic.h" 16#include "trackerlogic.h"
16 17
@@ -25,11 +26,16 @@ typedef enum {
25 26
26struct http_data { 27struct http_data {
27 ot_buf request; 28 ot_buf request;
29 int interest; /* EVENT_IN and EVENT_OUT as asked for */
28 ot_batch *batch; 30 ot_batch *batch;
29 ot_ip6 ip; 31 ot_ip6 ip;
30 STRUCT_HTTP_FLAG flag; 32 STRUCT_HTTP_FLAG flag;
31}; 33};
32 34
35/* Add to or drop from what this connection is waiting to be told about */
36void http_interest_add(const int64_t s, struct http_data *cookie, int what);
37void http_interest_drop(const int64_t s, struct http_data *cookie, int what);
38
33ssize_t http_handle_request(const int64_t s, struct ot_workstruct *ws); 39ssize_t http_handle_request(const int64_t s, struct ot_workstruct *ws);
34ssize_t http_sendiovecdata(const int64_t s, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial); 40ssize_t http_sendiovecdata(const int64_t s, struct ot_workstruct *ws, size_t iovec_entries, struct iovec *iovector, int is_partial);
35ssize_t http_issue_error(const int64_t s, struct ot_workstruct *ws, int code); 41ssize_t http_issue_error(const int64_t s, struct ot_workstruct *ws, int code);
diff --git a/ot_iovec.c b/ot_iovec.c
index 2ee455c..7e5903f 100644
--- a/ot_iovec.c
+++ b/ot_iovec.c
@@ -7,8 +7,6 @@
7#include <stdlib.h> 7#include <stdlib.h>
8#include <sys/uio.h> 8#include <sys/uio.h>
9 9
10/* Libowfat */
11
12/* Opentracker */ 10/* Opentracker */
13#include "ot_iovec.h" 11#include "ot_iovec.h"
14 12
diff --git a/ot_livesync.h b/ot_livesync.h
index 5b9fa0e..4725023 100644
--- a/ot_livesync.h
+++ b/ot_livesync.h
@@ -6,7 +6,6 @@
6#ifndef OT_LIVESYNC_H__ 6#ifndef OT_LIVESYNC_H__
7#define OT_LIVESYNC_H__ 7#define OT_LIVESYNC_H__
8 8
9#include "io.h"
10#include "trackerlogic.h" 9#include "trackerlogic.h"
11 10
12/* 11/*
diff --git a/ot_mutex.c b/ot_mutex.c
index 2a8cbf5..37d9962 100644
--- a/ot_mutex.c
+++ b/ot_mutex.c
@@ -8,11 +8,10 @@
8#include <pthread.h> 8#include <pthread.h>
9#include <stdio.h> 9#include <stdio.h>
10#include <stdlib.h> 10#include <stdlib.h>
11#include <unistd.h>
11#include <string.h> 12#include <string.h>
12#include <sys/uio.h> 13#include <sys/uio.h>
13 14
14/* Libowfat */
15#include "io.h"
16 15
17/* Opentracker */ 16/* Opentracker */
18#include "ot_iovec.h" 17#include "ot_iovec.h"
@@ -193,7 +192,8 @@ int mutex_workqueue_pushresult(ot_taskid taskid, size_t iovec_entries, struct io
193 /* Release lock */ 192 /* Release lock */
194 pthread_mutex_unlock(&tasklist_mutex); 193 pthread_mutex_unlock(&tasklist_mutex);
195 194
196 io_trywrite(g_self_pipe[1], &byte, 1); 195 /* A full pipe has already done this nudge's job, so a failure is fine */
196 (void)!write(g_self_pipe[1], &byte, 1);
197 197
198 /* Indicate whether the worker has to throw away results */ 198 /* Indicate whether the worker has to throw away results */
199 return task ? 0 : -1; 199 return task ? 0 : -1;
@@ -221,7 +221,8 @@ int mutex_workqueue_pushchunked(ot_taskid taskid, struct iovec *iovec) {
221 /* Release lock */ 221 /* Release lock */
222 pthread_mutex_unlock(&tasklist_mutex); 222 pthread_mutex_unlock(&tasklist_mutex);
223 223
224 io_trywrite(g_self_pipe[1], &byte, 1); 224 /* A full pipe has already done this nudge's job, so a failure is fine */
225 (void)!write(g_self_pipe[1], &byte, 1);
225 226
226 /* Indicate whether the worker has to throw away results */ 227 /* Indicate whether the worker has to throw away results */
227 return task ? 0 : -1; 228 return task ? 0 : -1;
diff --git a/ot_socket.c b/ot_socket.c
index 84020ca..576087f 100644
--- a/ot_socket.c
+++ b/ot_socket.c
@@ -40,14 +40,16 @@ static void ip_from_sockaddr(ot_ip6 ip, uint16_t *port, const struct sockaddr_st
40 } 40 }
41} 41}
42 42
43static int set_nonblocking(int s) { 43int socket_set_blocking(int s, int blocking) {
44 int flags = fcntl(s, F_GETFL, 0); 44 int flags = fcntl(s, F_GETFL, 0);
45 45
46 if (flags == -1) 46 if (flags == -1)
47 return -1; 47 return -1;
48 return fcntl(s, F_SETFL, flags | O_NONBLOCK); 48 return fcntl(s, F_SETFL, blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK));
49} 49}
50 50
51static int set_nonblocking(int s) { return socket_set_blocking(s, 0); }
52
51/* Close without letting the failure we are about to report be overwritten */ 53/* Close without letting the failure we are about to report be overwritten */
52static int close_and_fail(int s) { 54static int close_and_fail(int s) {
53 int saved = errno; 55 int saved = errno;
diff --git a/ot_socket.h b/ot_socket.h
index 21d04b1..aa4e2d2 100644
--- a/ot_socket.h
+++ b/ot_socket.h
@@ -27,6 +27,7 @@ int socket_udp_bind(const ot_ip6 ip, uint16_t port, socket_sharing sharing);
27int socket_tcp_connect(const ot_ip6 srcip, uint16_t srcport, const ot_ip6 dstip, uint16_t dstport); 27int socket_tcp_connect(const ot_ip6 srcip, uint16_t srcport, const ot_ip6 dstip, uint16_t dstport);
28int socket_is_connected(int s); 28int socket_is_connected(int s);
29int socket_accept(int s, ot_ip6 ip, uint16_t *port); 29int socket_accept(int s, ot_ip6 ip, uint16_t *port);
30int socket_set_blocking(int s, int blocking);
30 31
31ssize_t socket_recv(int s, void *buf, size_t len, ot_ip6 ip, uint16_t *port); 32ssize_t socket_recv(int s, void *buf, size_t len, ot_ip6 ip, uint16_t *port);
32ssize_t socket_send(int s, const void *buf, size_t len, const ot_ip6 ip, uint16_t port); 33ssize_t socket_send(int s, const void *buf, size_t len, const ot_ip6 ip, uint16_t port);
diff --git a/ot_stats.c b/ot_stats.c
index ceeb89d..bee1f93 100644
--- a/ot_stats.c
+++ b/ot_stats.c
@@ -16,9 +16,6 @@
16#include <syslog.h> 16#include <syslog.h>
17#endif 17#endif
18 18
19/* Libowfat */
20#include "io.h"
21
22/* Opentracker */ 19/* Opentracker */
23#include "ot_accesslist.h" 20#include "ot_accesslist.h"
24#include "ot_hex.h" 21#include "ot_hex.h"
diff --git a/ot_sync.c b/ot_sync.c
index 1a6bebc..f958a20 100644
--- a/ot_sync.c
+++ b/ot_sync.c
@@ -10,9 +10,6 @@
10#include <sys/types.h> 10#include <sys/types.h>
11#include <sys/uio.h> 11#include <sys/uio.h>
12 12
13/* Libowfat */
14#include "io.h"
15
16/* Opentracker */ 13/* Opentracker */
17#include "ot_iovec.h" 14#include "ot_iovec.h"
18#include "ot_mutex.h" 15#include "ot_mutex.h"
diff --git a/ot_udp.c b/ot_udp.c
index 7f6517f..5bf9d52 100644
--- a/ot_udp.c
+++ b/ot_udp.c
@@ -10,9 +10,6 @@
10#include <stdlib.h> 10#include <stdlib.h>
11#include <string.h> 11#include <string.h>
12 12
13/* Libowfat */
14#include "io.h"
15
16/* Opentracker */ 13/* Opentracker */
17#include "ot_ip.h" 14#include "ot_ip.h"
18#include "ot_random.h" 15#include "ot_random.h"
diff --git a/tests/t_event.c b/tests/t_event.c
index 306f8cd..5509f19 100644
--- a/tests/t_event.c
+++ b/tests/t_event.c
@@ -59,18 +59,18 @@ static void case_readable(void) {
59 test_case("a descriptor with something to read is reported, with its generation"); 59 test_case("a descriptor with something to read is reported, with its generation");
60 pair_open(); 60 pair_open();
61 CHECK(sv[0] != -1); 61 CHECK(sv[0] != -1);
62 CHECK_INT(event_add(sv[0], EVENT_READ, 4711), 0); 62 CHECK_INT(event_add(sv[0], EVENT_IN, 4711), 0);
63 CHECK_INT(write(sv[1], "x", 1), 1); 63 CHECK_INT(write(sv[1], "x", 1), 1);
64 CHECK_INT(wait_for(sv[0], EVENT_READ, 1000, &generation), 1); 64 CHECK_INT(wait_for(sv[0], EVENT_IN, 1000, &generation), 1);
65 CHECK_INT(generation, 4711); 65 CHECK_INT(generation, 4711);
66 66
67 test_case("and keeps being reported until it is read"); 67 test_case("and keeps being reported until it is read");
68 CHECK_INT(wait_for(sv[0], EVENT_READ, 1000, NULL), 1); 68 CHECK_INT(wait_for(sv[0], EVENT_IN, 1000, NULL), 1);
69 { 69 {
70 char scratch[4]; 70 char scratch[4];
71 CHECK_INT(read(sv[0], scratch, sizeof(scratch)), 1); 71 CHECK_INT(read(sv[0], scratch, sizeof(scratch)), 1);
72 } 72 }
73 CHECK_INT(wait_for(sv[0], EVENT_READ, 50, NULL), 0); 73 CHECK_INT(wait_for(sv[0], EVENT_IN, 50, NULL), 0);
74 74
75 CHECK_INT(event_del(sv[0]), 0); 75 CHECK_INT(event_del(sv[0]), 0);
76 pair_close(); 76 pair_close();
@@ -80,12 +80,12 @@ static void case_writable(void) {
80 test_case("a descriptor with room to write is reported"); 80 test_case("a descriptor with room to write is reported");
81 pair_open(); 81 pair_open();
82 CHECK(sv[0] != -1); 82 CHECK(sv[0] != -1);
83 CHECK_INT(event_add(sv[0], EVENT_WRITE, 1), 0); 83 CHECK_INT(event_add(sv[0], EVENT_OUT, 1), 0);
84 CHECK_INT(wait_for(sv[0], EVENT_WRITE, 1000, NULL), 1); 84 CHECK_INT(wait_for(sv[0], EVENT_OUT, 1000, NULL), 1);
85 85
86 test_case("and is not, once we say we no longer care"); 86 test_case("and is not, once we say we no longer care");
87 CHECK_INT(event_modify(sv[0], EVENT_READ, 1), 0); 87 CHECK_INT(event_modify(sv[0], EVENT_IN, 1), 0);
88 CHECK_INT(wait_for(sv[0], EVENT_WRITE, 50, NULL), 0); 88 CHECK_INT(wait_for(sv[0], EVENT_OUT, 50, NULL), 0);
89 89
90 CHECK_INT(event_del(sv[0]), 0); 90 CHECK_INT(event_del(sv[0]), 0);
91 pair_close(); 91 pair_close();
@@ -95,13 +95,13 @@ static void case_interest_is_separate(void) {
95 test_case("asking only about writing does not report reading"); 95 test_case("asking only about writing does not report reading");
96 pair_open(); 96 pair_open();
97 CHECK(sv[0] != -1); 97 CHECK(sv[0] != -1);
98 CHECK_INT(event_add(sv[0], EVENT_WRITE, 1), 0); 98 CHECK_INT(event_add(sv[0], EVENT_OUT, 1), 0);
99 CHECK_INT(write(sv[1], "x", 1), 1); 99 CHECK_INT(write(sv[1], "x", 1), 1);
100 CHECK_INT(wait_for(sv[0], EVENT_READ, 50, NULL), 0); 100 CHECK_INT(wait_for(sv[0], EVENT_IN, 50, NULL), 0);
101 101
102 test_case("until we ask about it"); 102 test_case("until we ask about it");
103 CHECK_INT(event_modify(sv[0], EVENT_READ | EVENT_WRITE, 1), 0); 103 CHECK_INT(event_modify(sv[0], EVENT_IN | EVENT_OUT, 1), 0);
104 CHECK_INT(wait_for(sv[0], EVENT_READ, 1000, NULL), 1); 104 CHECK_INT(wait_for(sv[0], EVENT_IN, 1000, NULL), 1);
105 105
106 CHECK_INT(event_del(sv[0]), 0); 106 CHECK_INT(event_del(sv[0]), 0);
107 pair_close(); 107 pair_close();
@@ -111,11 +111,11 @@ static void case_removed_is_silent(void) {
111 test_case("a removed descriptor is not reported again"); 111 test_case("a removed descriptor is not reported again");
112 pair_open(); 112 pair_open();
113 CHECK(sv[0] != -1); 113 CHECK(sv[0] != -1);
114 CHECK_INT(event_add(sv[0], EVENT_READ, 1), 0); 114 CHECK_INT(event_add(sv[0], EVENT_IN, 1), 0);
115 CHECK_INT(write(sv[1], "x", 1), 1); 115 CHECK_INT(write(sv[1], "x", 1), 1);
116 CHECK_INT(wait_for(sv[0], EVENT_READ, 1000, NULL), 1); 116 CHECK_INT(wait_for(sv[0], EVENT_IN, 1000, NULL), 1);
117 CHECK_INT(event_del(sv[0]), 0); 117 CHECK_INT(event_del(sv[0]), 0);
118 CHECK_INT(wait_for(sv[0], EVENT_READ, 50, NULL), 0); 118 CHECK_INT(wait_for(sv[0], EVENT_IN, 50, NULL), 0);
119 pair_close(); 119 pair_close();
120} 120}
121 121
@@ -127,21 +127,21 @@ static void case_generations_do_not_mix(void) {
127 pair_open(); 127 pair_open();
128 CHECK(sv[0] != -1); 128 CHECK(sv[0] != -1);
129 CHECK_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, other), 0); 129 CHECK_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, other), 0);
130 CHECK_INT(event_add(sv[0], EVENT_READ, 100), 0); 130 CHECK_INT(event_add(sv[0], EVENT_IN, 100), 0);
131 CHECK_INT(event_add(other[0], EVENT_READ, 200), 0); 131 CHECK_INT(event_add(other[0], EVENT_IN, 200), 0);
132 CHECK_INT(write(sv[1], "x", 1), 1); 132 CHECK_INT(write(sv[1], "x", 1), 1);
133 CHECK_INT(write(other[1], "y", 1), 1); 133 CHECK_INT(write(other[1], "y", 1), 1);
134 134
135 CHECK_INT(wait_for(sv[0], EVENT_READ, 1000, &generation), 1); 135 CHECK_INT(wait_for(sv[0], EVENT_IN, 1000, &generation), 1);
136 CHECK_INT(generation, 100); 136 CHECK_INT(generation, 100);
137 CHECK_INT(wait_for(other[0], EVENT_READ, 1000, &generation), 1); 137 CHECK_INT(wait_for(other[0], EVENT_IN, 1000, &generation), 1);
138 CHECK_INT(generation, 200); 138 CHECK_INT(generation, 200);
139 139
140 test_case("and re-registering one changes only its own"); 140 test_case("and re-registering one changes only its own");
141 CHECK_INT(event_modify(sv[0], EVENT_READ, 101), 0); 141 CHECK_INT(event_modify(sv[0], EVENT_IN, 101), 0);
142 CHECK_INT(wait_for(sv[0], EVENT_READ, 1000, &generation), 1); 142 CHECK_INT(wait_for(sv[0], EVENT_IN, 1000, &generation), 1);
143 CHECK_INT(generation, 101); 143 CHECK_INT(generation, 101);
144 CHECK_INT(wait_for(other[0], EVENT_READ, 1000, &generation), 1); 144 CHECK_INT(wait_for(other[0], EVENT_IN, 1000, &generation), 1);
145 CHECK_INT(generation, 200); 145 CHECK_INT(generation, 200);
146 146
147 event_del(sv[0]); 147 event_del(sv[0]);
@@ -162,23 +162,23 @@ static void case_delete_from_the_middle(void) {
162 test_case("deleting one of three leaves the others reported correctly"); 162 test_case("deleting one of three leaves the others reported correctly");
163 for (i = 0; i < 3; ++i) { 163 for (i = 0; i < 3; ++i) {
164 CHECK_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, pair[i]), 0); 164 CHECK_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, pair[i]), 0);
165 CHECK_INT(event_add(pair[i][0], EVENT_READ, (uint32_t)(10 + i)), 0); 165 CHECK_INT(event_add(pair[i][0], EVENT_IN, (uint32_t)(10 + i)), 0);
166 } 166 }
167 CHECK_INT(event_del(pair[1][0]), 0); 167 CHECK_INT(event_del(pair[1][0]), 0);
168 168
169 for (i = 0; i < 3; i += 2) { 169 for (i = 0; i < 3; i += 2) {
170 CHECK_INT(write(pair[i][1], "x", 1), 1); 170 CHECK_INT(write(pair[i][1], "x", 1), 1);
171 CHECK_INT(wait_for(pair[i][0], EVENT_READ, 1000, &generation), 1); 171 CHECK_INT(wait_for(pair[i][0], EVENT_IN, 1000, &generation), 1);
172 CHECK_INT(generation, 10 + i); 172 CHECK_INT(generation, 10 + i);
173 } 173 }
174 174
175 test_case("and the survivors can still be changed and removed"); 175 test_case("and the survivors can still be changed and removed");
176 CHECK_INT(event_modify(pair[2][0], EVENT_READ, 99), 0); 176 CHECK_INT(event_modify(pair[2][0], EVENT_IN, 99), 0);
177 CHECK_INT(wait_for(pair[2][0], EVENT_READ, 1000, &generation), 1); 177 CHECK_INT(wait_for(pair[2][0], EVENT_IN, 1000, &generation), 1);
178 CHECK_INT(generation, 99); 178 CHECK_INT(generation, 99);
179 CHECK_INT(event_del(pair[0][0]), 0); 179 CHECK_INT(event_del(pair[0][0]), 0);
180 CHECK_INT(event_del(pair[2][0]), 0); 180 CHECK_INT(event_del(pair[2][0]), 0);
181 CHECK_INT(wait_for(pair[2][0], EVENT_READ, 50, NULL), 0); 181 CHECK_INT(wait_for(pair[2][0], EVENT_IN, 50, NULL), 0);
182 182
183 for (i = 0; i < 3; ++i) 183 for (i = 0; i < 3; ++i)
184 close(pair[i][0]), close(pair[i][1]); 184 close(pair[i][0]), close(pair[i][1]);
@@ -201,7 +201,7 @@ static void case_timeout(void) {
201 201
202static void case_unknown_descriptor(void) { 202static void case_unknown_descriptor(void) {
203 test_case("changing or removing one that was never added is refused"); 203 test_case("changing or removing one that was never added is refused");
204 CHECK_INT(event_modify(4096, EVENT_READ, 1), -1); 204 CHECK_INT(event_modify(4096, EVENT_IN, 1), -1);
205 CHECK_INT(event_del(4096), -1); 205 CHECK_INT(event_del(4096), -1);
206} 206}
207 207