spinel_native 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 861579157d9270857eede60bc891c64f7b6b78c152a62512ef0ad098f112fad4
4
- data.tar.gz: 132e7349789d035475fd5386ffa5bf6c60b39a3c08880e9adcd01244563d2e4e
3
+ metadata.gz: 6eb84c9447a7802b37d923c0fc03328b913d196cd7394f45f7d8ff8ebdae61f8
4
+ data.tar.gz: a4761840558347f8d65510053ce013351011ed8a98dfe21e463b3c93e7ba1198
5
5
  SHA512:
6
- metadata.gz: b195d6cf158a5bc71c802c7f181f9956a868c1989fd3901c6cd2ea93bfd04ddcb40eaf08fcd92e34e09f10253a4403ce2ef4275aa2d084332d6c75a7318ea1f2
7
- data.tar.gz: 2ed20f171858b8f635bfda4dc66cbad803235430bd162a3cdbc32b3b8dc741acb4638f618c0b361b5eb4d3789b8a3dd094354df457ee6546fc14efe8810edc90
6
+ metadata.gz: 3a16adfa8b94475d39fa61eea71cd6e886977efa37207517204fc30a96e8478e139d7efd33837e23cc71b1b9cfa559274d825ff79514e58072fb997ff46ed17b
7
+ data.tar.gz: d898452eff97062057a9dbd82d112bfd35653fce9ce8b8a27adc208644950e7510aeb18e43bd41cc627ae25d56d73c972a746c3ae58ebe2b0518f916fc317787
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1 (2026-09-20)
4
+
5
+ - Run the kernel with the GVL held. The CRuby shim Spinel emits locks its
6
+ mutex under the GVL and then releases the GVL for the call, which deadlocks
7
+ on the second concurrent call from another Ruby thread (Puma under load).
8
+ Until the shim is fixed upstream, spinel_native rewrites the call site so
9
+ the kernel runs under the GVL; kernels no longer overlap other Ruby threads.
10
+ - The build cache key includes the spinel_native version.
11
+
3
12
  ## 0.3.0 (2026-09-18)
4
13
 
5
14
  - `native_entries :a, :b`: in a stateful kernel, name the methods called from
data/README.md CHANGED
@@ -284,8 +284,8 @@ SPINEL_NATIVE_VERBOSE=1 # print the commands and timings
284
284
  - A `raise` inside the kernel arrives in Ruby as the same exception class and
285
285
  message. Integer overflow raises `RangeError` where CRuby would promote to a
286
286
  Bignum, and a Bignum argument is a `RangeError` at the boundary.
287
- - The kernel runs without the GVL, one call at a time per module, so
288
- `native_state` needs no locking of its own.
287
+ - Kernels run one call at a time per module, with the GVL held (see the
288
+ 0.3.1 changelog for why), so `native_state` needs no locking of its own.
289
289
  - In a stateful module with `native_entries`, only the entries reach the
290
290
  kernel's state. A non-entry method called from Ruby runs as Ruby, on the
291
291
  module's own ivars.
@@ -55,7 +55,7 @@ module Spinel
55
55
  def fingerprint
56
56
  @fingerprint ||= begin
57
57
  st = File.stat(spinel_bin)
58
- Digest::SHA256.hexdigest([st.size, st.mtime.to_i, RUBY_VERSION, RUBY_PLATFORM, RbConfig::CONFIG["CC"]].join("|"))
58
+ Digest::SHA256.hexdigest([st.size, st.mtime.to_i, RUBY_VERSION, RUBY_PLATFORM, RbConfig::CONFIG["CC"], VERSION].join("|"))
59
59
  end
60
60
  end
61
61
 
@@ -158,6 +158,23 @@ module Spinel
158
158
  "--ext", "cruby", "--ext-init", "spx_init_#{@feature}", "--ext-entry", entry_list,
159
159
  "-o", File.join(@dir, "#{@feature}.c")]
160
160
  sh(cmd, "spinel")
161
+ keep_gvl(File.join(@dir, "#{@feature}_ext.c"))
162
+ end
163
+
164
+ # The shim Spinel emits takes its mutex while holding the GVL and then
165
+ # releases the GVL for the kernel call. A second Ruby thread entering
166
+ # the shim blocks on the mutex with the GVL held, the first cannot take
167
+ # the GVL back to unlock, and the process deadlocks on its second
168
+ # concurrent call (reproduced under Puma with wrk). Until the shim
169
+ # orders the two the other way round, run the kernel with the GVL held:
170
+ # the mutex is then never contended and the conversions, which touch
171
+ # the single-threaded Spinel heap, are serialized too. The cost is that
172
+ # kernels do not overlap with other Ruby threads.
173
+ def keep_gvl(shim)
174
+ src = File.read(shim)
175
+ patched = src.gsub(/rb_thread_call_without_gvl\((spx_run_\d+), &c__, RUBY_UBF_IO, NULL\)/, '\1(&c__)')
176
+ raise CompileError, "unexpected shim shape in #{shim}: no rb_thread_call_without_gvl call sites" if patched == src
177
+ File.write(shim, patched)
161
178
  end
162
179
 
163
180
  # Every kernel carries its own copy of the runtime and exports the same
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Spinel
4
4
  module Native
5
- VERSION = "0.3.0"
5
+ VERSION = "0.3.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spinel_native
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Hasiński
@@ -64,7 +64,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
64
64
  - !ruby/object:Gem::Version
65
65
  version: '0'
66
66
  requirements: []
67
- rubygems_version: 4.0.16
67
+ rubygems_version: 4.0.20
68
68
  specification_version: 4
69
69
  summary: Compile individual Ruby methods to native code with the Spinel AOT compiler
70
70
  test_files: []