polyphony 0.43.3 → 0.43.4

Sign up to get free protection for your applications and to get access to all the features.
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