polyphony 0.43.3 → 0.43.4

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: f48ef7d009af377b337388a1cca2eb4fe16b85deb1f37076fcd40e010aa9c0e3
4
- data.tar.gz: 7b4fa6e8951dc52fd3fdcc9b5a2f1974155e2b709d71de593657374de5020c88
3
+ metadata.gz: 9481b252526ebc3f8e0f5a0121eebb68492bc0c1502cfed447da7b0648e6095b
4
+ data.tar.gz: dfd2d5d0415833f14f9ebe2cc6336e87d0951ce86f07ebcdec0ad892f71fb74c
5
5
  SHA512:
6
- metadata.gz: 8de0f7526767acef9487417efb79c528312905adc4daed2664e8781ddfffa82118812407c2632269f8c6df0ba91733723804bad027e67cd5094aa1855241d8b4
7
- data.tar.gz: 94f5f80ec12f9fba315ce76495f7792125190a2e2004b455a79d58912cac523cd07f90f62218823126023a4003e4f08281676d899737f30d271d5c981f191d04
6
+ metadata.gz: 652633b1fc27623edb2e87b5657322ba4826ec176e8eb5131a43249e08340f793ba426743be343bfe0fce02fc60b73cb790afef816a4153585d68bdfeaa9c55d
7
+ data.tar.gz: 946abb7526324cae5f1d6b62e25c8410129b07ca75c82a6b7285d6269ed1911e161a6030a394ef29ba238a80da6f96787dd94fdbd5c05bd2a643379252ce80d0
@@ -1,3 +1,9 @@
1
+ ## 0.43.4 2020-07-09
2
+
3
+ * Reimplement Kernel#trap
4
+ * Dynamically allocate read buffer if length not given (#23)
5
+ * Prevent CPU saturation on infinite sleep (#24)
6
+
1
7
  ## 0.43.3 2020-07-08
2
8
 
3
9
  * Fix behaviour after call to `Process.daemon` (#8)
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- polyphony (0.43.3)
4
+ polyphony (0.43.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -279,7 +279,7 @@ def chat_user_handler(user_name, connection)
279
279
  while command = connection.gets
280
280
  case command
281
281
  when /^connect (.+)/
282
- room&.send [:unsubscribe, message_subscriber]
282
+ room&.send [:subscribe, message_subscriber]
283
283
  room = CHAT_ROOMS[$1]
284
284
  when "disconnect"
285
285
  room&.send [:unsubscribe, message_subscriber]
@@ -483,4 +483,4 @@ reach version 1.0. Here are some of the exciting directions we're working on.
483
483
  - Support for more core and stdlib APIs
484
484
  - More adapters for gems with C-extensions, such as `mysql`, `sqlite3` etc
485
485
  - Use `io_uring` agent as alternative to the libev agent
486
- - More concurrency constructs for building highly concurrent applications
486
+ - More concurrency constructs for building highly concurrent applications
@@ -4,47 +4,53 @@ def mem_usage
4
4
  `ps -o rss #{$$}`.split.last.to_i
5
5
  end
6
6
 
7
- def calculate_fiber_memory_cost(count)
7
+ def calculate_memory_cost(name, count, &block)
8
+ GC.enable
9
+ ObjectSpace.garbage_collect
10
+ sleep 0.5
8
11
  GC.disable
9
12
  rss0 = mem_usage
10
- count.times { Fiber.new { sleep 1 } }
13
+ count0 = ObjectSpace.count_objects[:TOTAL] - ObjectSpace.count_objects[:FREE]
14
+ a = []
15
+ count.times { a << block.call }
11
16
  rss1 = mem_usage
12
- GC.start
17
+ count1 = ObjectSpace.count_objects[:TOTAL] - ObjectSpace.count_objects[:FREE]
18
+ p [count0, count1]
19
+ # sleep 0.5
13
20
  cost = (rss1 - rss0).to_f / count
21
+ count_delta = (count1 - count0) / count
14
22
 
15
- puts "fiber memory cost: #{cost}KB"
23
+ puts "#{name} rss cost: #{cost}KB object count: #{count_delta}"
16
24
  end
17
25
 
18
- calculate_fiber_memory_cost(10000)
19
-
20
- def calculate_thread_memory_cost(count)
21
- GC.disable
22
- rss0 = mem_usage
23
- count.times { Thread.new { sleep 1 } }
24
- sleep 0.5
25
- rss1 = mem_usage
26
- sleep 0.5
27
- GC.start
28
- cost = (rss1 - rss0).to_f / count
26
+ f = Fiber.new { |f| f.transfer }
27
+ f.transfer Fiber.current
29
28
 
30
- puts "thread memory cost: #{cost}KB"
29
+ calculate_memory_cost('fiber', 10000) do
30
+ f = Fiber.new { |f| f.transfer :foo }
31
+ f.transfer Fiber.current
32
+ f
31
33
  end
32
34
 
33
- calculate_thread_memory_cost(500)
35
+ t = Thread.new { sleep 1}
36
+ t.kill
37
+ t.join
38
+
39
+ calculate_memory_cost('thread', 500) do
40
+ t = Thread.new { sleep 1 }
41
+ sleep 0.001
42
+ t
43
+ end
44
+ (Thread.list - [Thread.current]).each(&:kill).each(&:join)
34
45
 
35
46
  require 'bundler/setup'
36
47
  require 'polyphony'
37
48
 
38
- def calculate_extended_fiber_memory_cost(count)
39
- GC.disable
40
- rss0 = mem_usage
41
- count.times { spin { :foo } }
42
- snooze
43
- rss1 = mem_usage
44
- GC.start
45
- cost = (rss1 - rss0).to_f / count
49
+ f = spin { sleep 0.1 }
50
+ f.await
46
51
 
47
- puts "extended fiber memory cost: #{cost}KB"
52
+ calculate_memory_cost('polyphony fiber', 10000) do
53
+ f = spin { :foo }
54
+ f.await
55
+ f
48
56
  end
49
-
50
- calculate_extended_fiber_memory_cost(10000)
@@ -281,7 +281,8 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
281
281
  struct LibevAgent_t *agent;
282
282
  struct libev_io watcher;
283
283
  rb_io_t *fptr;
284
- long len = NUM2INT(length);
284
+ long dynamic_len = length == Qnil;
285
+ long len = dynamic_len ? 4096 : NUM2INT(length);
285
286
  int shrinkable = io_setstrbuf(&str, len);
286
287
  char *buf = RSTRING_PTR(str);
287
288
  long total = 0;
@@ -298,8 +299,8 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
298
299
 
299
300
  OBJ_TAINT(str);
300
301
 
301
- while (len > 0) {
302
- ssize_t n = read(fptr->fd, buf, len);
302
+ while (1) {
303
+ ssize_t n = read(fptr->fd, buf, len - total);
303
304
  if (n < 0) {
304
305
  int e = errno;
305
306
  if (e != EWOULDBLOCK && e != EAGAIN) rb_syserr_fail(e, strerror(e));
@@ -312,14 +313,21 @@ VALUE LibevAgent_read(VALUE self, VALUE io, VALUE str, VALUE length, VALUE to_eo
312
313
  if (TEST_EXCEPTION(switchpoint_result)) goto error;
313
314
 
314
315
  if (n == 0) break; // EOF
315
-
316
316
  total = total + n;
317
- buf += n;
318
- len -= n;
319
- if (!read_to_eof || (len == 0)) break;
317
+ if (!read_to_eof) break;
318
+
319
+ if (total == len) {
320
+ if (!dynamic_len) break;
321
+
322
+ rb_str_resize(str, total);
323
+ rb_str_modify_expand(str, len);
324
+ buf = RSTRING_PTR(str) + total;
325
+ shrinkable = 0;
326
+ len += len;
327
+ }
328
+ else buf += n;
320
329
  }
321
330
  }
322
-
323
331
  if (total == 0) return Qnil;
324
332
 
325
333
  io_set_read_length(str, total, shrinkable);
@@ -100,17 +100,9 @@ module Polyphony
100
100
  Polyphony::Process.watch(cmd, &block)
101
101
  end
102
102
 
103
- def emit_signal_exception(exception, fiber = Thread.main.main_fiber)
104
- Thread.current.break_out_of_ev_loop(fiber, exception)
105
- end
106
-
107
- def install_terminating_signal_handler(signal, exception_class)
108
- trap(signal) { emit_signal_exception(exception_class.new) }
109
- end
110
-
111
103
  def install_terminating_signal_handlers
112
- install_terminating_signal_handler('SIGTERM', ::SystemExit)
113
- install_terminating_signal_handler('SIGINT', ::Interrupt)
104
+ trap('SIGTERM', SystemExit)
105
+ trap('SIGINT', Interrupt)
114
106
  end
115
107
 
116
108
  def terminate_threads
@@ -103,7 +103,7 @@ module Polyphony
103
103
 
104
104
  def sleep_forever
105
105
  Thread.current.agent.ref
106
- suspend
106
+ loop { sleep 60 }
107
107
  ensure
108
108
  Thread.current.agent.unref
109
109
  end
@@ -126,6 +126,31 @@ module ::Kernel
126
126
  break
127
127
  end
128
128
  end
129
+
130
+ alias_method :orig_trap, :trap
131
+ def trap(sig, command = nil, &block)
132
+ return orig_trap(sig, command) if command.is_a? String
133
+
134
+ block = command if command.respond_to?(:call) && !block
135
+ exception = command.is_a?(Class) && command.new
136
+
137
+ # The signal trap can be invoked at any time, including while the system
138
+ # agent is blocking while polling for events. In order to deal with this
139
+ # correctly, we spin a fiber that will run the signal handler code, then
140
+ # call break_out_of_ev_loop, which will put the fiber at the front of the
141
+ # run queue, then wake up the system agent.
142
+ #
143
+ # If the command argument is an exception class however, it will be raised
144
+ # directly in the context of the main fiber.
145
+ orig_trap(sig) do
146
+ if exception
147
+ Thread.current.break_out_of_ev_loop(Thread.main.main_fiber, exception)
148
+ else
149
+ fiber = spin { snooze; block.call }
150
+ Thread.current.break_out_of_ev_loop(fiber, nil)
151
+ end
152
+ end
153
+ end
129
154
  end
130
155
 
131
156
  # Override Timeout to use cancel scope
@@ -97,7 +97,7 @@ class ::IO
97
97
  # end
98
98
 
99
99
  alias_method :orig_read, :read
100
- def read(len = 1 << 30)
100
+ def read(len = nil)
101
101
  @read_buffer ||= +''
102
102
  result = Thread.current.agent.read(self, @read_buffer, len, true)
103
103
  return nil unless result
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.43.3'
4
+ VERSION = '0.43.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polyphony
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.43.3
4
+ version: 0.43.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-08 00:00:00.000000000 Z
11
+ date: 2020-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty