17 Commits
Author SHA1 Message Date
Douglas Eichelberger 50f6624862 Reset the fork lock in the child without unlocking it
A thread that is waiting for the fork lock when another thread forks
exists only in the parent, but on macOS the child's copy of the lock
still counts it. After the child unlocks its copy,
pthread_rwlock_destroy() and pthread_rwlock_init() fail with EBUSY, so
the child aborts with
"[BUG] pthread_rwlock_destroy: Resource busy (EBUSY)". Lookup threads
wait for the lock whenever a fork holds it, so a process that resolves
names in background threads while it forks loses a child now and then.

Reset the child's copy by assigning PTHREAD_RWLOCK_INITIALIZER, as
rb_internal_thread_event_hooks_rw_lock_atfork() does for its lock, and
do not unlock it first. With a waiter counted, macOS's unlock enters the
kernel to wake it, and the state that leaves behind for the lock's
address survives the assignment, so a later waiter in the child can
sleep forever although no thread holds the lock. FreeBSD already skipped
the unlock in the child (dc8c382266), and on glibc the child's unlock
does not release the write lock anyway.

[Bug #22445]
2026-10-17 20:37:04 +09:00
Hiroshi SHIBATAandNobuyoshi Nakada 892849ac98 Remove dependency on fiddle from test/ruby
Co-authored-by: "Nobuyoshi Nakada" <nobu@ruby-lang.org>
2024-06-04 19:53:04 +09:00
卜部昌平 c844968b72 ruby tool/update-deps --fix 2024-04-27 21:55:28 +09:00
Pierrick Bouvier 1ca3482e0a Fix compilation for platforms without pthread
Found when compiling ruby for windows-arm64 using msys2

Missing return type for function Init_lock_native_thread
lock_native_thread.c:45:1: error: type specifier missing, defaults to 'int'; ISO C99 and later do not support implicit int [-Wimplicit-int]
   45 | Init_lock_native_thread(void)
      | ^
      | int
2024-02-26 20:45:48 +09:00
Koichi Sasada d578684989 rb_thread_lock_native_thread()
Introduce `rb_thread_lock_native_thread()` to allocate dedicated
native thread to the current Ruby thread for M:N threads.
This C API is similar to Go's `runtime.LockOSThread()`.

Accepted at https://github.com/ruby/dev-meeting-log/blob/master/2023/DevMeeting-2023-08-24.md
(and missed to implement on Ruby 3.3.0)
2024-02-21 15:38:29 +09:00
Jean Boussier 982641939c Further fix the GVL instrumentation API
Followup: https://github.com/ruby/ruby/pull/9029

[Bug #20019]

Some events still weren't triggered from the right place.

The test suite was also improved a bit more.
2023-11-28 20:06:55 +01:00
23a7714343 Refactor and fix the GVL instrumentation API
This entirely changes how it is tested. Rather than to use counters
we now record the timeline of events with associated threads which
makes it much easier to assert that certains events are only preceded
by a specific event, and makes it much easier to debug unexpected
timelines.

Co-Authored-By: Étienne Barrié <etienne.barrie@gmail.com>
Co-Authored-By: JP Camara <jp@jpcamara.com>
Co-Authored-By: John Hawthorn <john@hawthorn.email>
2023-11-27 17:37:57 +01:00
Jean Boussier 9ca41e9991 GVL Instrumentation: pass thread->self as part of event data
Context: https://github.com/ivoanjo/gvl-tracing/pull/4

Some hooks may want to collect data on a per thread basis.
Right now the only way to identify the concerned thread is to
use `rb_nativethread_self()` or similar, but even then because
of the thread cache or MaNy, two distinct Ruby threads may report
the same native thread id.

By passing `thread->self`, hooks can use it as a key to store
the metadata.

NB: Most hooks are executed outside the GVL, so such data collection
need to use a thread-safe data-structure, and shouldn't use the
reference in other ways from inside the hook.

They must also either pin that value or handle compaction.
2023-11-13 08:45:20 +01:00
Nobuyoshi Nakada f99af43980 [Bug#19161] Detect thread local storage specifier
Checking by `__STDC_VERSION__` is unreliable because old gcc 4.8
supports `-std=gnu11` option but does not implement `_Thread_local`.
Check the implementation directly instead.
2023-04-07 13:42:48 +09:00
Matt Valentine-House 5e4b80177e Update the depend files 2023-02-28 09:09:00 -08:00
Matt Valentine-House f38c6552f9 Remove intern/gc.h from Make deps 2023-02-27 10:11:56 -08:00
Nobuyoshi Nakada 899ea35035 Extract include/ruby/internal/attr/packed_struct.h
Split `PACKED_STRUCT` and `PACKED_STRUCT_UNALIGNED` macros into the
macros bellow:
* `RBIMPL_ATTR_PACKED_STRUCT_BEGIN`
* `RBIMPL_ATTR_PACKED_STRUCT_END`
* `RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_BEGIN`
* `RBIMPL_ATTR_PACKED_STRUCT_UNALIGNED_END`
2023-02-08 12:34:13 +09:00
Nobuyoshi Nakada cf991337fb Make a local symbol static 2022-07-08 10:55:44 +09:00
Jean Boussier 587d2d199b thread_pthread.c: call SUSPENDED event when entering native_sleep
[Bug #18900]

Thread#join and a few other codepaths are using native sleep as
a way to suspend the current thread. So we should call the relevant
hook when this happen, otherwise some thread may transition
directly from `RESUMED` to `READY`.
2022-07-07 17:49:00 +02:00
Nobuyoshi Nakada 4aebbf44e9 Remove unnecessary * before the function name 2022-06-19 23:32:47 +09:00
Jean Boussier b6c1e1158d GVL Instrumentation API: add STARTED and EXITED events
[Feature #18339]

After experimenting with the initial version of the API I figured there is a need
for an exit event to cleanup instrumentation data. e.g. if you record data in a
{thread_id -> data} table, you need to free associated data when a thread goes away.
2022-06-17 09:08:26 +02:00
Jean Boussier 9125374726 [Feature #18339] GVL Instrumentation API
Ref: https://bugs.ruby-lang.org/issues/18339

Design:

- This tries to minimize the overhead when no hook is registered.
  It should only incur an extra unsynchronized boolean check.
- The hook list is protected with a read-write lock as to cause
  contention when some hooks are registered.
- The hooks MUST be thread safe, and MUST NOT call into Ruby as they
  are executed outside the GVL.
- It's simply a noop on Windows.

API:

```
rb_internal_thread_event_hook_t * rb_internal_thread_add_event_hook(rb_internal_thread_event_callback callback, rb_event_flag_t internal_event, void *user_data);
bool rb_internal_thread_remove_event_hook(rb_internal_thread_event_hook_t * hook);
```

You can subscribe to 3 events:

  - READY: called right before attempting to acquire the GVL
  - RESUMED: called right after successfully acquiring the GVL
  - SUSPENDED: called right after releasing the GVL.

The hooks MUST be threadsafe, as they are executed outside of the GVL, they also MUST NOT call any Ruby API.
2022-06-03 15:13:33 +02:00