Skip to content

Commit b815bdd

Browse files
Use blocking lock in worker_pool_mark — workers never hold mutex with GVL
Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 716d65a commit b815bdd

1 file changed

Lines changed: 7 additions & 6 deletions

File tree

ext/io/event/worker_pool.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,11 @@ static void worker_pool_mark(void *ptr)
109109
// queue we need to mark from here to keep blocking_operation_value alive
110110
// across any GC that might run during that window.
111111
//
112-
// We use trylock rather than lock: if a worker thread is currently
113-
// dequeuing (which it does while holding the mutex but without the GVL),
114-
// we skip this cycle. The work will still be on the blocked fiber's
115-
// C stack and the conservative scan will keep the VALUEs alive.
116-
if (pthread_mutex_trylock(&pool->mutex) == 0) {
112+
// Mark all queued work items. Workers only hold this mutex during brief
113+
// non-Ruby queue operations (no GVL acquired while locked), so a blocking
114+
// lock here is safe — no deadlock risk.
115+
pthread_mutex_lock(&pool->mutex);
116+
{
117117
struct IO_Event_WorkerPool_Work *work = pool->work_queue;
118118
while (work) {
119119
rb_gc_mark(work->blocking_operation_value);
@@ -122,7 +122,8 @@ static void worker_pool_mark(void *ptr)
122122
rb_gc_mark(work->fiber);
123123
work = work->next;
124124
}
125-
pthread_mutex_unlock(&pool->mutex);
125+
}
126+
pthread_mutex_unlock(&pool->mutex);
126127
}
127128
}
128129

0 commit comments

Comments
 (0)