Skip to content

Commit 127b571

Browse files
committed
api: fix deadlock on shutdown when clients are connected
The docstring of event_base_foreach_event() states explicitly that modifying events in the callback function is unsafe and will cause crashes. event_free_finalize tries to acquire a lock that is already held when the callback is called. Leading to a deadlock: (gdb) bt ... DPDK#3 ___pthread_mutex_lock (mutex=0x504000001550) at pthread_mutex_lock.c:93 DPDK#4 0x00007f3f211b8485 in event_finalize_impl_ (flags=65536, ev=0x50c000005200, cb=0x4031ba <finalize_fd>) DPDK#5 0x00000000004042ed in close_connections (ev=0x50c000005200) at main/api.c:174 ... DPDK#10 0x00007f3f211b263a in event_base_foreach_event (base=0x517000006d00, fn=0x40429f <close_connections>, arg=0x0) DPDK#11 0x0000000000404a3a in api_socket_stop () at main/api.c:253 DPDK#12 0x00000000004072aa in main (argc=4, argv=0x7ffcc575d898) at main/main.c:210 Only use event_base_foreach_event() for iterating over the events that we actually want to free (namely, ones that have read_cb and write_cb as callbacks). Only *after* returning from event_base_foreach_event(), call event_free_finalize on all these events. Fixes: 8653320 ("main: close active connections on shutdown") Signed-off-by: Robin Jarry <[email protected]>
1 parent 5c91e81 commit 127b571

File tree

1 file changed

+16
-8
lines changed

1 file changed

+16
-8
lines changed

main/api.c

+16-8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <gr_api.h>
99
#include <gr_log.h>
1010
#include <gr_macro.h>
11+
#include <gr_vec.h>
1112

1213
#include <event2/event.h>
1314

@@ -168,13 +169,6 @@ static void read_cb(evutil_socket_t sock, short what, void * /*priv*/) {
168169
event_free_finalize(0, ev, finalize_fd);
169170
}
170171

171-
static int close_connections(const struct event_base *, const struct event *ev, void * /*priv*/) {
172-
event_callback_fn cb = event_get_callback(ev);
173-
if (cb == read_cb || cb == write_cb)
174-
event_free_finalize(0, (struct event *)ev, finalize_fd);
175-
return 0;
176-
}
177-
178172
static void listen_cb(evutil_socket_t sock, short what, void * /*priv*/) {
179173
struct event *ev;
180174
int fd;
@@ -246,9 +240,23 @@ int api_socket_start(struct event_base *base) {
246240
return 0;
247241
}
248242

243+
static int collect_clients(const struct event_base *, const struct event *ev, void *priv) {
244+
struct event ***events = priv;
245+
event_callback_fn cb = event_get_callback(ev);
246+
if (cb == read_cb || cb == write_cb)
247+
gr_vec_add(*events, (struct event *)ev);
248+
return 0;
249+
}
250+
249251
void api_socket_stop(struct event_base *) {
252+
struct event **events = NULL;
253+
struct event *ev;
254+
250255
if (ev_listen != NULL)
251256
event_free_finalize(0, ev_listen, finalize_fd);
252257

253-
event_base_foreach_event(ev_base, close_connections, NULL);
258+
event_base_foreach_event(ev_base, collect_clients, &events);
259+
gr_vec_foreach (ev, events)
260+
event_free_finalize(0, ev, finalize_fd);
261+
gr_vec_free(events);
254262
}

0 commit comments

Comments
 (0)