polyphony 0.13 → 0.14

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 (135) hide show
  1. checksums.yaml +4 -4
  2. data/.gitbook.yaml +5 -0
  3. data/.gitignore +55 -0
  4. data/.rubocop.yml +49 -0
  5. data/CHANGELOG.md +13 -2
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +31 -0
  8. data/LICENSE +21 -0
  9. data/README.md +35 -18
  10. data/Rakefile +20 -0
  11. data/TODO.md +49 -0
  12. data/docs/getting-started/getting-started.md +10 -0
  13. data/docs/getting-started/tutorial.md +2 -0
  14. data/docs/summary.md +9 -0
  15. data/examples/core/cancel.rb +10 -0
  16. data/examples/core/channel_echo.rb +43 -0
  17. data/examples/core/enumerator.rb +14 -0
  18. data/examples/core/fork.rb +22 -0
  19. data/examples/core/genserver.rb +74 -0
  20. data/examples/core/lock.rb +20 -0
  21. data/examples/core/move_on.rb +11 -0
  22. data/examples/core/move_on_twice.rb +17 -0
  23. data/examples/core/move_on_with_ensure.rb +17 -0
  24. data/examples/core/multiple_async.rb +17 -0
  25. data/examples/core/nested_async.rb +18 -0
  26. data/examples/core/nested_cancel.rb +41 -0
  27. data/examples/core/nested_multiple_async.rb +19 -0
  28. data/examples/core/next_tick.rb +13 -0
  29. data/examples/core/pulse.rb +13 -0
  30. data/examples/core/resource.rb +29 -0
  31. data/examples/core/resource_cancel.rb +34 -0
  32. data/examples/core/resource_delegate.rb +32 -0
  33. data/examples/core/sleep.rb +9 -0
  34. data/examples/core/sleep2.rb +13 -0
  35. data/examples/core/spawn.rb +15 -0
  36. data/examples/core/spawn_cancel.rb +19 -0
  37. data/examples/core/spawn_error.rb +28 -0
  38. data/examples/core/supervisor.rb +22 -0
  39. data/examples/core/supervisor_with_cancel_scope.rb +24 -0
  40. data/examples/core/supervisor_with_error.rb +23 -0
  41. data/examples/core/supervisor_with_manual_move_on.rb +25 -0
  42. data/examples/core/thread.rb +30 -0
  43. data/examples/core/thread_cancel.rb +30 -0
  44. data/examples/core/thread_pool.rb +60 -0
  45. data/examples/core/throttle.rb +17 -0
  46. data/examples/fs/read.rb +37 -0
  47. data/examples/interfaces/pg_client.rb +38 -0
  48. data/examples/interfaces/pg_pool.rb +37 -0
  49. data/examples/interfaces/pg_query.rb +32 -0
  50. data/examples/interfaces/redis_channels.rb +119 -0
  51. data/examples/interfaces/redis_client.rb +21 -0
  52. data/examples/interfaces/redis_pubsub.rb +26 -0
  53. data/examples/interfaces/redis_pubsub_perf.rb +65 -0
  54. data/examples/io/config.ru +3 -0
  55. data/examples/io/echo_client.rb +22 -0
  56. data/examples/io/echo_server.rb +14 -0
  57. data/examples/io/echo_server_with_timeout.rb +33 -0
  58. data/examples/io/echo_stdin.rb +15 -0
  59. data/examples/io/happy_eyeballs.rb +32 -0
  60. data/examples/io/http_client.rb +19 -0
  61. data/examples/io/http_server.js +24 -0
  62. data/examples/io/http_server.rb +16 -0
  63. data/examples/io/http_server_forked.rb +27 -0
  64. data/examples/io/http_server_throttled.rb +16 -0
  65. data/examples/io/http_ws_server.rb +42 -0
  66. data/examples/io/https_client.rb +17 -0
  67. data/examples/io/https_server.rb +23 -0
  68. data/examples/io/https_wss_server.rb +46 -0
  69. data/examples/io/rack_server.rb +19 -0
  70. data/examples/io/rack_server_https.rb +24 -0
  71. data/examples/io/rack_server_https_forked.rb +32 -0
  72. data/examples/io/websocket_server.rb +33 -0
  73. data/examples/io/ws_page.html +34 -0
  74. data/examples/io/wss_page.html +34 -0
  75. data/examples/performance/perf_multi_snooze.rb +21 -0
  76. data/examples/performance/perf_snooze.rb +30 -0
  77. data/examples/performance/thread-vs-fiber/polyphony_server.rb +63 -0
  78. data/examples/performance/thread-vs-fiber/threaded_server.rb +27 -0
  79. data/examples/streams/lines.rb +27 -0
  80. data/examples/streams/stdio.rb +18 -0
  81. data/ext/ev/async.c +168 -0
  82. data/ext/ev/child.c +169 -0
  83. data/ext/ev/ev.h +32 -0
  84. data/ext/ev/ev_ext.c +20 -0
  85. data/ext/ev/ev_module.c +222 -0
  86. data/ext/ev/io.c +405 -0
  87. data/ext/ev/libev.h +9 -0
  88. data/ext/ev/signal.c +119 -0
  89. data/ext/ev/timer.c +197 -0
  90. data/ext/libev/Changes +513 -0
  91. data/ext/libev/LICENSE +37 -0
  92. data/ext/libev/README +58 -0
  93. data/ext/libev/README.embed +3 -0
  94. data/ext/libev/ev.c +5214 -0
  95. data/ext/libev/ev.h +849 -0
  96. data/ext/libev/ev_epoll.c +285 -0
  97. data/ext/libev/ev_kqueue.c +218 -0
  98. data/ext/libev/ev_poll.c +151 -0
  99. data/ext/libev/ev_port.c +189 -0
  100. data/ext/libev/ev_select.c +316 -0
  101. data/ext/libev/ev_vars.h +204 -0
  102. data/ext/libev/ev_win32.c +162 -0
  103. data/ext/libev/ev_wrap.h +200 -0
  104. data/ext/libev/test_libev_win32.c +123 -0
  105. data/lib/polyphony.rb +7 -2
  106. data/lib/polyphony/core.rb +1 -1
  107. data/lib/polyphony/core/{coroutine.rb → coprocess.rb} +10 -10
  108. data/lib/polyphony/core/exceptions.rb +5 -5
  109. data/lib/polyphony/core/supervisor.rb +16 -16
  110. data/lib/polyphony/core/thread.rb +1 -1
  111. data/lib/polyphony/extensions/io.rb +43 -42
  112. data/lib/polyphony/extensions/kernel.rb +10 -34
  113. data/lib/polyphony/extensions/postgres.rb +3 -2
  114. data/lib/polyphony/extensions/redis.rb +1 -1
  115. data/lib/polyphony/extensions/socket.rb +8 -4
  116. data/lib/polyphony/extensions/ssl.rb +0 -54
  117. data/lib/polyphony/http/agent.rb +4 -10
  118. data/lib/polyphony/http/http1.rb +25 -25
  119. data/lib/polyphony/http/http1_request.rb +38 -26
  120. data/lib/polyphony/http/http2.rb +4 -5
  121. data/lib/polyphony/http/http2_request.rb +12 -18
  122. data/lib/polyphony/http/rack.rb +1 -3
  123. data/lib/polyphony/http/server.rb +9 -9
  124. data/lib/polyphony/net.rb +2 -2
  125. data/lib/polyphony/resource_pool.rb +5 -1
  126. data/lib/polyphony/version.rb +1 -1
  127. data/lib/polyphony/websocket.rb +52 -0
  128. data/polyphony.gemspec +31 -0
  129. data/test/test_coprocess.rb +131 -0
  130. data/test/test_core.rb +274 -0
  131. data/test/test_ev.rb +117 -0
  132. data/test/test_io.rb +38 -0
  133. metadata +113 -7
  134. data/lib/polyphony/core/async.rb +0 -36
  135. data/lib/polyphony/net_old.rb +0 -299
@@ -0,0 +1,123 @@
1
+ // a single header file is required
2
+ #include <ev.h>
3
+ #include <stdio.h>
4
+ #include <io.h>
5
+
6
+ // every watcher type has its own typedef'd struct
7
+ // with the name ev_TYPE
8
+ ev_io stdin_watcher;
9
+ ev_timer timeout_watcher;
10
+
11
+ // all watcher callbacks have a similar signature
12
+ // this callback is called when data is readable on stdin
13
+ static void
14
+ stdin_cb (EV_P_ ev_io *w, int revents)
15
+ {
16
+ puts ("stdin ready or done or something");
17
+ // for one-shot events, one must manually stop the watcher
18
+ // with its corresponding stop function.
19
+ //ev_io_stop (EV_A_ w);
20
+
21
+ // this causes all nested ev_loop's to stop iterating
22
+ //ev_unloop (EV_A_ EVUNLOOP_ALL);
23
+ }
24
+
25
+ // another callback, this time for a time-out
26
+ static void
27
+ timeout_cb (EV_P_ ev_timer *w, int revents)
28
+ {
29
+ puts ("timeout");
30
+ // this causes the innermost ev_loop to stop iterating
31
+ ev_unloop (EV_A_ EVUNLOOP_ONE);
32
+ }
33
+
34
+
35
+
36
+ #include <winsock.h>
37
+
38
+ #include <stdlib.h>
39
+ #include <iostream>
40
+ int get_server_fd()
41
+ {
42
+
43
+ //----------------------
44
+ // Initialize Winsock.
45
+ WSADATA wsaData;
46
+ int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
47
+ if (iResult != NO_ERROR) {
48
+ printf("Error at WSAStartup()\n");
49
+ return 1;
50
+ }
51
+
52
+ //----------------------
53
+ // Create a SOCKET for listening for
54
+ // incoming connection requests.
55
+ SOCKET ListenSocket;
56
+ ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
57
+ if (ListenSocket == INVALID_SOCKET) {
58
+ printf("Error at socket(): %ld\n", WSAGetLastError());
59
+ WSACleanup();
60
+ return 1;
61
+ }
62
+ printf("socket returned %d\n", ListenSocket);
63
+
64
+ //----------------------
65
+ // The sockaddr_in structure specifies the address family,
66
+ // IP address, and port for the socket that is being bound.
67
+ sockaddr_in service;
68
+ service.sin_family = AF_INET;
69
+ service.sin_addr.s_addr = inet_addr("127.0.0.1");
70
+ service.sin_port = htons(4444);
71
+
72
+ if (bind( ListenSocket,
73
+ (SOCKADDR*) &service,
74
+ sizeof(service)) == SOCKET_ERROR) {
75
+ printf("bind() failed.\n");
76
+ closesocket(ListenSocket);
77
+ WSACleanup();
78
+ return 1;
79
+ }
80
+
81
+ //----------------------
82
+ // Listen for incoming connection requests.
83
+ // on the created socket
84
+ if (listen( ListenSocket, 1 ) == SOCKET_ERROR) {
85
+ printf("Error listening on socket.\n");
86
+ closesocket(ListenSocket);
87
+ WSACleanup();
88
+ return 1;
89
+ }
90
+
91
+
92
+ printf("sock and osf handle are %d %d, error is \n", ListenSocket, _get_osfhandle (ListenSocket)); // -1 is invalid file handle: http://msdn.microsoft.com/en-us/library/ks2530z6.aspx
93
+ printf("err was %d\n", WSAGetLastError());
94
+ //----------------------
95
+ return ListenSocket;
96
+ }
97
+
98
+
99
+ int
100
+ main (void)
101
+ {
102
+ struct ev_loop *loopy = ev_default_loop(0);
103
+ int fd = get_server_fd();
104
+ int fd_real = _open_osfhandle(fd, NULL);
105
+ int conv = _get_osfhandle(fd_real);
106
+ printf("got server fd %d, loop %d, fd_real %d, that converted %d\n", fd, loopy, fd_real, conv);
107
+ // accept(fd, NULL, NULL);
108
+ // initialise an io watcher, then start it
109
+ // this one will watch for stdin to become readable
110
+ ev_io_init (&stdin_watcher, stdin_cb, /*STDIN_FILENO*/ conv, EV_READ);
111
+ ev_io_start (loopy, &stdin_watcher);
112
+
113
+ // initialise a timer watcher, then start it
114
+ // simple non-repeating 5.5 second timeout
115
+ //ev_timer_init (&timeout_watcher, timeout_cb, 15.5, 0.);
116
+ //ev_timer_start (loopy, &timeout_watcher);
117
+ printf("starting loop\n");
118
+ // now wait for events to arrive
119
+ ev_loop (loopy, 0);
120
+
121
+ // unloop was called, so exit
122
+ return 0;
123
+ }
@@ -7,19 +7,24 @@ export_default :Polyphony
7
7
  Polyphony = import('./polyphony/core')
8
8
  Exceptions = import('./polyphony/core/exceptions')
9
9
 
10
+ import('polyphony/extensions/socket')
11
+ import('polyphony/extensions/ssl')
12
+
10
13
  module Polyphony
11
14
  Cancel = Exceptions::Cancel
12
15
  MoveOn = Exceptions::MoveOn
13
16
 
17
+ Net = import('./polyphony/net')
18
+
14
19
  auto_import(
15
20
  Channel: './polyphony/core/channel',
16
- Coroutine: './polyphony/core/coroutine',
21
+ Coprocess: './polyphony/core/coprocess',
17
22
  Sync: './polyphony/core/sync',
18
23
  Thread: './polyphony/core/thread',
19
24
  ThreadPool: './polyphony/core/thread_pool',
20
25
 
21
26
  FS: './polyphony/fs',
22
- Net: './polyphony/net',
27
+ # Net: './polyphony/net',
23
28
  ResourcePool: './polyphony/resource_pool',
24
29
  Supervisor: './polyphony/supervisor'
25
30
  )
@@ -22,7 +22,7 @@ module Core
22
22
  pid = Kernel.fork do
23
23
  FiberPool.reset!
24
24
  EV.post_fork
25
- Fiber.current.coroutine = Coroutine.new(Fiber.current)
25
+ Fiber.current.coprocess = Coprocess.new(Fiber.current)
26
26
 
27
27
  block.()
28
28
 
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- export_default :Coroutine
3
+ export_default :Coprocess
4
4
 
5
5
  import('../extensions/kernel')
6
6
 
@@ -8,7 +8,7 @@ FiberPool = import('./fiber_pool')
8
8
  Exceptions = import('./exceptions')
9
9
 
10
10
  # Encapsulates an asynchronous task
11
- class Coroutine
11
+ class Coprocess
12
12
  attr_reader :result, :fiber
13
13
 
14
14
 
@@ -21,7 +21,7 @@ class Coroutine
21
21
  @caller = caller if Exceptions.debug
22
22
 
23
23
  @fiber = FiberPool.spawn do
24
- @fiber.coroutine = self
24
+ @fiber.coprocess = self
25
25
  @result = (@block || block2).call(self)
26
26
  rescue Exceptions::MoveOn, Exceptions::Stop => e
27
27
  @result = e.value
@@ -29,7 +29,7 @@ class Coroutine
29
29
  e.cleanup_backtrace(@caller) if Exceptions.debug
30
30
  @result = e
31
31
  ensure
32
- @fiber.coroutine = nil
32
+ @fiber.coprocess = nil
33
33
  @fiber = nil
34
34
  @awaiting_fiber&.schedule @result
35
35
  @when_done&.()
@@ -66,7 +66,7 @@ class Coroutine
66
66
  end
67
67
 
68
68
  # Kernel.await expects the given argument / block to be a callable, so #call
69
- # in fact waits for the coroutine to finish
69
+ # in fact waits for the coprocess to finish
70
70
  def await
71
71
  run unless @ran
72
72
  if @fiber
@@ -76,7 +76,7 @@ class Coroutine
76
76
  @result
77
77
  end
78
78
  ensure
79
- # if awaiting was interrupted and the coroutine is still running, we need to stop it
79
+ # if awaiting was interrupted and the coprocess is still running, we need to stop it
80
80
  if @fiber
81
81
  @fiber&.schedule(Exceptions::MoveOn.new)
82
82
  suspend
@@ -91,16 +91,16 @@ class Coroutine
91
91
  @fiber&.schedule(value)
92
92
  end
93
93
 
94
- def interrupt(value = Exceptions::MoveOn.new)
95
- @fiber&.schedule(value)
94
+ def interrupt(value = nil)
95
+ @fiber&.schedule(Exceptions::MoveOn.new(nil, value))
96
96
  end
97
97
  alias_method :stop, :interrupt
98
98
 
99
99
  def cancel!
100
- interrupt(Exceptions::Cancel.new)
100
+ @fiber&.schedule(Exceptions::Cancel.new)
101
101
  end
102
102
 
103
103
  def self.current
104
- Fiber.current.coroutine
104
+ Fiber.current.coprocess
105
105
  end
106
106
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- export :CoroutineInterrupt, :MoveOn, :Stop, :Cancel, :debug, :debug=
3
+ export :CoprocessInterrupt, :MoveOn, :Stop, :Cancel, :debug, :debug=
4
4
 
5
- class CoroutineInterrupt < ::Exception
5
+ class CoprocessInterrupt < ::Exception
6
6
  attr_reader :scope, :value
7
7
 
8
8
  def initialize(scope = nil, value = nil)
@@ -11,9 +11,9 @@ class CoroutineInterrupt < ::Exception
11
11
  end
12
12
  end
13
13
 
14
- class Stop < CoroutineInterrupt; end
15
- class MoveOn < CoroutineInterrupt; end
16
- class Cancel < CoroutineInterrupt; end
14
+ class Stop < CoprocessInterrupt; end
15
+ class MoveOn < CoprocessInterrupt; end
16
+ class Cancel < CoprocessInterrupt; end
17
17
 
18
18
  def debug
19
19
  @debug
@@ -2,12 +2,12 @@
2
2
 
3
3
  export_default :Supervisor
4
4
 
5
- Coroutine = import('./coroutine')
5
+ Coprocess = import('./coprocess')
6
6
  Exceptions = import('./exceptions')
7
7
 
8
8
  class Supervisor
9
9
  def initialize
10
- @coroutines = []
10
+ @coprocesss = []
11
11
  end
12
12
 
13
13
  def await(&block)
@@ -26,31 +26,31 @@ class Supervisor
26
26
  end
27
27
 
28
28
  def spawn(proc = nil, &block)
29
- if proc.is_a?(Coroutine)
30
- spawn_coroutine(proc)
29
+ if proc.is_a?(Coprocess)
30
+ spawn_coprocess(proc)
31
31
  else
32
32
  spawn_proc(block || proc)
33
33
  end
34
34
  end
35
35
 
36
- def spawn_coroutine(proc)
37
- @coroutines << proc
36
+ def spawn_coprocess(proc)
37
+ @coprocesss << proc
38
38
  proc.when_done { task_completed(proc) }
39
39
  proc.run unless proc.running?
40
40
  proc
41
41
  end
42
42
 
43
43
  def spawn_proc(proc)
44
- @coroutines << Object.spawn do |coroutine|
45
- proc.call(coroutine)
46
- task_completed(coroutine)
44
+ @coprocesss << Object.spawn do |coprocess|
45
+ proc.call(coprocess)
46
+ task_completed(coprocess)
47
47
  rescue Exception => e
48
- task_completed(coroutine)
48
+ task_completed(coprocess)
49
49
  end
50
50
  end
51
51
 
52
52
  def still_running?
53
- !@coroutines.empty?
53
+ !@coprocesss.empty?
54
54
  end
55
55
 
56
56
  def stop!(result = nil)
@@ -61,15 +61,15 @@ class Supervisor
61
61
 
62
62
  def stop_all_tasks
63
63
  exception = Exceptions::Stop.new
64
- @coroutines.each do |c|
64
+ @coprocesss.each do |c|
65
65
  EV.next_tick { c.interrupt(exception) }
66
66
  end
67
67
  end
68
68
 
69
- def task_completed(coroutine)
70
- return unless @coroutines.include?(coroutine)
69
+ def task_completed(coprocess)
70
+ return unless @coprocesss.include?(coprocess)
71
71
 
72
- @coroutines.delete(coroutine)
73
- @supervisor_fiber&.transfer if @coroutines.empty?
72
+ @coprocesss.delete(coprocess)
73
+ @supervisor_fiber&.transfer if @coprocesss.empty?
74
74
  end
75
75
  end
@@ -23,7 +23,7 @@ end
23
23
 
24
24
  def wait_for_thread(ctx)
25
25
  suspend
26
- rescue Exceptions::CoroutineInterrupt => e
26
+ rescue Exceptions::CoprocessInterrupt => e
27
27
  ctx[:fiber] = nil
28
28
  ctx[:thread]&.raise(e)
29
29
  raise e
@@ -14,49 +14,50 @@ class ::IO
14
14
  @write_watcher&.stop
15
15
  end
16
16
 
17
- NO_EXCEPTION = { exception: false }.freeze
17
+ # NO_EXCEPTION = { exception: false }.freeze
18
18
 
19
- def read(max = 8192, outbuf = nil)
20
- outbuf ||= (@read_buffer ||= +'')
21
- loop do
22
- result = read_nonblock(max, outbuf, NO_EXCEPTION)
23
- case result
24
- when nil then raise IOError
25
- when :wait_readable then read_watcher.await
26
- else return result
27
- end
28
- end
29
- ensure
30
- @read_watcher&.stop
31
- end
19
+ # def read(max = 8192, outbuf = nil)
20
+ # outbuf ||= (@read_buffer ||= +'')
21
+ # loop do
22
+ # result = read_nonblock(max, outbuf, NO_EXCEPTION)
23
+ # case result
24
+ # when nil then raise IOError
25
+ # when :wait_readable then read_watcher.await
26
+ # else return result
27
+ # end
28
+ # end
29
+ # ensure
30
+ # @read_watcher&.stop
31
+ # end
32
32
 
33
- def write(data)
34
- loop do
35
- result = write_nonblock(data, NO_EXCEPTION)
36
- case result
37
- when nil then raise IOError
38
- when :wait_writable then write_watcher.await
39
- else
40
- (result == data.bytesize) ? (return result) : (data = data[result..-1])
41
- end
42
- end
43
- ensure
44
- @write_watcher&.stop
45
- end
33
+ # def write(data)
34
+ # loop do
35
+ # result = write_nonblock(data, NO_EXCEPTION)
36
+ # case result
37
+ # when nil then raise IOError
38
+ # when :wait_writable then write_watcher.await
39
+ # else
40
+ # (result == data.bytesize) ? (return result) : (data = data[result..-1])
41
+ # end
42
+ # end
43
+ # ensure
44
+ # @write_watcher&.stop
45
+ # end
46
46
 
47
- def write_list(*list)
48
- list.each do |data|
49
- loop do
50
- result = write_nonblock(data, NO_EXCEPTION)
51
- case result
52
- when nil then raise IOError
53
- when :wait_writable then write_watcher.await
54
- else
55
- (result == data.bytesize) ? (break result) : (data = data[result..-1])
56
- end
57
- end
58
- end
59
- ensure
60
- @write_watcher&.stop
61
- end
47
+ # # write_list is inspired by
48
+ # def write_list(*list)
49
+ # list.each do |data|
50
+ # loop do
51
+ # result = write_nonblock(data, NO_EXCEPTION)
52
+ # case result
53
+ # when nil then raise IOError
54
+ # when :wait_writable then write_watcher.await
55
+ # else
56
+ # (result == data.bytesize) ? (break result) : (data = data[result..-1])
57
+ # end
58
+ # end
59
+ # end
60
+ # ensure
61
+ # @write_watcher&.stop
62
+ # end
62
63
  end
@@ -3,7 +3,7 @@
3
3
  require 'fiber'
4
4
 
5
5
  CancelScope = import('../core/cancel_scope')
6
- Coroutine = import('../core/coroutine')
6
+ Coprocess = import('../core/coprocess')
7
7
  Exceptions = import('../core/exceptions')
8
8
  Supervisor = import('../core/supervisor')
9
9
  Throttler = import('../core/throttler')
@@ -11,33 +11,18 @@ Throttler = import('../core/throttler')
11
11
  # Fiber extensions
12
12
  class ::Fiber
13
13
  attr_writer :cancelled
14
- attr_accessor :next_job, :coroutine
14
+ attr_accessor :next_job, :coprocess
15
15
 
16
16
  def cancelled?
17
17
  @cancelled
18
18
  end
19
19
 
20
- def root?
21
- @root
22
- end
23
-
24
20
  def schedule(value = nil)
25
21
  EV.schedule_fiber(self, value)
26
22
  end
27
23
 
28
- def set_root!
29
- @root = true
30
- end
31
-
32
- def self.root
33
- @@root
34
- end
35
-
36
- @@root = Fiber.current
37
- @@root.set_root!
38
-
39
- # Associate a (pseudo-)coroutine with the main fiber
40
- current.coroutine = Coroutine.new(Fiber.current)
24
+ # Associate a (pseudo-)coprocess with the main fiber
25
+ current.coprocess = Coprocess.new(current)
41
26
  end
42
27
 
43
28
  class ::Exception
@@ -60,7 +45,7 @@ module ::Kernel
60
45
  if sym
61
46
  async_decorate(is_a?(Class) ? self : singleton_class, sym)
62
47
  else
63
- Coroutine.new(&block)
48
+ Coprocess.new(&block)
64
49
  end
65
50
  end
66
51
 
@@ -72,9 +57,7 @@ module ::Kernel
72
57
  def async_decorate(receiver, sym)
73
58
  sync_sym = :"sync_#{sym}"
74
59
  receiver.alias_method(sync_sym, sym)
75
- receiver.define_method(sym) do |*args, &block|
76
- Coroutine.new { send(sync_sym, *args, &block) }
77
- end
60
+ receiver.class_eval("def #{sym}(*args, &block); Coprocess.new { send(#{sync_sym.inspect}, *args, &block) }; end")
78
61
  end
79
62
 
80
63
  def cancel_after(duration, &block)
@@ -113,7 +96,7 @@ module ::Kernel
113
96
  end
114
97
 
115
98
  def receive
116
- Fiber.current.coroutine.receive
99
+ Fiber.current.coprocess.receive
117
100
  end
118
101
 
119
102
  alias_method :sync_sleep, :sleep
@@ -125,10 +108,10 @@ module ::Kernel
125
108
  end
126
109
 
127
110
  def spawn(proc = nil, &block)
128
- if proc.is_a?(Coroutine)
111
+ if proc.is_a?(Coprocess)
129
112
  proc.run
130
113
  else
131
- Coroutine.new(&(block || proc)).run
114
+ Coprocess.new(&(block || proc)).run
132
115
  end
133
116
  end
134
117
 
@@ -136,13 +119,6 @@ module ::Kernel
136
119
  Supervisor.new.await(&block)
137
120
  end
138
121
 
139
- # @@reactor_fiber = Fiber.root
140
-
141
- # def suspend
142
- # result = @@reactor_fiber.transfer
143
- # result.is_a?(Exception) ? raise(result) : result
144
- # end
145
-
146
122
  def throttled_loop(rate, &block)
147
123
  throttler = Throttler.new(rate)
148
124
  loop do
@@ -155,7 +131,7 @@ module ::Kernel
155
131
  end
156
132
 
157
133
  def timeout(duration, opts = {}, &block)
158
- CancelScope.new(opts.merge(timeout: duration)).(&block)
134
+ CancelScope.new(**opts, timeout: duration).(&block)
159
135
  end
160
136
  end
161
137