Skip to content

Commit 0297ae8

Browse files
committed
[DOC] WIP concurrency guide
1 parent c995faa commit 0297ae8

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

doc/concurrency_guide.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Concurrency Guide
2+
3+
This is a guide to thinking about concurrency in the native cruby source code, whether that's
4+
contributing to Ruby by writing C or Rust. This doesn't touch on native extensions, only the core
5+
language. It will go over:
6+
7+
* How to use the VM lock, and what you can and can't do when you've acquired this lock.
8+
* What you can and can't do when you've acquired other native locks.
9+
* The difference between the VM lock and the GVL.
10+
* How to write code that is ractor safe.
11+
* What a VM barrier is and when to use it.
12+
* The lock hierarchy of some important locks.
13+
* How ruby interrupt handling works.
14+
* What happens when IO is performed through ruby.
15+
* The timer thread and what it's responsible for.
16+
17+
18+
## The VM Lock
19+
20+
There's only one VM lock and its for critical sections that can only be entered by one ractor at a time.
21+
Without ractors, the VM lock is useless. It does not stop all ractors from running, as ractors can run
22+
without trying to acquire this lock. If you're updating global (shared) data between ractors and aren't using
23+
atomics, you need to use this lock. When you take the VM lock, there are things you can and can't do during
24+
your (hopefully brief) critical section:
25+
26+
You can (as long as no other locks are also held):
27+
28+
* Create ruby objects, call ruby_xmalloc, etc.
29+
30+
* Raise exceptions or use `EC_JUMP_TAG`. The lock will automatically be unlocked depending on how far up the call stack you locked it, and how far you're jumping to.
31+
32+
* Check ruby interrupts. Since raising exceptions can pop ruby frames and popping ruby frames checks interrupts, you are allowed.
33+
34+
You can't:
35+
36+
* Context switch to another thread or ractor. This is important, as many things can cause context switches including:
37+
38+
* Calling any ruby method through, for example, `rb_funcall`. If you execute ruby code with the VM lock, a context switch
39+
could happen. This also applies to ruby methods defined in C. You also can't check if objects respond to methods or set
40+
constants (these can both call ruby methods).
41+
42+
* Calling `rb_nogvl`
43+
44+
* Enter any blocking operation managed by ruby. This will context switch to another ruby thread.
45+
46+
* Calling a ruby-level mechanism that can context switch, like `rb_mutex_lock`.
47+
48+
Internally, this is the `vm->ractor.sync.lock`.
49+
50+
## Other Locks
51+
52+
All native locks that aren't the VM lock share a more strict set of rules for what's allowed during the critical section. By native locks, we mean
53+
anything that uses `rb_native_mutex_lock`. Some important examples are the `interrupt_lock` and the ractor scheduling lock.
54+
55+
You can't:
56+
57+
* Raise exceptions or use `EC_JUMP_TAG` if it jumps out of the critical section.
58+
59+
* Context switch. See the `VM Lock` section for more info.
60+
61+
* Check interrupts. Doing so can raise exceptions or context switch.
62+
63+
* Allocate memory through ruby. This includes creating ruby objects or using `ruby_xmalloc` or `st_insert`.
64+
65+
66+

0 commit comments

Comments
 (0)