[ruby-core:115965] [Ruby master Bug#20103] rb_internal_thread_remove_event_hook() hangs when called from within a Thread hook

Issue #20103 has been reported by osyoyu (Daisuke Aritomo). ---------------------------------------- Bug #20103: rb_internal_thread_remove_event_hook() hangs when called from within a Thread hook https://bugs.ruby-lang.org/issues/20103 * Author: osyoyu (Daisuke Aritomo) * Status: Open * Priority: Normal * ruby -v: ruby 3.4.0dev (2023-12-28T14:53:15Z master e81a5453e3) [x86_64-linux] * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- ## Problem The Ruby process hangs when `rb_internal_thread_remove_event_hook()` is called from within a Thread hook registered by `rb_internal_thread_add_event_hook()`. The thread is waiting for the thread event execution lock (`pthread_rwlock_wrlock(&rb_internal_thread_event_hooks_rw_lock))`), which is acquired by its caller, `rb_thread_execute_hooks()`. https://github.com/ruby/ruby/blob/e81a5453e3c76c4348da042d86debde7689254fe/t... This situation would occur when one wants to register a *oneshot* hook that performs something on a Thread for only a single time. The hook would remove itself after its main procedure. In my case, I'm doing a timer_create(3) on each pthread for profiling purposes. ## Expected behavior The process won't hang, or at least print some kind of warning. I think there some options here: 1. Discourage this kind of definition. Thread hooks should not add/remove other Thread hooks, or otherwise do so through other async methods, such as postponed jobs. 2. Find a way to make this work. Maybe inner calls to add/remove_event_hook() can share locks with the outer call, but I'm not sure if that's possible as I'm not familiar with pthread_rwlocks. ## Repro ```c #include "ruby.h" #include "ruby/thread.h" rb_internal_thread_event_hook_t *hook; void event_hook_callback(rb_event_flag_t flag, const rb_internal_thread_event_data_t *data, void *custom_data) { rb_internal_thread_remove_event_hook(hook); // hangs } RUBY_FUNC_EXPORTED void Init_mycext(void) { hook = rb_internal_thread_add_event_hook( event_hook_callback, RUBY_INTERNAL_THREAD_EVENT_RESUMED, NULL ); } ``` ``` ruby -rmycext -e 'Thread.new { loop { 1 + 1 } }' ``` -- https://bugs.ruby-lang.org/
participants (1)
-
osyoyu (Daisuke Aritomo)