Skip to content

Commit bffefb2

Browse files
authored
RFC 2: MT safe fiber context switch on ARM32 (#15582)
We need a store-store barrier between pushing the registers to the current stack and setting the resumable flag of the current fiber, otherwise the CPU is allowed to reorder the instructions at runtime and to store the resumable flag before or while storing the registers thread 1: enqueues current fiber A therad 1: swapcontext -> store resumable thread 1: is preempted thread 2: steals fiber A thread 2: resumes fiber A thread 2: loads registers => reads garbage => segfaults thread 1: stores registers (too late) The chosen assembly is compatible with armv6, but might not work on older architectures, and it doesn't take advantage of armv7 supporting the `dmb ish` instruction. We might want to consider integrating #14524 (comment) into the compiler, so we could add flags based on features, for example `armv7` when any feature matches `/\+v7(ve|r|m|em|s|k|)/`. This is the ARM32 equivalent of #15581.
1 parent 2a03133 commit bffefb2

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

src/fiber/context/arm.cr

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ class Fiber
2929
#
3030
# Eventually reset LR to zero to avoid the ARM unwinder to mistake the
3131
# context switch as a regular call.
32+
#
33+
# NOTE: depending on the ARM architecture (v7, v6 or older) LLVM uses
34+
# different strategies for atomics. By default it uses the "older"
35+
# architecture that relies on the libgcc __sync_* symbols; when an armv6 CPU
36+
# or +v6 feature is specified it uses the coprocessor instruction as used
37+
# below, unless the +db (data barrier) feature is set, in which case it
38+
# uses the `dmb ish` instruction. The +db feature is always enabled since
39+
# armv7 / +v7.
40+
#
41+
# TODO: we should do the same, but we don't know the list of CPU features
42+
# for the current target machine (and LLVM won't tell us).
3243

3344
{% if compare_versions(Crystal::LLVM_VERSION, "9.0.0") >= 0 %}
3445
asm("
@@ -42,6 +53,10 @@ class Fiber
4253
vstmdb sp!, {d8-d15} // push FPU registers
4354
{% end %}
4455
str sp, [r0, #0] // current_context.stack_top = sp
56+
{% if flag?(:execution_context) %}
57+
mov r4, #0 // barrier: ensure registers are stored
58+
mcr p15, #0, r4, c7, c10, #5
59+
{% end %}
4560
mov r4, #1 // current_context.resumable = 1
4661
str r4, [r0, #4]
4762
@@ -72,6 +87,10 @@ class Fiber
7287
vstmdb sp!, {d8-d15} // push FPU registers
7388
{% end %}
7489
str sp, [$0, #0] // current_context.stack_top = sp
90+
{% if flag?(:execution_context) %}
91+
mov r4, #0 // barrier: ensure registers are stored
92+
mcr p15, #0, r4, c7, c10, #5
93+
{% end %}
7594
mov r4, #1 // current_context.resumable = 1
7695
str r4, [$0, #4]
7796

0 commit comments

Comments
 (0)