polyphony 0.45.0 → 0.46.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -0
  3. data/.gitmodules +0 -0
  4. data/.rubocop.yml +1 -0
  5. data/CHANGELOG.md +38 -0
  6. data/Gemfile.lock +11 -3
  7. data/README.md +3 -3
  8. data/Rakefile +1 -1
  9. data/TODO.md +10 -18
  10. data/examples/adapters/redis_client.rb +3 -1
  11. data/examples/adapters/redis_pubsub_perf.rb +11 -8
  12. data/examples/adapters/sequel_mysql.rb +1 -1
  13. data/examples/adapters/sequel_pg.rb +24 -0
  14. data/examples/core/{02-awaiting-fibers.rb → await.rb} +0 -0
  15. data/examples/core/{xx-channels.rb → channels.rb} +0 -0
  16. data/examples/core/deferring-an-operation.rb +16 -0
  17. data/examples/core/{xx-erlang-style-genserver.rb → erlang-style-genserver.rb} +16 -9
  18. data/examples/core/{xx-forking.rb → forking.rb} +1 -1
  19. data/examples/core/handling-signals.rb +11 -0
  20. data/examples/core/{03-interrupting.rb → interrupt.rb} +0 -0
  21. data/examples/core/{xx-pingpong.rb → pingpong.rb} +7 -5
  22. data/examples/core/{xx-recurrent-timer.rb → recurrent-timer.rb} +1 -1
  23. data/examples/core/{xx-resource_delegate.rb → resource_delegate.rb} +3 -4
  24. data/examples/core/{01-spinning-up-fibers.rb → spin.rb} +1 -1
  25. data/examples/core/{xx-spin_error_backtrace.rb → spin_error_backtrace.rb} +1 -1
  26. data/examples/core/{xx-supervise-process.rb → supervise-process.rb} +8 -5
  27. data/examples/core/supervisor.rb +20 -0
  28. data/examples/core/{xx-thread-sleep.rb → thread-sleep.rb} +0 -0
  29. data/examples/core/{xx-thread_pool.rb → thread_pool.rb} +0 -0
  30. data/examples/core/{xx-throttling.rb → throttling.rb} +0 -0
  31. data/examples/core/{xx-timeout.rb → timeout.rb} +0 -0
  32. data/examples/core/{xx-using-a-mutex.rb → using-a-mutex.rb} +0 -0
  33. data/examples/core/{xx-worker-thread.rb → worker-thread.rb} +2 -2
  34. data/examples/io/{xx-backticks.rb → backticks.rb} +0 -0
  35. data/examples/io/{xx-echo_client.rb → echo_client.rb} +1 -1
  36. data/examples/io/{xx-echo_client_from_stdin.rb → echo_client_from_stdin.rb} +2 -2
  37. data/examples/io/{xx-echo_pipe.rb → echo_pipe.rb} +1 -1
  38. data/examples/io/{xx-echo_server.rb → echo_server.rb} +0 -0
  39. data/examples/io/{xx-echo_server_with_timeout.rb → echo_server_with_timeout.rb} +1 -1
  40. data/examples/io/{xx-echo_stdin.rb → echo_stdin.rb} +0 -0
  41. data/examples/io/{xx-happy-eyeballs.rb → happy-eyeballs.rb} +0 -0
  42. data/examples/io/{xx-httparty.rb → httparty.rb} +4 -13
  43. data/examples/io/{xx-irb.rb → irb.rb} +0 -0
  44. data/examples/io/{xx-net-http.rb → net-http.rb} +0 -0
  45. data/examples/io/{xx-open.rb → open.rb} +0 -0
  46. data/examples/io/{xx-pry.rb → pry.rb} +0 -0
  47. data/examples/io/{xx-rack_server.rb → rack_server.rb} +0 -0
  48. data/examples/io/raw.rb +14 -0
  49. data/examples/io/reline.rb +18 -0
  50. data/examples/io/{xx-system.rb → system.rb} +1 -1
  51. data/examples/io/{xx-tcpserver.rb → tcpserver.rb} +0 -0
  52. data/examples/io/{xx-tcpsocket.rb → tcpsocket.rb} +0 -0
  53. data/examples/io/tunnel.rb +6 -1
  54. data/examples/io/{xx-zip.rb → zip.rb} +0 -0
  55. data/examples/performance/fiber_transfer.rb +2 -1
  56. data/examples/performance/fs_read.rb +5 -6
  57. data/examples/performance/multi_snooze.rb +0 -1
  58. data/examples/{io/xx-switch.rb → performance/switch.rb} +2 -1
  59. data/examples/performance/thread-vs-fiber/{xx-httparty_multi.rb → httparty_multi.rb} +3 -4
  60. data/examples/performance/thread-vs-fiber/{xx-httparty_threaded.rb → httparty_threaded.rb} +0 -0
  61. data/examples/performance/thread-vs-fiber/polyphony_mt_server.rb +1 -1
  62. data/examples/performance/thread-vs-fiber/polyphony_server.rb +1 -2
  63. data/examples/performance/thread-vs-fiber/threaded_server.rb +1 -5
  64. data/examples/performance/thread_pool_perf.rb +6 -7
  65. data/ext/liburing/liburing.h +585 -0
  66. data/ext/liburing/liburing/README.md +4 -0
  67. data/ext/liburing/liburing/barrier.h +73 -0
  68. data/ext/liburing/liburing/compat.h +15 -0
  69. data/ext/liburing/liburing/io_uring.h +343 -0
  70. data/ext/liburing/queue.c +333 -0
  71. data/ext/liburing/register.c +187 -0
  72. data/ext/liburing/setup.c +210 -0
  73. data/ext/liburing/syscall.c +54 -0
  74. data/ext/liburing/syscall.h +18 -0
  75. data/ext/polyphony/backend.h +1 -16
  76. data/ext/polyphony/backend_common.h +109 -0
  77. data/ext/polyphony/backend_io_uring.c +884 -0
  78. data/ext/polyphony/backend_io_uring_context.c +73 -0
  79. data/ext/polyphony/backend_io_uring_context.h +52 -0
  80. data/ext/polyphony/{libev_backend.c → backend_libev.c} +255 -345
  81. data/ext/polyphony/event.c +1 -1
  82. data/ext/polyphony/extconf.rb +31 -13
  83. data/ext/polyphony/fiber.c +111 -27
  84. data/ext/polyphony/libev.c +4 -0
  85. data/ext/polyphony/libev.h +8 -2
  86. data/ext/polyphony/liburing.c +8 -0
  87. data/ext/polyphony/playground.c +51 -0
  88. data/ext/polyphony/polyphony.c +6 -8
  89. data/ext/polyphony/polyphony.h +29 -25
  90. data/ext/polyphony/polyphony_ext.c +13 -6
  91. data/ext/polyphony/queue.c +3 -4
  92. data/ext/polyphony/ring_buffer.c +0 -1
  93. data/ext/polyphony/runqueue.c +102 -0
  94. data/ext/polyphony/runqueue_ring_buffer.c +85 -0
  95. data/ext/polyphony/runqueue_ring_buffer.h +31 -0
  96. data/ext/polyphony/thread.c +45 -92
  97. data/lib/polyphony.rb +2 -2
  98. data/lib/polyphony/adapters/fs.rb +1 -1
  99. data/lib/polyphony/adapters/process.rb +0 -3
  100. data/lib/polyphony/adapters/redis.rb +1 -1
  101. data/lib/polyphony/adapters/trace.rb +2 -2
  102. data/lib/polyphony/core/global_api.rb +9 -12
  103. data/lib/polyphony/core/sync.rb +6 -2
  104. data/lib/polyphony/extensions/core.rb +6 -24
  105. data/lib/polyphony/extensions/debug.rb +13 -0
  106. data/lib/polyphony/extensions/fiber.rb +21 -44
  107. data/lib/polyphony/extensions/io.rb +55 -10
  108. data/lib/polyphony/extensions/socket.rb +70 -12
  109. data/lib/polyphony/version.rb +1 -1
  110. data/polyphony.gemspec +3 -2
  111. data/test/helper.rb +36 -4
  112. data/test/io_uring_test.rb +55 -0
  113. data/test/stress.rb +5 -2
  114. data/test/test_backend.rb +4 -6
  115. data/test/test_ext.rb +1 -2
  116. data/test/test_fiber.rb +31 -24
  117. data/test/test_global_api.rb +58 -31
  118. data/test/test_io.rb +58 -0
  119. data/test/test_signal.rb +11 -8
  120. data/test/test_socket.rb +17 -0
  121. data/test/test_sync.rb +21 -0
  122. data/test/test_throttler.rb +3 -6
  123. data/test/test_trace.rb +7 -5
  124. metadata +86 -76
  125. data/examples/adapters/concurrent-ruby.rb +0 -9
  126. data/examples/core/04-handling-signals.rb +0 -19
  127. data/examples/core/xx-at_exit.rb +0 -29
  128. data/examples/core/xx-backend.rb +0 -102
  129. data/examples/core/xx-caller.rb +0 -12
  130. data/examples/core/xx-daemon.rb +0 -14
  131. data/examples/core/xx-deadlock.rb +0 -8
  132. data/examples/core/xx-deferring-an-operation.rb +0 -14
  133. data/examples/core/xx-exception-backtrace.rb +0 -40
  134. data/examples/core/xx-fork-cleanup.rb +0 -22
  135. data/examples/core/xx-fork-spin.rb +0 -42
  136. data/examples/core/xx-fork-terminate.rb +0 -27
  137. data/examples/core/xx-move_on.rb +0 -23
  138. data/examples/core/xx-queue-async.rb +0 -120
  139. data/examples/core/xx-readpartial.rb +0 -18
  140. data/examples/core/xx-signals.rb +0 -16
  141. data/examples/core/xx-sleep-forever.rb +0 -9
  142. data/examples/core/xx-sleeping.rb +0 -25
  143. data/examples/core/xx-snooze-starve.rb +0 -16
  144. data/examples/core/xx-spin-fork.rb +0 -49
  145. data/examples/core/xx-state-machine.rb +0 -51
  146. data/examples/core/xx-stop.rb +0 -20
  147. data/examples/core/xx-supervisors.rb +0 -21
  148. data/examples/core/xx-thread-selector-sleep.rb +0 -51
  149. data/examples/core/xx-thread-selector-snooze.rb +0 -46
  150. data/examples/core/xx-thread-snooze.rb +0 -34
  151. data/examples/core/xx-timer-gc.rb +0 -17
  152. data/examples/core/xx-trace.rb +0 -79
  153. data/examples/performance/xx-array.rb +0 -11
  154. data/examples/performance/xx-fiber-switch.rb +0 -9
  155. data/examples/performance/xx-snooze.rb +0 -15
  156. data/examples/xx-spin.rb +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f9c8ab74213c6cc5e3852f73ee027ee496f2b04c6844e09856c9771ea5e7839a
4
- data.tar.gz: 83d7c533024b6d6d633b9e18abc392911adfc07f728af826bd84cce35cafb20c
3
+ metadata.gz: 890abc2b84ed305f591c697764ea16255059aeb3cd4ddd23195b81f78f5f6daf
4
+ data.tar.gz: a02442318f82682ba1fa3a87e2b4e7ad8ae06d365a7d4a4b5c45689b2e55472f
5
5
  SHA512:
6
- metadata.gz: c42e49ebcd6fb10b384438cb7688801a387963bc2a6fb2c1d3de6d022a7731a7d88db138a34b364b35c9d71830b975a69cb1f14fb277166a9db1802e24e82dec
7
- data.tar.gz: 6c578eacded00dd7a77a35124c69ebc966e4f9aa42264913df82af147f43955a2ecd86087630c085fcd4d6e964aa705202c5aa24bb4032648d3ba278d60d4f63
6
+ metadata.gz: 506a2fdbdee9e6c5bb94b976489537792941326080441f3d93924cd9657db5188b29e4ced6e1c8a6f8db06ae211da0522b3ac042e45365be1af2e68f8b157b0e
7
+ data.tar.gz: cbc0e333731e035c2094abfa72d425e649c210a8c9d3aec467446f615315cfc6e1f6de664321099ccdf93ddd6e1bb0ba484b2b8b53922725b2df8483aedefeab
@@ -23,6 +23,8 @@ jobs:
23
23
  run: |
24
24
  gem install bundler
25
25
  bundle install
26
+ - name: Show Linux kernel version
27
+ run: uname -r
26
28
  - name: Compile C-extension
27
29
  run: bundle exec rake compile
28
30
  - name: Run tests
File without changes
@@ -96,6 +96,7 @@ Metrics/ModuleLength:
96
96
  Metrics/ClassLength:
97
97
  Exclude:
98
98
  - lib/polyphony/http/server/http1.rb
99
+ - lib/polyphony/extensions/io.rb
99
100
  - test/**/*.rb
100
101
  - examples/**/*.rb
101
102
 
@@ -1,3 +1,41 @@
1
+ ## 0.46.0
2
+
3
+ * Implement [io_uring backend](https://github.com/digital-fabric/polyphony/pull/44)
4
+
5
+ ## 0.45.5
6
+
7
+ * Fix compilation error (#43)
8
+ * Add support for resetting move_on_after, cancel_after timeouts
9
+ * Optimize anti-event starvation polling
10
+ * Implement optimized runqueue for better performance
11
+ * Schedule parent with priority on uncaught exception
12
+ * Fix race condition in `Mutex#synchronize` (#41)
13
+
14
+ ## 0.45.4
15
+
16
+ * Improve signal trapping mechanism
17
+
18
+ ## 0.45.3
19
+
20
+ * Don't swallow error in `Process#kill_and_await`
21
+ * Add `Fiber#mailbox` attribute reader
22
+ * Fix bug in `Fiber.await`
23
+ * Implement `IO#getc`, `IO#getbyte`
24
+
25
+ ## 0.45.2
26
+
27
+ * Rewrite `Fiber#<<`, `Fiber#await`, `Fiber#receive` in C
28
+
29
+ ## 0.45.1
30
+
31
+ * Fix Net::HTTP compatibility
32
+ * Fix fs adapter
33
+ * Improve performance of IO#puts
34
+ * Mutex#synchronize
35
+ * Fix Socket#connect
36
+ * Cleanup code
37
+ * Improve support for Ruby 3 keyword args
38
+
1
39
  ## 0.45.0
2
40
 
3
41
  * Cleanup code
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.45.0)
4
+ polyphony (0.46.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -23,6 +23,9 @@ GEM
23
23
  forwardable-extended (2.6.0)
24
24
  hiredis (0.6.3)
25
25
  http_parser.rb (0.6.0)
26
+ httparty (0.17.1)
27
+ mime-types (~> 3.0)
28
+ multi_xml (>= 0.5.2)
26
29
  i18n (0.9.5)
27
30
  concurrent-ruby (~> 1.0)
28
31
  jekyll (3.8.6)
@@ -60,12 +63,16 @@ GEM
60
63
  rb-inotify (~> 0.9, >= 0.9.10)
61
64
  mercenary (0.3.6)
62
65
  method_source (1.0.0)
66
+ mime-types (3.3.1)
67
+ mime-types-data (~> 3.2015)
68
+ mime-types-data (3.2020.0512)
63
69
  minitest (5.13.0)
64
70
  minitest-reporters (1.4.2)
65
71
  ansi
66
72
  builder
67
73
  minitest (>= 5.0)
68
74
  ruby-progressbar
75
+ multi_xml (0.6.0)
69
76
  mysql2 (0.5.3)
70
77
  parallel (1.19.1)
71
78
  parser (2.7.0.2)
@@ -80,7 +87,7 @@ GEM
80
87
  rack (2.2.3)
81
88
  rainbow (3.0.0)
82
89
  rake (12.3.3)
83
- rake-compiler (1.0.5)
90
+ rake-compiler (1.1.1)
84
91
  rake
85
92
  rb-fsevent (0.10.3)
86
93
  rb-inotify (0.10.1)
@@ -122,6 +129,7 @@ PLATFORMS
122
129
  DEPENDENCIES
123
130
  hiredis (= 0.6.3)
124
131
  http_parser.rb (~> 0.6.0)
132
+ httparty (= 0.17.1)
125
133
  jekyll (~> 3.8.6)
126
134
  jekyll-remote-theme (~> 0.4.1)
127
135
  jekyll-seo-tag (~> 2.6.1)
@@ -133,7 +141,7 @@ DEPENDENCIES
133
141
  polyphony!
134
142
  pry (= 0.13.1)
135
143
  rack (>= 2.0.8, < 2.3.0)
136
- rake-compiler (= 1.0.5)
144
+ rake-compiler (= 1.1.1)
137
145
  redis (= 4.1.0)
138
146
  rubocop (= 0.85.1)
139
147
  sequel (= 5.34.0)
data/README.md CHANGED
@@ -35,9 +35,9 @@
35
35
  Polyphony is a library for building concurrent applications in Ruby. Polyphony
36
36
  harnesses the power of [Ruby fibers](https://ruby-doc.org/core-2.5.1/Fiber.html)
37
37
  to provide a cooperative, sequential coroutine-based concurrency model. Under
38
- the hood, Polyphony uses [libev](https://github.com/enki/libev) as a
39
- high-performance event reactor that provides timers, I/O watchers and other
40
- asynchronous event primitives.
38
+ the hood, Polyphony uses
39
+ [io_uring](https://unixism.net/loti/what_is_io_uring.html) or
40
+ [libev](https://github.com/enki/libev) to maximize I/O performance.
41
41
 
42
42
  ## Features
43
43
 
data/Rakefile CHANGED
@@ -23,4 +23,4 @@ task :docs do
23
23
  exec 'RUBYOPT=-W0 jekyll serve -s docs -H ec2-18-156-117-172.eu-central-1.compute.amazonaws.com'
24
24
  end
25
25
 
26
- CLEAN.include "**/*.o", "**/*.so", "**/*.bundle", "**/*.jar", "pkg", "tmp"
26
+ CLEAN.include "**/*.o", "**/*.so", "**/*.so.*", "**/*.a", "**/*.bundle", "**/*.jar", "pkg", "tmp"
data/TODO.md CHANGED
@@ -1,15 +1,15 @@
1
- 0.45
2
-
3
- - Review all code
4
- - Cleanup C code
5
- - Cleanup and annotate examples (and remove all the examples used for
6
- debugging). Focus on examples that serve as "how-to".
7
-
8
- 0.45.1
9
-
1
+ - change fiber_trace method to return nil, change trace logic to use provided
2
+ arguments instead of return values for fiber events
3
+ - allow backend selection at runtime
4
+ - add Backend#timer_loop that does what throttled_loop does, on lower level
5
+ - Adapter for io/console (what does `IO#raw` do?)
10
6
  - Adapter for Pry and IRB (Which fixes #5 and #6)
7
+ - Improve `#supervise`. It does not work as advertised, and seems to exhibit an
8
+ inconsistent behaviour (see supervisor example).
9
+ - Fix backtrace for `Timeout.timeout` API (see timeout example).
10
+ - Check why worker-thread example doesn't work.
11
11
 
12
- 0.46.0
12
+ 0.47
13
13
 
14
14
  - Debugging
15
15
  - Eat your own dogfood: need a good tool to check what's going on when some
@@ -123,8 +123,6 @@
123
123
  - discuss using `snooze` for ensuring responsiveness when executing CPU-bound work
124
124
 
125
125
 
126
- ## 0.47
127
-
128
126
  ### Some more API work, more docs
129
127
 
130
128
  - sintra app with database access (postgresql)
@@ -136,14 +134,10 @@
136
134
  - proceed from there
137
135
 
138
136
 
139
- ## 0.48
140
-
141
137
  ### Sinatra / Sidekiq
142
138
 
143
139
  - Pull out redis/postgres code, put into new `polyphony-xxx` gems
144
140
 
145
- ## 0.49
146
-
147
141
  ### Testing && Docs
148
142
 
149
143
  - More tests
@@ -154,8 +148,6 @@
154
148
  - `IO.foreach`
155
149
  - `Process.waitpid`
156
150
 
157
- ## 0.50 DNS
158
-
159
151
  ### DNS client
160
152
 
161
153
  ```ruby
@@ -3,7 +3,9 @@
3
3
  require 'bundler/setup'
4
4
  require 'polyphony/adapters/redis'
5
5
 
6
- redis = Redis.new
6
+ ::Exception.__disable_sanitized_backtrace__ = true
7
+
8
+ redis = Redis.new(host: ENV['REDIS_HOST'] || 'localhost')
7
9
 
8
10
  X = 10
9
11
 
@@ -6,7 +6,7 @@ require 'json'
6
6
 
7
7
  X_SESSIONS = 1000
8
8
  X_NODES = 10_000
9
- X_SUBSCRIPTIONS_PER_SESSION = 100
9
+ X_SUBSCRIPTIONS_PER_SESSION = 1000
10
10
 
11
11
  $sessions = []
12
12
  X_SESSIONS.times do
@@ -17,8 +17,11 @@ X_SESSIONS.times do
17
17
  }
18
18
  end
19
19
 
20
+ REDIS_HOST = ENV['REDIS_HOST'] || 'localhost'
21
+ p redis_host: REDIS_HOST
22
+
20
23
  spin do
21
- redis = Redis.new
24
+ redis = Redis.new(host: REDIS_HOST)
22
25
  redis.subscribe('events') do |on|
23
26
  on.message do |_, message|
24
27
  distribute_event(JSON.parse(message, symbolize_names: true))
@@ -30,18 +33,18 @@ $update_count = 0
30
33
 
31
34
  def distribute_event(event)
32
35
  $update_count += 1
33
- # t0 = Time.now
36
+ t0 = Time.now
34
37
  count = 0
35
38
  $sessions.each do |s|
36
39
  count += 1 if s[:subscriptions].include?(event[:path])
37
40
  end
38
- # elapsed = Time.now - t0
39
- # rate = X_SESSIONS / elapsed
40
- # puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
41
+ elapsed = Time.now - t0
42
+ rate = X_SESSIONS / elapsed
43
+ puts "elapsed: #{elapsed} (#{rate}/s)" if $update_count % 100 == 0
41
44
  end
42
45
 
43
46
  spin do
44
- redis = Redis.new
47
+ redis = Redis.new(host: REDIS_HOST)
45
48
  throttled_loop(1000) do
46
49
  redis.publish('events', { path: "node#{rand(X_NODES)}" }.to_json)
47
50
  end
@@ -60,7 +63,7 @@ spin do
60
63
  end
61
64
  end
62
65
 
63
- trap(:int) do
66
+ trap('SIGINT') do
64
67
  puts 'bye...'
65
68
  exit!
66
69
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'bundler/setup'
4
4
  require 'polyphony/adapters/sequel'
5
- require 'polyphony/adapters/mysql2'
5
+ require 'polyphony/adapters/postgres'
6
6
 
7
7
  time_printer = spin do
8
8
  last = Time.now
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony/adapters/sequel'
5
+ require 'polyphony/adapters/postgres'
6
+
7
+ URL = ENV['SEQUEL_URL'] || 'postgres://localhost/test'
8
+
9
+ x = 10000
10
+ query_count = 0
11
+
12
+ spin do
13
+ db = Sequel.connect(URL)
14
+ x.times { query_count += 1; db.execute('select 1 as test') }
15
+ end
16
+
17
+ spin do
18
+ db = Sequel.connect(URL)
19
+ x.times { query_count += 1; db.execute('select 2 as test') }
20
+ end
21
+
22
+ t0 = Time.now
23
+ Fiber.current.await_all_children
24
+ puts "query rate: #{query_count / (Time.now - t0)} reqs/s; count = #{query_count}"
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ spin do
7
+ puts 'two'
8
+ # spinning a fiber from the parent fiber allows us to schedule an operation to
9
+ # be performed even after the current fiber is terminated
10
+ Fiber.current.parent.spin { puts 'four' }
11
+ puts 'three'
12
+ end
13
+
14
+ puts 'one'
15
+
16
+ suspend
@@ -3,8 +3,10 @@
3
3
  require 'bundler/setup'
4
4
  require 'polyphony'
5
5
 
6
- class GenServer
7
- def self.start(receiver, *args)
6
+ module GenServer
7
+ module_function
8
+
9
+ def start(receiver, *args)
8
10
  fiber = spin do
9
11
  state = receiver.initial_state(*args)
10
12
  loop do
@@ -14,11 +16,10 @@ class GenServer
14
16
  end
15
17
  end
16
18
  build_api(fiber, receiver)
17
- snooze
18
19
  fiber
19
20
  end
20
21
 
21
- def self.build_api(fiber, receiver)
22
+ def build_api(fiber, receiver)
22
23
  receiver.methods(false).each do |m|
23
24
  if m =~ /!$/
24
25
  fiber.define_singleton_method(m) do |*args|
@@ -32,7 +33,7 @@ class GenServer
32
33
  end
33
34
  end
34
35
 
35
- def self.cast(process, method, *args)
36
+ def cast(process, method, *args)
36
37
  process << {
37
38
  from: Fiber.current,
38
39
  method: method,
@@ -40,7 +41,7 @@ class GenServer
40
41
  }
41
42
  end
42
43
 
43
- def self.call(process, method, *args)
44
+ def call(process, method, *args)
44
45
  process << {
45
46
  from: Fiber.current,
46
47
  method: method,
@@ -50,21 +51,27 @@ class GenServer
50
51
  end
51
52
  end
52
53
 
54
+ # In a generic server the state is not held in an instance variable but rather
55
+ # passed as the first parameter to method calls. The return value of each method
56
+ # is an array consisting of the result and the potentially mutated state.
53
57
  module Map
54
- def self.initial_state(hash = {})
58
+ module_function
59
+
60
+ def initial_state(hash = {})
55
61
  hash
56
62
  end
57
63
 
58
- def self.get(state, key)
64
+ def get(state, key)
59
65
  [state[key], state]
60
66
  end
61
67
 
62
- def self.put!(state, key, value)
68
+ def put!(state, key, value)
63
69
  state[key] = value
64
70
  [:noreply, state]
65
71
  end
66
72
  end
67
73
 
74
+ # start server with initial state
68
75
  map_server = GenServer.start(Map, {foo: :bar})
69
76
 
70
77
  puts 'getting value from map server'
@@ -20,5 +20,5 @@ end
20
20
  puts "got child pid #{pid}"
21
21
 
22
22
  puts 'parent waiting for child'
23
- Gyro::Child.new(pid).await
23
+ Thread.current.backend.waitpid(pid)
24
24
  puts 'parent done waiting'
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/setup'
4
+ require 'polyphony'
5
+
6
+ puts "going to sleep (press Ctrl-C to stop)"
7
+ begin
8
+ sleep
9
+ ensure
10
+ puts "done sleeping"
11
+ end
@@ -9,10 +9,12 @@ pong = spin_loop do
9
9
  ping << 'pong'
10
10
  end
11
11
 
12
- ping = spin_loop do
13
- pong << ['ping', Fiber.current]
14
- msg = receive
15
- puts msg
12
+ ping = spin do
13
+ 3.times do
14
+ pong << ['ping', Fiber.current]
15
+ msg = receive
16
+ puts msg
17
+ end
16
18
  end
17
19
 
18
- suspend
20
+ ping.await