@@ -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
184189void
185190libkqueue_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