Skip to content

Commit 0780ba9

Browse files
committed
Don't lock kq mutexes on fork
1 parent 7dcce1b commit 0780ba9

File tree

2 files changed

+48
-53
lines changed

2 files changed

+48
-53
lines changed

ChangeLog

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,46 @@
11
Unreleased
22
------------------------------------------------------------------------
3-
4-
2022-04-27 v2.6.2
3+
4+
2022-11-02 v2.6.2
55
------------------------------------------------------------------------
66

77
* Fix: Various build system and include fixes to allow libkqueue
88
to build correctly with musl libc.
9-
9+
1010
* Fix: Various macro and include fixes for Windows/MinGW builds.
1111
(Fixed by: neheb)
12-
13-
* Always build both a static and a shared library. The STATIC_KQUEUE
12+
13+
* Always build both a static and a shared library. The STATIC_KQUEUE
1414
build variable has been removed.
15-
15+
16+
* Fix: Don't attempt to lock kqueues on fork. It's no longer needed
17+
as we're not attempting to free memory in the kqueues, only close
18+
file descriptors. This may resolve stalling fork() calls where
19+
kqueues were in a waiting state.
20+
1621
2022-04-27 v2.6.1
1722
------------------------------------------------------------------------
1823

19-
* Fix: Set the core dumped flag correctly in linux/proc on
24+
* Fix: Set the core dumped flag correctly in linux/proc on
2025
CLD_DUMPED.
2126

2227
* Fix: Don't attempt to cleanup memory on fork as free() is not
2328
fork safe. We still close open kqueue FDs on fork, and liberal
2429
use of CLOEXEC should clean up any lingering filter FDs though
2530
we may want to close these explicitly in future too.
26-
31+
2732
* Fix: Double unlock in posix/proc.c
28-
33+
2934
* Fix: Potential deadlock on kqueue initialisation failure.
3035

3136
* Fix: Building for MSVC (Patch by Jan200101)
3237

3338
* Fix: Sprinkle CLOEXEC around various places in the Linux and
3439
POSIX platforms to stop us leaking file descriptors on exec.
35-
36-
* Add EVFILT_LIBKQUEUE/NOTE_THREAD_SAFE. When set to 0, the
37-
global mutex is not locked on kqueue lookup. The application
38-
must guarantee that kqueues must not be destroyed by a different
40+
41+
* Add EVFILT_LIBKQUEUE/NOTE_THREAD_SAFE. When set to 0, the
42+
global mutex is not locked on kqueue lookup. The application
43+
must guarantee that kqueues must not be destroyed by a different
3944
thread to the one that created them.
4045

4146
2022-03-21 v2.6.0

src/common/kqueue.c

Lines changed: 30 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -141,18 +141,6 @@ libkqueue_pre_fork(void)
141141
{
142142
struct kqueue *kq, *kq_tmp;
143143

144-
/*
145-
* Ensure that all global structures are in a
146-
* consistent state before attempting the
147-
* fork.
148-
*
149-
* If we don't do this then kq_mtx state will
150-
* be undefined when the child starts cleaning
151-
* up resources, and we could get deadlocks, nasty
152-
* memory corruption and or crashes in the child.
153-
*/
154-
tracing_mutex_lock(&kq_mtx);
155-
156144
/*
157145
* Unfortunately there's no way to remove the atfork
158146
* handlers, so all we can do if cleanup is
@@ -166,35 +154,44 @@ libkqueue_pre_fork(void)
166154
return;
167155

168156
/*
169-
* Acquire locks for all the active kqueues,
170-
* this ensures in the child all kqueues are in
171-
* a consistent state, ready to be freed.
157+
* Ensure that all global structures are in a consistent
158+
* state before attempting the fork.
172159
*
173-
* This has the potential to stall out the process
174-
* whilst we attempt to acquire all the locks,
175-
* so it might be a good idea to make this
176-
* configurable in future.
160+
* If we don't do this then kq_mtx state will
161+
* be undefined when the child starts cleaning
162+
* up resources, and we could get deadlocks, nasty
163+
* memory corruption and/or crashes in the child.
164+
*
165+
* We always lock the kq_mtx even when
166+
* !libkqueue_thread_safe because it's still locked when
167+
* kqueues are being freed, and we don't want to access
168+
* freed memory when attempting to perform cleanup.
169+
*/
170+
tracing_mutex_lock(&kq_mtx);
171+
172+
/*
173+
* We previously attempted to lock all the child
174+
* kqueues, but when they were waiting in kevent_wait
175+
* this caused fork to stall.
176+
*
177+
* The main reason for locking the child kqueues was
178+
* to ensure filters and kqueues were in a consistent
179+
* state at the time of the fork, to ensure we could
180+
* free resources correctly... but as it was later
181+
* discovered many systems really don't like free()
182+
* being called in the forked child, so we were limited
183+
* to async-safe calls like close... These should be
184+
* safe no matter what the state of the kqueues so
185+
* the locking was removed.
177186
*/
178-
dbg_puts("gathering kqueue locks on fork");
179-
LIST_FOREACH_SAFE(kq, &kq_list, kq_entry, kq_tmp) {
180-
kqueue_lock(kq);
181-
}
182187
}
183188

184189
void
185190
libkqueue_parent_fork(void)
186191
{
187-
struct kqueue *kq, *kq_tmp;
188-
189-
if (!libkqueue_fork_cleanup_active) {
190-
tracing_mutex_unlock(&kq_mtx);
192+
if (!libkqueue_fork_cleanup_active)
191193
return;
192-
}
193194

194-
dbg_puts("releasing kqueue locks in parent");
195-
LIST_FOREACH_SAFE(kq, &kq_list, kq_entry, kq_tmp) {
196-
kqueue_unlock(kq);
197-
}
198195
tracing_mutex_unlock(&kq_mtx);
199196
}
200197

@@ -205,15 +202,8 @@ libkqueue_child_fork(void)
205202

206203
libkqueue_in_child = true;
207204

208-
if (!libkqueue_fork_cleanup_active) {
209-
tracing_mutex_unlock(&kq_mtx);
205+
if (!libkqueue_fork_cleanup_active)
210206
return;
211-
}
212-
213-
dbg_puts("releasing kqueue locks in child");
214-
LIST_FOREACH_SAFE(kq, &kq_list, kq_entry, kq_tmp) {
215-
kqueue_unlock(kq);
216-
}
217207

218208
dbg_puts("cleaning up forked resources");
219209
filter_fork_all();

0 commit comments

Comments
 (0)