polyphony 0.45.0 → 0.46.0

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.
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