uringmachine 0.7 → 0.8

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: d7c0b7cfea4bdb08c954cf8dcef6cc776e4eb73e64fc366a43042f7a62902430
4
- data.tar.gz: 83f60da253aa4ab69ef98a96205995b258c0d4a6925385818e34d2cb9fd26a0f
3
+ metadata.gz: c901aae24c3fad58a2453333885d10c577448c910c069753188cf8a89b6a1f2e
4
+ data.tar.gz: '0804b7103ccf9ae6c244ef5a9677987af2944e508b63d98aeee5f19dee0f1f2e'
5
5
  SHA512:
6
- metadata.gz: 54d58ae7aedc3f7444cff6d8b4afbf4845ba0ddf6ae5a662b60b04b83c81b7e2af35c1e46a1f3827adb07bf95c4677b4253774bd50c590541177a5a251d7f2b4
7
- data.tar.gz: 9a6d69766b3d17c5b1593bd153608f846370c32bd7219796f4fbe677c379724aa1186f70a5cf4cbb797817e4564bdff01ab5a5a3514e803ac8ead5b949899fde
6
+ metadata.gz: 3a6934132fad56b013a8754c375b33acd2cefc28577879b7e05bbf0ded8e9b9cd8e50070ec398d67c00c07ebb15468347e96d27d6ba2ccdbfbc19b5a206aff6c
7
+ data.tar.gz: 9c54ade5eada0ce6238f6138f8be9c5857436668851154ead8a55b8d221d2f4f3d2318616d1fdc733e99562748c17b26eca7e171cf43ddeb34a80320df2e2b43
@@ -13,7 +13,7 @@ jobs:
13
13
  matrix:
14
14
  # macos-latest uses arm64, macos-13 uses x86
15
15
  os: [ubuntu-latest]
16
- ruby: ['3.3', '3.4', 'head']
16
+ ruby: ['3.4', 'head']
17
17
 
18
18
  name: ${{matrix.os}}, ${{matrix.ruby}}
19
19
 
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 2025-05-03 Version 0.8
2
+
3
+ - Add `#join`
4
+
1
5
  # 2025-04-28 Version 0.7
2
6
 
3
7
  - Add `#shutdown`
data/TODO.md CHANGED
@@ -1,3 +1,5 @@
1
+ # ops
2
+
1
3
  - [ ] multishot timeout
2
4
  - [v] machine.periodically(interval) { ... }
3
5
  - [ ] machine.prep_timeout_multishot(interval)
@@ -15,3 +17,9 @@
15
17
  - madvise
16
18
  - getxattr / setxattr
17
19
  - send_bundle / recv_bundle (kernel >= 6.10)
20
+
21
+ # actors
22
+
23
+ When doing a `call`, we need to provide a mailbox for the response. can this be
24
+ automatic?
25
+
data/ext/um/extconf.rb CHANGED
@@ -6,61 +6,6 @@ require 'rbconfig'
6
6
 
7
7
  dir_config 'um_ext'
8
8
 
9
- def config_ssl
10
- # don't use pkg_config('openssl') if '--with-openssl-dir' is used
11
- has_openssl_dir = dir_config('openssl').any? ||
12
- RbConfig::CONFIG['configure_args']&.include?('openssl')
13
-
14
- found_pkg_config = !has_openssl_dir && pkg_config('openssl')
15
-
16
- found_ssl = if !$mingw && found_pkg_config
17
- puts '──── Using OpenSSL pkgconfig (openssl.pc) ────'
18
- true
19
- elsif have_library('libcrypto', 'BIO_read') && have_library('libssl', 'SSL_CTX_new')
20
- true
21
- elsif %w'crypto libeay32'.find {|crypto| have_library(crypto, 'BIO_read')} &&
22
- %w'ssl ssleay32'.find {|ssl| have_library(ssl, 'SSL_CTX_new')}
23
- true
24
- else
25
- puts '** Puma will be compiled without SSL support'
26
- false
27
- end
28
-
29
- if found_ssl
30
- have_header "openssl/bio.h"
31
-
32
- ssl_h = "openssl/ssl.h".freeze
33
-
34
- puts "\n──── Below are yes for 1.0.2 & later ────"
35
- have_func "DTLS_method" , ssl_h
36
- have_func "SSL_CTX_set_session_cache_mode(NULL, 0)", ssl_h
37
-
38
- puts "\n──── Below are yes for 1.1.0 & later ────"
39
- have_func "TLS_server_method" , ssl_h
40
- have_func "SSL_CTX_set_min_proto_version(NULL, 0)" , ssl_h
41
-
42
- puts "\n──── Below is yes for 1.1.0 and later, but isn't documented until 3.0.0 ────"
43
- # https://github.com/openssl/openssl/blob/OpenSSL_1_1_0/include/openssl/ssl.h#L1159
44
- have_func "SSL_CTX_set_dh_auto(NULL, 0)" , ssl_h
45
-
46
- puts "\n──── Below is yes for 1.1.1 & later ────"
47
- have_func "SSL_CTX_set_ciphersuites(NULL, \"\")" , ssl_h
48
-
49
- puts "\n──── Below is yes for 3.0.0 & later ────"
50
- have_func "SSL_get1_peer_certificate" , ssl_h
51
-
52
- puts ''
53
-
54
- # Random.bytes available in Ruby 2.5 and later, Random::DEFAULT deprecated in 3.0
55
- if Random.respond_to?(:bytes)
56
- $defs.push "-DHAVE_RANDOM_BYTES"
57
- puts "checking for Random.bytes... yes"
58
- else
59
- puts "checking for Random.bytes... no"
60
- end
61
- end
62
- end
63
-
64
9
  KERNEL_INFO_RE = /Linux (\d)\.(\d+)(?:\.)?((?:\d+\.?)*)(?:\-)?([\w\-]+)?/
65
10
  def get_config
66
11
  if RUBY_PLATFORM !~ /linux/
@@ -90,8 +35,6 @@ def get_config
90
35
  }
91
36
  end
92
37
 
93
- # config_ssl
94
-
95
38
  config = get_config
96
39
  puts "Building UringMachine (\n#{config.map { |(k, v)| " #{k}: #{v}\n"}.join})"
97
40
 
data/ext/um/um.h CHANGED
@@ -246,6 +246,4 @@ VALUE um_queue_shift(struct um *machine, struct um_queue *queue);
246
246
 
247
247
  void um_define_net_constants(VALUE mod);
248
248
 
249
- // void Init_micro_ssl(VALUE mod);
250
-
251
249
  #endif // UM_H
data/ext/um/um_class.c CHANGED
@@ -368,7 +368,5 @@ void Init_UM(void) {
368
368
  rb_define_method(cUM, "unshift", UM_queue_unshift, 2);
369
369
  #endif
370
370
 
371
- // Init_micro_ssl(cUM);
372
-
373
371
  um_define_net_constants(cUM);
374
372
  }
@@ -10,6 +10,19 @@ class UringMachine
10
10
  actor
11
11
  end
12
12
 
13
+ def spin_thread_actor(mod, *a, **k)
14
+ machine = UM.new
15
+ target = Object.new.extend(mod)
16
+ mailbox = UM::Queue.new
17
+ actor = Actor.new
18
+ thread = Thread.new do
19
+ actor.run(machine, target, mailbox)
20
+ end
21
+ target.setup(*a, **k)
22
+ snooze
23
+ actor
24
+ end
25
+
13
26
  class Actor < Fiber
14
27
  def run(machine, target, mailbox)
15
28
  @machine = machine
@@ -23,30 +36,26 @@ class UringMachine
23
36
  end
24
37
 
25
38
  def cast(sym, *a, **k)
26
- self << [:cast, nil, sym, a, k]
39
+ @machine.push @mailbox, [:cast, nil, sym, a, k]
27
40
  self
28
41
  end
29
42
 
30
- def call(sym, *a, **k)
31
- self << [:call, Fiber.current, sym, a, k]
32
- @machine.yield
43
+ def call(response_mailbox, sym, *a, **k)
44
+ @machine.push @mailbox, [:call, response_mailbox, sym, a, k]
45
+ @machine.shift response_mailbox
33
46
  end
34
47
 
35
48
  private
36
49
 
37
50
  def process_message(msg)
38
- type, fiber, sym, args, kwargs = msg
51
+ type, response_mailbox, sym, args, kwargs = msg
39
52
  case type
40
53
  when :cast
41
54
  @target.send(sym, *args, **kwargs)
42
55
  when :call
43
56
  res = @target.send(sym, *args, **kwargs)
44
- @machine.schedule(fiber, res)
57
+ @machine.push(response_mailbox, res)
45
58
  end
46
59
  end
47
-
48
- def <<(msg)
49
- @machine.push(@mailbox, msg)
50
- end
51
60
  end
52
61
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UringMachine
4
- VERSION = '0.7'
4
+ VERSION = '0.8'
5
5
  end
data/lib/uringmachine.rb CHANGED
@@ -12,30 +12,85 @@ class UringMachine
12
12
  @@fiber_map
13
13
  end
14
14
 
15
+ class Terminate < Exception
16
+ end
17
+
15
18
  def spin(value = nil, fiber_class = Fiber, &block)
16
19
  f = fiber_class.new do |resume_value|
17
- block.(resume_value)
20
+ f.set_result block.(resume_value)
18
21
  rescue Exception => e
19
- STDERR.puts "Unhandled fiber exception: #{e.inspect}"
20
- STDERR.puts e.backtrace.join("\n")
21
- exit
22
+ f.set_result e
22
23
  ensure
24
+ f.mark_as_done
25
+ # cleanup
23
26
  @@fiber_map.delete(f)
24
- # yield control
27
+ self.notify_done_listeners(f)
28
+ # transfer control to other fibers
25
29
  self.yield
26
- p :bad_bad_bad
27
30
  end
28
- schedule(f, value)
31
+ self.schedule(f, value)
29
32
  @@fiber_map[f] = true
30
33
  f
31
34
  end
32
35
 
36
+ def join(*fibers)
37
+ results = fibers.inject({}) { |h, f| h[f] = nil; h }
38
+ queue = nil
39
+ pending = nil
40
+ fibers.each do |f|
41
+ if f.done?
42
+ results[f] = f.result
43
+ else
44
+ (pending ||= []) << f
45
+ queue ||= UM::Queue.new
46
+ f.add_done_listener(queue)
47
+ end
48
+ end
49
+ return results.values if !pending
50
+
51
+ while !pending.empty?
52
+ f = self.shift(queue)
53
+ pending.delete(f)
54
+ results[f] = f.result
55
+ end
56
+ results.values
57
+ end
58
+
33
59
  def resolve(hostname, type = :A)
34
60
  @resolver ||= DNSResolver.new(self)
35
61
  @resolver.resolve(hostname, type)
36
62
  end
37
63
 
38
- def ssl_accept(fd, ssl_ctx)
39
- SSL::Connection.new(self, fd, ssl_ctx)
64
+ private
65
+
66
+ def notify_done_listeners(fiber)
67
+ listeners = fiber.done_listeners
68
+ return if !listeners
69
+
70
+ listeners.each { self.push(it, fiber) }
71
+ end
72
+
73
+ module FiberExtensions
74
+ attr_reader :result, :done, :done_listeners
75
+
76
+ def mark_as_done
77
+ @done = true
78
+ end
79
+
80
+ def set_result(value)
81
+ @result = value
82
+ end
83
+
84
+ def done?
85
+ @done
86
+ end
87
+
88
+ def add_done_listener(queue)
89
+ (@done_listeners ||= []) << queue
90
+ end
91
+ end
92
+
93
+ class ::Fiber
94
+ include UringMachine::FiberExtensions
40
95
  end
41
96
  end
data/test/test_actor.rb CHANGED
@@ -7,7 +7,7 @@ require 'uringmachine/actor'
7
7
  class ActorTest < UMBaseTest
8
8
  module Counter
9
9
  def setup
10
- @count = 0
10
+ @count = 0
11
11
  end
12
12
 
13
13
  def incr
@@ -24,16 +24,17 @@ class ActorTest < UMBaseTest
24
24
  end
25
25
 
26
26
  def test_basic_actor_functionality
27
+ mailbox = UM::Queue.new
27
28
  actor = @machine.spin_actor(Counter)
28
29
 
29
30
  assert_kind_of Fiber, actor
30
31
 
31
- assert_equal 0, actor.call(:get)
32
- assert_equal 1, actor.call(:incr)
32
+ assert_equal 0, actor.call(mailbox, :get)
33
+ assert_equal 1, actor.call(mailbox, :incr)
33
34
  assert_equal actor, actor.cast(:incr)
34
- assert_equal 2, actor.call(:get)
35
+ assert_equal 2, actor.call(mailbox, :get)
35
36
  assert_equal actor, actor.cast(:reset)
36
- assert_equal 0, actor.call(:get)
37
+ assert_equal 0, actor.call(mailbox, :get)
37
38
  end
38
39
 
39
40
  module Counter2
@@ -57,7 +58,8 @@ class ActorTest < UMBaseTest
57
58
 
58
59
  def test_actor_with_args
59
60
  actor = @machine.spin_actor(Counter2, 43)
61
+ mailbox = UM::Queue.new
60
62
 
61
- assert_equal 43, actor.call(:get)
63
+ assert_equal 43, actor.call(mailbox, :get)
62
64
  end
63
65
  end
@@ -0,0 +1,171 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'helper'
4
+ require 'socket'
5
+
6
+ class FiberSpinTest < UMBaseTest
7
+ def test_spin
8
+ x = nil
9
+ f = machine.spin do
10
+ x = :foo
11
+ end
12
+
13
+ assert_kind_of Fiber, f
14
+ assert_nil x
15
+
16
+ machine.snooze
17
+
18
+ assert_equal :foo, x
19
+ end
20
+
21
+ def test_spin_with_initial_value
22
+ x = nil
23
+ f = machine.spin(42) do |v|
24
+ x = v
25
+ end
26
+
27
+ assert_kind_of Fiber, f
28
+ assert_nil x
29
+
30
+ machine.snooze
31
+ assert_equal 42, x
32
+ end
33
+
34
+ class MyFiber < Fiber
35
+ end
36
+
37
+ def test_spin_with_custom_class
38
+ f = machine.spin(nil, MyFiber) do
39
+ end
40
+
41
+ assert_kind_of MyFiber, f
42
+ end
43
+ end
44
+
45
+ class FiberTerminateTest < UMBaseTest
46
+ def test_terminate_fiber
47
+ x = nil
48
+ f = machine.spin do
49
+ x = 1
50
+ machine.sleep 0.01
51
+ ensure
52
+ x = 0
53
+ end
54
+
55
+ assert_nil x
56
+ machine.snooze
57
+ assert_equal 1, x
58
+
59
+ machine.schedule(f, UM::Terminate.new)
60
+ 2.times { machine.snooze }
61
+
62
+ assert_equal 0, x
63
+ end
64
+ end
65
+
66
+ class JoinTest < UMBaseTest
67
+ def test_join
68
+ q = UM::Queue.new
69
+ x = nil
70
+
71
+ f = machine.spin do
72
+ x = 1
73
+ machine.push q, machine.shift(q) + 1
74
+ 42
75
+ ensure
76
+ x = 0
77
+ end
78
+
79
+ assert_nil x
80
+ machine.snooze
81
+ assert_equal 1, x
82
+
83
+ machine.spin do
84
+ x = 2
85
+ machine.push q, 2
86
+ end
87
+
88
+ res = machine.join(f)
89
+ assert_equal 0, x
90
+ assert_equal 3, machine.shift(q)
91
+ assert_equal [42], res
92
+ end
93
+
94
+ def test_join_multiple
95
+ f1 = machine.spin do
96
+ :foo
97
+ end
98
+
99
+ f2 = machine.spin do
100
+ machine.sleep(0.001)
101
+ :bar
102
+ end
103
+
104
+ f3 = machine.spin do
105
+ :baz
106
+ end
107
+
108
+ res = machine.join(f1, f2, f3)
109
+ assert_equal [:foo, :bar, :baz], res
110
+ end
111
+
112
+ def test_join_cross_thread
113
+ q = UM::Queue.new
114
+
115
+ t2 = Thread.new do
116
+ m2 = UM.new
117
+ f = m2.spin do
118
+ m2.push(q, f)
119
+ m2.snooze
120
+ :foo
121
+ end
122
+ m2.join(f)
123
+ end
124
+
125
+ f = machine.shift(q)
126
+ assert_kind_of Fiber, f
127
+ res = machine.join(f)
128
+ assert_equal [:foo], res
129
+ ensure
130
+ t2.join
131
+ end
132
+
133
+ def test_join_with_exception
134
+ f = machine.spin do
135
+ raise "Foobar"
136
+ end
137
+
138
+ res = machine.join(f)
139
+ e = res.first
140
+ assert_kind_of RuntimeError, e
141
+ assert_equal 'Foobar', e.message
142
+ end
143
+ end
144
+
145
+ class ScopeTest < UMBaseTest
146
+ def test_scope
147
+ skip
148
+
149
+ x1 = nil
150
+ x2 = nil
151
+
152
+ machine.scope do
153
+ f1 = machine.spin do
154
+ x1 = 1
155
+ machine.sleep 0.01
156
+ ensure
157
+ x1 = 0
158
+ end
159
+
160
+ f2 = machine.spin do
161
+ x2 = 1
162
+ machine.sleep 0.01
163
+ ensure
164
+ x2 = 0
165
+ end
166
+ end
167
+
168
+ assert_equal 0, x1
169
+ assert_equal 0, x2
170
+ end
171
+ end
data/test/test_um.rb CHANGED
@@ -1076,6 +1076,30 @@ class QueueTest < UMBaseTest
1076
1076
  assert_equal :bar, machine.shift(q)
1077
1077
  assert_equal :foo, machine.shift(q)
1078
1078
  end
1079
+
1080
+ def test_cross_thread_push_shift
1081
+ q = UM::Queue.new
1082
+
1083
+ t1 = Thread.new {
1084
+ m = UM.new
1085
+ 3.times { m.push(q, it); m.sleep(0.01) }
1086
+ }
1087
+
1088
+ items = []
1089
+
1090
+ t2 = Thread.new {
1091
+ m = UM.new
1092
+ 3.times {
1093
+ i = m.pop(q)
1094
+ items << i
1095
+ m.sleep(0.01)
1096
+ }
1097
+ }
1098
+
1099
+ [t1, t2].each(&:join)
1100
+
1101
+ assert_equal [0, 1, 2], items
1102
+ end
1079
1103
  end
1080
1104
 
1081
1105
  class OpenTest < UMBaseTest
data/uringmachine.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
  s.extra_rdoc_files = ["README.md"]
19
19
  s.extensions = ["ext/um/extconf.rb"]
20
20
  s.require_paths = ["lib"]
21
- s.required_ruby_version = '>= 3.3'
21
+ s.required_ruby_version = '>= 3.4'
22
22
 
23
23
  s.add_development_dependency 'rake-compiler', '1.2.9'
24
24
  s.add_development_dependency 'minitest', '5.25.4'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uringmachine
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.7'
4
+ version: '0.8'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-28 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rake-compiler
@@ -123,23 +123,18 @@ files:
123
123
  - ext/um/um_mutex_class.c
124
124
  - ext/um/um_op.c
125
125
  - ext/um/um_queue_class.c
126
- - ext/um/um_ssl.c
127
- - ext/um/um_ssl.h
128
- - ext/um/um_ssl_class.c
129
126
  - ext/um/um_sync.c
130
127
  - ext/um/um_utils.c
131
128
  - lib/uringmachine.rb
132
129
  - lib/uringmachine/actor.rb
133
130
  - lib/uringmachine/dns_resolver.rb
134
- - lib/uringmachine/ssl.rb
135
- - lib/uringmachine/ssl/context_builder.rb
136
131
  - lib/uringmachine/version.rb
137
132
  - supressions/ruby.supp
138
133
  - test/helper.rb
139
134
  - test/run.rb
140
135
  - test/test_actor.rb
141
136
  - test/test_async_op.rb
142
- - test/test_ssl.rb
137
+ - test/test_fiber.rb
143
138
  - test/test_um.rb
144
139
  - uringmachine.gemspec
145
140
  - vendor/liburing/.github/actions/codespell/stopwords
@@ -453,14 +448,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
453
448
  requirements:
454
449
  - - ">="
455
450
  - !ruby/object:Gem::Version
456
- version: '3.3'
451
+ version: '3.4'
457
452
  required_rubygems_version: !ruby/object:Gem::Requirement
458
453
  requirements:
459
454
  - - ">="
460
455
  - !ruby/object:Gem::Version
461
456
  version: '0'
462
457
  requirements: []
463
- rubygems_version: 3.6.2
458
+ rubygems_version: 3.6.8
464
459
  specification_version: 4
465
460
  summary: A lean, mean io_uring machine
466
461
  test_files: []