polyphony 0.82 → 0.83

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ libs = $libs
4
+ if %w'z libz zlib1 zlib zdll zlibwapi'.find {|z| have_library(z, 'deflateReset')} and
5
+ have_header('zlib.h') then
6
+ have_zlib = true
7
+ else
8
+ $libs = libs
9
+ unless File.directory?(zsrc = "#{$srcdir}/zlib")
10
+ dirs = Dir.open($srcdir) {|z| z.grep(/\Azlib-\d+[.\d]*\z/) {|x|"#{$srcdir}/#{x}"}}
11
+ dirs.delete_if {|x| !File.directory?(x)}
12
+ zsrc = dirs.max_by {|x| x.scan(/\d+/).map(&:to_i)}
13
+ end
14
+ if zsrc
15
+ addconf = [
16
+ "ZSRC = $(srcdir)/#{File.basename(zsrc)}\n",
17
+ "all:\n",
18
+ ]
19
+ $INCFLAGS << " -I$(ZSRC)"
20
+ if $mswin or $mingw
21
+ dll = "zlib1.dll"
22
+ $extso << dll
23
+ $cleanfiles << "$(topdir)/#{dll}" << "$(ZIMPLIB)"
24
+ zmk = "\t$(MAKE) -f $(ZMKFILE) TOP=$(ZSRC)"
25
+ zopts = []
26
+ if $nmake
27
+ zmkfile = "$(ZSRC)/win32/Makefile.msc"
28
+ m = "#{zsrc}/win32/Makefile.msc"
29
+ # zopts << "USE_ASM=1"
30
+ zopts << "ARCH=#{RbConfig::CONFIG['target_cpu']}"
31
+ else
32
+ zmkfile = "$(ZSRC)/win32/Makefile.gcc"
33
+ m = "#{zsrc}/win32/Makefile.gcc"
34
+ zmk += " PREFIX="
35
+ zmk << CONFIG['CC'][/(.*-)gcc([^\/]*)\z/, 1]
36
+ zmk << " CC=$(CC)" if $2
37
+ end
38
+ m = File.read(m)
39
+ zimplib = m[/^IMPLIB[ \t]*=[ \t]*(\S+)/, 1]
40
+ ($LOCAL_LIBS << " ./" << zimplib).strip!
41
+ unless $nmake or /^TOP[ \t]/ =~ m
42
+ m.gsub!(/win32\/zlib\.def/, '$(TOP)/\&')
43
+ m.gsub!(/^(\t.*[ \t])(\S+\.rc)/, '\1-I$(<D) $<')
44
+ m = "TOP = .\n""VPATH=$(TOP)\n" + m
45
+ zmkfile = File.basename(zmkfile)
46
+ File.rename(zmkfile, zmkfile+".orig") if File.exist?(zmkfile)
47
+ File.write(zmkfile, m)
48
+ end
49
+ addconf.push(
50
+ "ZMKFILE = #{zmkfile}\n",
51
+ "ZIMPLIB = #{zimplib}\n",
52
+ "ZOPTS = #{zopts.join(' ')}\n",
53
+ "$(TARGET_SO): $(ZIMPLIB)\n",
54
+ "$(ZIMPLIB):\n",
55
+ "#{zmk} $(ZOPTS) $@\n",
56
+ "install-so static: $(topdir)/#{dll}",
57
+ "$(topdir)/#{dll}: $(ZIMPLIB)\n",
58
+ "\t$(Q) $(COPY) #{dll} $(@D)\n",
59
+ "clean: clean-zsrc\n",
60
+ "clean-zsrc:\n",
61
+ "#{zmk} clean\n",
62
+ )
63
+ end
64
+ Logging.message "using zlib in #{zsrc}\n"
65
+ $defs << "-DHAVE_ZLIB_H"
66
+ have_zlib = true
67
+ end
68
+ end
69
+
70
+ if have_zlib
71
+ defines = []
72
+
73
+ Logging::message 'checking for kind of operating system... '
74
+ os_code = with_config('os-code') ||
75
+ case RUBY_PLATFORM.split('-',2)[1]
76
+ when 'amigaos' then
77
+ os_code = 'AMIGA'
78
+ when /mswin|mingw|bccwin/ then
79
+ # NOTE: cygwin should be regarded as Unix.
80
+ os_code = 'WIN32'
81
+ else
82
+ os_code = 'UNIX'
83
+ end
84
+ os_code = 'OS_' + os_code.upcase
85
+
86
+ OS_NAMES = {
87
+ 'OS_MSDOS' => 'MS-DOS',
88
+ 'OS_AMIGA' => 'Amiga',
89
+ 'OS_VMS' => 'VMS',
90
+ 'OS_UNIX' => 'Unix',
91
+ 'OS_ATARI' => 'Atari',
92
+ 'OS_MACOS' => 'MacOS',
93
+ 'OS_TOPS20' => 'TOPS20',
94
+ 'OS_WIN32' => 'Win32',
95
+ 'OS_VMCMS' => 'VM/CMS',
96
+ 'OS_ZSYSTEM' => 'Z-System',
97
+ 'OS_CPM' => 'CP/M',
98
+ 'OS_QDOS' => 'QDOS',
99
+ 'OS_RISCOS' => 'RISCOS',
100
+ 'OS_UNKNOWN' => 'Unknown',
101
+ }
102
+ unless OS_NAMES.key? os_code then
103
+ raise "invalid OS_CODE `#{os_code}'"
104
+ end
105
+ Logging::message "#{OS_NAMES[os_code]}\n"
106
+ defines << "OS_CODE=#{os_code}"
107
+
108
+ $defs.concat(defines.collect{|d|' -D'+d})
109
+
110
+ if zsrc
111
+ $defs << "-DHAVE_CRC32_COMBINE"
112
+ $defs << "-DHAVE_ADLER32_COMBINE"
113
+ $defs << "-DHAVE_TYPE_Z_CRC_T"
114
+ else
115
+ have_func('crc32_combine', 'zlib.h')
116
+ have_func('adler32_combine', 'zlib.h')
117
+ have_type('z_crc_t', 'zlib.h')
118
+ end
119
+ end
@@ -73,6 +73,14 @@ class ::IO
73
73
 
74
74
  Open3.popen2(cmd) { |_i, o, _t| yield o }
75
75
  end
76
+
77
+ def splice(src, dest, maxlen)
78
+ Polyphony.backend_splice(src, dest, maxlen)
79
+ end
80
+
81
+ def splice_to_eof(src, dest, chunk_size = 8192)
82
+ Polyphony.backend_splice_to_eof(src, dest, chunk_size)
83
+ end
76
84
  end
77
85
  end
78
86
 
@@ -257,11 +265,11 @@ class ::IO
257
265
  end
258
266
  end
259
267
 
260
- def splice(src, maxlen)
268
+ def splice_from(src, maxlen)
261
269
  Polyphony.backend_splice(src, self, maxlen)
262
270
  end
263
271
 
264
- def splice_to_eof(src, chunksize = 8192)
272
+ def splice_to_eof_from(src, chunksize = 8192)
265
273
  Polyphony.backend_splice_to_eof(src, self, chunksize)
266
274
  end
267
275
  end
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Pipe instance methods
4
+ class Polyphony::Pipe
5
+ def __read_method__
6
+ :backend_read
7
+ end
8
+
9
+ def getbyte
10
+ char = getc
11
+ char ? char.getbyte(0) : nil
12
+ end
13
+
14
+ def getc
15
+ return @read_buffer.slice!(0) if @read_buffer && !@read_buffer.empty?
16
+
17
+ @read_buffer ||= +''
18
+ Polyphony.backend_read(self, @read_buffer, 8192, false, -1)
19
+ return @read_buffer.slice!(0) if !@read_buffer.empty?
20
+
21
+ nil
22
+ end
23
+
24
+ def read(len = nil, buf = nil, buf_pos = 0)
25
+ if buf
26
+ return Polyphony.backend_read(self, buf, len, true, buf_pos)
27
+ end
28
+
29
+ @read_buffer ||= +''
30
+ result = Polyphony.backend_read(self, @read_buffer, len, true, -1)
31
+ return nil unless result
32
+
33
+ already_read = @read_buffer
34
+ @read_buffer = +''
35
+ already_read
36
+ end
37
+
38
+ def readpartial(len, str = +'', buffer_pos = 0, raise_on_eof = true)
39
+ result = Polyphony.backend_read(self, str, len, false, buffer_pos)
40
+ raise EOFError if !result && raise_on_eof
41
+
42
+ result
43
+ end
44
+
45
+ def write(str, *args)
46
+ Polyphony.backend_write(self, str, *args)
47
+ end
48
+
49
+ def <<(str)
50
+ Polyphony.backend_write(self, str)
51
+ self
52
+ end
53
+
54
+ def gets(sep = $/, _limit = nil, _chomp: nil)
55
+ if sep.is_a?(Integer)
56
+ sep = $/
57
+ _limit = sep
58
+ end
59
+ sep_size = sep.bytesize
60
+
61
+ @read_buffer ||= +''
62
+
63
+ while true
64
+ idx = @read_buffer.index(sep)
65
+ return @read_buffer.slice!(0, idx + sep_size) if idx
66
+
67
+ result = readpartial(8192, @read_buffer, -1)
68
+ return nil unless result
69
+ end
70
+ rescue EOFError
71
+ return nil
72
+ end
73
+
74
+ # def print(*args)
75
+ # end
76
+
77
+ # def printf(format, *args)
78
+ # end
79
+
80
+ # def putc(obj)
81
+ # end
82
+
83
+ LINEFEED = "\n"
84
+ LINEFEED_RE = /\n$/.freeze
85
+
86
+ def puts(*args)
87
+ if args.empty?
88
+ write LINEFEED
89
+ return
90
+ end
91
+
92
+ idx = 0
93
+ while idx < args.size
94
+ arg = args[idx]
95
+ args[idx] = arg = arg.to_s unless arg.is_a?(String)
96
+ if arg =~ LINEFEED_RE
97
+ idx += 1
98
+ else
99
+ args.insert(idx + 1, LINEFEED)
100
+ idx += 2
101
+ end
102
+ end
103
+
104
+ write(*args)
105
+ nil
106
+ end
107
+
108
+ # def readbyte
109
+ # end
110
+
111
+ # def readchar
112
+ # end
113
+
114
+ # def readline(sep = $/, limit = nil, chomp: nil)
115
+ # end
116
+
117
+ # def readlines(sep = $/, limit = nil, chomp: nil)
118
+ # end
119
+
120
+ def write_nonblock(string, _options = {})
121
+ write(string)
122
+ end
123
+
124
+ def read_nonblock(maxlen, buf = nil, _options = nil)
125
+ buf ? readpartial(maxlen, buf) : readpartial(maxlen)
126
+ end
127
+
128
+ def read_loop(maxlen = 8192, &block)
129
+ Polyphony.backend_read_loop(self, maxlen, &block)
130
+ end
131
+
132
+ def feed_loop(receiver, method = :call, &block)
133
+ Polyphony.backend_feed_loop(self, receiver, method, &block)
134
+ end
135
+
136
+ def wait_readable(timeout = nil)
137
+ if timeout
138
+ move_on_after(timeout) do
139
+ Polyphony.backend_wait_io(self, false)
140
+ self
141
+ end
142
+ else
143
+ Polyphony.backend_wait_io(self, false)
144
+ self
145
+ end
146
+ end
147
+
148
+ def wait_writable(timeout = nil)
149
+ if timeout
150
+ move_on_after(timeout) do
151
+ Polyphony.backend_wait_io(self, true)
152
+ self
153
+ end
154
+ else
155
+ Polyphony.backend_wait_io(self, true)
156
+ self
157
+ end
158
+ end
159
+
160
+ def splice_from(src, maxlen)
161
+ Polyphony.backend_splice(src, self, maxlen)
162
+ end
163
+
164
+ def splice_to_eof_from(src, chunksize = 8192)
165
+ Polyphony.backend_splice_to_eof(src, self, chunksize)
166
+ end
167
+ end
@@ -3,6 +3,7 @@
3
3
  require_relative './extensions/exception'
4
4
  require_relative './extensions/fiber'
5
5
  require_relative './extensions/io'
6
+ require_relative './extensions/pipe'
6
7
  require_relative './extensions/object'
7
8
  require_relative './extensions/kernel'
8
9
  require_relative './extensions/process'
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.82'
4
+ VERSION = '0.83'
5
5
  end
data/lib/polyphony.rb CHANGED
@@ -18,6 +18,10 @@ require_relative './polyphony/adapters/process'
18
18
  # Polyphony API
19
19
  module Polyphony
20
20
  class << self
21
+ def pipe
22
+ Pipe.new
23
+ end
24
+
21
25
  def fork(&block)
22
26
  Kernel.fork do
23
27
  # A race condition can arise if a TERM or INT signal is received before
data/test/helper.rb CHANGED
@@ -37,6 +37,10 @@ module ::Kernel
37
37
  format("%p\n", args.size == 1 ? args.first : args)
38
38
  end
39
39
  end
40
+
41
+ def monotonic_clock
42
+ ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
43
+ end
40
44
  end
41
45
 
42
46
  class MiniTest::Test
data/test/test_backend.rb CHANGED
@@ -17,7 +17,7 @@ class BackendTest < MiniTest::Test
17
17
 
18
18
  def test_sleep
19
19
  count = 0
20
- t0 = Time.now
20
+ t0 = monotonic_clock
21
21
  spin {
22
22
  @backend.sleep 0.01
23
23
  count += 1
@@ -26,7 +26,7 @@ class BackendTest < MiniTest::Test
26
26
  @backend.sleep 0.01
27
27
  count += 1
28
28
  }.await
29
- assert_in_range 0.02..0.06, Time.now - t0 if IS_LINUX
29
+ assert_in_range 0.02..0.06, monotonic_clock - t0 if IS_LINUX
30
30
  assert_equal 3, count
31
31
  end
32
32
 
@@ -309,51 +309,6 @@ class BackendTest < MiniTest::Test
309
309
  assert_equal [1], buffer
310
310
  end
311
311
 
312
- def test_splice
313
- i1, o1 = IO.pipe
314
- i2, o2 = IO.pipe
315
- len = nil
316
-
317
- spin {
318
- len = o2.splice(i1, 1000)
319
- o2.close
320
- }
321
-
322
- o1.write('foobar')
323
- result = i2.read
324
-
325
- assert_equal 'foobar', result
326
- assert_equal 6, len
327
- end
328
-
329
- def test_splice_to_eof
330
- i1, o1 = IO.pipe
331
- i2, o2 = IO.pipe
332
- len = nil
333
-
334
- f = spin {
335
- len = o2.splice_to_eof(i1, 1000)
336
- o2.close
337
- }
338
-
339
- o1.write('foo')
340
- result = i2.readpartial(1000)
341
- assert_equal 'foo', result
342
-
343
- o1.write('bar')
344
- result = i2.readpartial(1000)
345
- assert_equal 'bar', result
346
- o1.close
347
- f.await
348
- assert_equal 6, len
349
- ensure
350
- if f.alive?
351
- f.interrupt
352
- f.await
353
- end
354
- end
355
-
356
-
357
312
  def test_splice_chunks
358
313
  body = 'abcd' * 4
359
314
  chunk_size = 12
@@ -512,7 +467,7 @@ class BackendChainTest < MiniTest::Test
512
467
  i, o = IO.pipe
513
468
  backend = Thread.current.backend
514
469
  while true
515
- len = o.splice(from, 8192)
470
+ len = o.splice_from(from, 8192)
516
471
  break if len == 0
517
472
 
518
473
  backend.chain(
@@ -103,38 +103,38 @@ end
103
103
 
104
104
  class MoveOnAfterTest < MiniTest::Test
105
105
  def test_move_on_after
106
- t0 = Time.now
106
+ t0 = monotonic_clock
107
107
  v = move_on_after(0.01) do
108
108
  sleep 1
109
109
  :foo
110
110
  end
111
- t1 = Time.now
111
+ t1 = monotonic_clock
112
112
 
113
113
  assert t1 - t0 < 0.1
114
114
  assert_nil v
115
115
  end
116
116
 
117
117
  def test_move_on_after_with_value
118
- t0 = Time.now
118
+ t0 = monotonic_clock
119
119
  v = move_on_after(0.01, with_value: :bar) do
120
120
  sleep 1
121
121
  :foo
122
122
  end
123
- t1 = Time.now
123
+ t1 = monotonic_clock
124
124
 
125
125
  assert t1 - t0 < 0.1
126
126
  assert_equal :bar, v
127
127
  end
128
128
 
129
129
  def test_move_on_after_with_reset
130
- t0 = Time.now
130
+ t0 = monotonic_clock
131
131
  v = move_on_after(0.01, with_value: :moved_on) do |timeout|
132
132
  sleep 0.007
133
133
  timeout.reset
134
134
  sleep 0.007
135
135
  nil
136
136
  end
137
- t1 = Time.now
137
+ t1 = monotonic_clock
138
138
 
139
139
  assert_nil v
140
140
  assert_in_range 0.014..0.02, t1 - t0 if IS_LINUX
@@ -143,23 +143,23 @@ class MoveOnAfterTest < MiniTest::Test
143
143
  def test_nested_move_on_after
144
144
  skip unless IS_LINUX
145
145
 
146
- t0 = Time.now
146
+ t0 = monotonic_clock
147
147
  o = move_on_after(0.01, with_value: 1) do
148
148
  move_on_after(0.02, with_value: 2) do
149
149
  sleep 1
150
150
  end
151
151
  end
152
- t1 = Time.now
152
+ t1 = monotonic_clock
153
153
  assert_equal 1, o
154
154
  assert_in_range 0.008..0.015, t1 - t0 if IS_LINUX
155
155
 
156
- t0 = Time.now
156
+ t0 = monotonic_clock
157
157
  o = move_on_after(0.05, with_value: 1) do
158
158
  move_on_after(0.01, with_value: 2) do
159
159
  sleep 1
160
160
  end
161
161
  end
162
- t1 = Time.now
162
+ t1 = monotonic_clock
163
163
  assert_equal 2, o
164
164
  assert_in_range 0.008..0.013, t1 - t0 if IS_LINUX
165
165
  end
@@ -167,7 +167,7 @@ end
167
167
 
168
168
  class CancelAfterTest < MiniTest::Test
169
169
  def test_cancel_after
170
- t0 = Time.now
170
+ t0 = monotonic_clock
171
171
 
172
172
  assert_raises Polyphony::Cancel do
173
173
  cancel_after(0.01) do
@@ -175,12 +175,12 @@ class CancelAfterTest < MiniTest::Test
175
175
  :foo
176
176
  end
177
177
  end
178
- t1 = Time.now
178
+ t1 = monotonic_clock
179
179
  assert t1 - t0 < 0.1
180
180
  end
181
181
 
182
182
  def test_cancel_after_with_reset
183
- t0 = Time.now
183
+ t0 = monotonic_clock
184
184
  cancel_after(0.01) do |f|
185
185
  assert_kind_of Fiber, f
186
186
  assert_equal Fiber.current, f.parent
@@ -188,7 +188,7 @@ class CancelAfterTest < MiniTest::Test
188
188
  f.reset
189
189
  sleep 0.007
190
190
  end
191
- t1 = Time.now
191
+ t1 = monotonic_clock
192
192
  assert_in_range 0.014..0.024, t1 - t0 if IS_LINUX
193
193
  end
194
194
 
@@ -270,7 +270,7 @@ class SpinLoopTest < MiniTest::Test
270
270
  def test_spin_loop_with_rate
271
271
  buffer = []
272
272
  counter = 0
273
- t0 = Time.now
273
+ t0 = monotonic_clock
274
274
  f = spin_loop(rate: 100) { buffer << (counter += 1) }
275
275
  sleep 0.02
276
276
  f.stop
@@ -280,7 +280,7 @@ class SpinLoopTest < MiniTest::Test
280
280
  def test_spin_loop_with_interval
281
281
  buffer = []
282
282
  counter = 0
283
- t0 = Time.now
283
+ t0 = monotonic_clock
284
284
  f = spin_loop(interval: 0.01) { buffer << (counter += 1) }
285
285
  sleep 0.02
286
286
  f.stop
@@ -361,7 +361,7 @@ class ThrottledLoopTest < MiniTest::Test
361
361
  def test_throttled_loop
362
362
  buffer = []
363
363
  counter = 0
364
- t0 = Time.now
364
+ t0 = monotonic_clock
365
365
  f = spin do
366
366
  throttled_loop(10) { buffer << (counter += 1) }
367
367
  end
@@ -372,12 +372,12 @@ class ThrottledLoopTest < MiniTest::Test
372
372
  def test_throttled_loop_with_count
373
373
  buffer = []
374
374
  counter = 0
375
- t0 = Time.now
375
+ t0 = monotonic_clock
376
376
  f = spin do
377
377
  throttled_loop(50, count: 5) { buffer << (counter += 1) }
378
378
  end
379
379
  f.await
380
- t1 = Time.now
380
+ t1 = monotonic_clock
381
381
  assert_in_range 0.075..0.15, t1 - t0 if IS_LINUX
382
382
  assert_equal [1, 2, 3, 4, 5], buffer
383
383
  end
@@ -395,7 +395,7 @@ class GlobalAPIEtcTest < MiniTest::Test
395
395
 
396
396
  def test_every
397
397
  buffer = []
398
- t0 = Time.now
398
+ t0 = monotonic_clock
399
399
  f = spin do
400
400
  every(0.01) { buffer << 1 }
401
401
  end
@@ -406,7 +406,7 @@ class GlobalAPIEtcTest < MiniTest::Test
406
406
 
407
407
  def test_every_with_slow_op
408
408
  buffer = []
409
- t0 = Time.now
409
+ t0 = monotonic_clock
410
410
  f = spin do
411
411
  every(0.01) { sleep 0.05; buffer << 1 }
412
412
  end
@@ -416,9 +416,9 @@ class GlobalAPIEtcTest < MiniTest::Test
416
416
  end
417
417
 
418
418
  def test_sleep
419
- t0 = Time.now
419
+ t0 = monotonic_clock
420
420
  sleep 0.1
421
- elapsed = Time.now - t0
421
+ elapsed = monotonic_clock - t0
422
422
  assert_in_range 0.05..0.15, elapsed if IS_LINUX
423
423
 
424
424
  f = spin { sleep }