polyphony 0.73.1 → 0.74

Sign up to get free protection for your applications and to get access to all the features.
@@ -17,6 +17,7 @@ const char *op_type_to_str(enum op_type type) {
17
17
  case OP_ACCEPT: return "ACCEPT";
18
18
  case OP_CONNECT: return "CONNECT";
19
19
  case OP_CHAIN: return "CHAIN";
20
+ case OP_CLOSE: return "CLOSE";
20
21
  default: return "";
21
22
  };
22
23
  }
@@ -15,7 +15,8 @@ enum op_type {
15
15
  OP_POLL,
16
16
  OP_ACCEPT,
17
17
  OP_CONNECT,
18
- OP_CHAIN
18
+ OP_CHAIN,
19
+ OP_CLOSE
19
20
  };
20
21
 
21
22
  typedef struct op_context {
@@ -697,10 +697,13 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
697
697
  Backend_t *backend;
698
698
  struct libev_io watcher;
699
699
  rb_io_t *fptr;
700
- struct sockaddr_in addr;
701
- char *host_buf = StringValueCStr(host);
700
+ struct sockaddr *ai_addr;
701
+ int ai_addrlen;
702
702
  VALUE switchpoint_result = Qnil;
703
703
  VALUE underlying_sock = rb_ivar_get(sock, ID_ivar_io);
704
+
705
+ ai_addrlen = backend_getaddrinfo(host, port, &ai_addr);
706
+
704
707
  if (underlying_sock != Qnil) sock = underlying_sock;
705
708
 
706
709
  GetBackend(self, backend);
@@ -708,12 +711,8 @@ VALUE Backend_connect(VALUE self, VALUE sock, VALUE host, VALUE port) {
708
711
  io_verify_blocking_mode(fptr, sock, Qfalse);
709
712
  watcher.fiber = Qnil;
710
713
 
711
- addr.sin_family = AF_INET;
712
- addr.sin_addr.s_addr = inet_addr(host_buf);
713
- addr.sin_port = htons(NUM2INT(port));
714
-
715
714
  backend->base.op_count++;
716
- int result = connect(fptr->fd, (struct sockaddr *)&addr, sizeof(addr));
715
+ int result = connect(fptr->fd, ai_addr, ai_addrlen);
717
716
  if (result < 0) {
718
717
  int e = errno;
719
718
  if (e != EINPROGRESS) rb_syserr_fail(e, strerror(e));
@@ -1156,7 +1155,6 @@ noreturn VALUE Backend_timer_loop(VALUE self, VALUE interval) {
1156
1155
  while (1) {
1157
1156
  uint64_t now_ns = current_time_ns();
1158
1157
  if (next_time_ns == 0) next_time_ns = now_ns + interval_ns;
1159
- double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
1160
1158
 
1161
1159
  if (next_time_ns > now_ns) {
1162
1160
  double sleep_duration = ((double)(next_time_ns - now_ns))/1e9;
@@ -1370,7 +1368,7 @@ inline VALUE Backend_run_idle_tasks(VALUE self) {
1370
1368
  return self;
1371
1369
  }
1372
1370
 
1373
- inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct libev_rw_io *watcher, VALUE *result) {
1371
+ static inline int splice_chunks_write(Backend_t *backend, int fd, VALUE str, struct libev_rw_io *watcher, VALUE *result) {
1374
1372
  char *buf = RSTRING_PTR(str);
1375
1373
  int len = RSTRING_LEN(str);
1376
1374
  int left = len;
@@ -59,14 +59,17 @@ VALUE Event_signal(int argc, VALUE *argv, VALUE self) {
59
59
 
60
60
  VALUE Event_await(VALUE self) {
61
61
  Event_t *event;
62
+ VALUE switchpoint_result;
63
+ VALUE backend;
64
+
62
65
  GetEvent(self, event);
63
66
 
64
67
  if (event->waiting_fiber != Qnil)
65
68
  rb_raise(rb_eRuntimeError, "Event is already awaited by another fiber");
66
69
 
67
- VALUE backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
70
+ backend = rb_ivar_get(rb_thread_current(), ID_ivar_backend);
68
71
  event->waiting_fiber = rb_fiber_current();
69
- VALUE switchpoint_result = Backend_wait_event(backend, Qnil);
72
+ switchpoint_result = Backend_wait_event(backend, Qnil);
70
73
  event->waiting_fiber = Qnil;
71
74
 
72
75
  RAISE_IF_EXCEPTION(switchpoint_result);
@@ -9,16 +9,18 @@ ID ID_clear;
9
9
  ID ID_each;
10
10
  ID ID_inspect;
11
11
  ID ID_invoke;
12
- ID ID_new;
13
12
  ID ID_ivar_blocking_mode;
14
13
  ID ID_ivar_io;
15
14
  ID ID_ivar_parked;
16
15
  ID ID_ivar_runnable;
17
16
  ID ID_ivar_running;
18
17
  ID ID_ivar_thread;
18
+ ID ID_new;
19
+ ID ID_raise;
19
20
  ID ID_size;
20
21
  ID ID_signal;
21
22
  ID ID_switch_fiber;
23
+ ID ID_to_s;
22
24
  ID ID_transfer;
23
25
  ID ID_R;
24
26
  ID ID_W;
@@ -123,6 +125,10 @@ VALUE Polyphony_backend_write(int argc, VALUE *argv, VALUE self) {
123
125
  return Backend_write_m(argc, argv, BACKEND());
124
126
  }
125
127
 
128
+ VALUE Polyphony_backend_close(VALUE self, VALUE io) {
129
+ return Backend_close(BACKEND(), io);
130
+ }
131
+
126
132
  void Init_Polyphony() {
127
133
  mPolyphony = rb_define_module("Polyphony");
128
134
 
@@ -147,6 +153,7 @@ void Init_Polyphony() {
147
153
  rb_define_singleton_method(mPolyphony, "backend_wait_io", Polyphony_backend_wait_io, 2);
148
154
  rb_define_singleton_method(mPolyphony, "backend_waitpid", Polyphony_backend_waitpid, 1);
149
155
  rb_define_singleton_method(mPolyphony, "backend_write", Polyphony_backend_write, -1);
156
+ rb_define_singleton_method(mPolyphony, "backend_close", Polyphony_backend_close, 1);
150
157
 
151
158
  rb_define_global_function("snooze", Polyphony_snooze, 0);
152
159
  rb_define_global_function("suspend", Polyphony_suspend, 0);
@@ -166,8 +173,10 @@ void Init_Polyphony() {
166
173
  ID_ivar_running = rb_intern("@running");
167
174
  ID_ivar_thread = rb_intern("@thread");
168
175
  ID_new = rb_intern("new");
176
+ ID_raise = rb_intern("raise");
169
177
  ID_signal = rb_intern("signal");
170
178
  ID_size = rb_intern("size");
171
179
  ID_switch_fiber = rb_intern("switch_fiber");
180
+ ID_to_s = rb_intern("to_s");
172
181
  ID_transfer = rb_intern("transfer");
173
182
  }
@@ -57,6 +57,7 @@ extern ID ID_raise;
57
57
  extern ID ID_signal;
58
58
  extern ID ID_size;
59
59
  extern ID ID_switch_fiber;
60
+ extern ID ID_to_s;
60
61
  extern ID ID_transfer;
61
62
 
62
63
  extern VALUE SYM_fiber_create;
@@ -112,6 +113,7 @@ VALUE Backend_wait_event(VALUE self, VALUE raise);
112
113
  VALUE Backend_wait_io(VALUE self, VALUE io, VALUE write);
113
114
  VALUE Backend_waitpid(VALUE self, VALUE pid);
114
115
  VALUE Backend_write_m(int argc, VALUE *argv, VALUE self);
116
+ VALUE Backend_close(VALUE self, VALUE io);
115
117
 
116
118
  VALUE Backend_poll(VALUE self, VALUE blocking);
117
119
  VALUE Backend_wait_event(VALUE self, VALUE raise_on_exception);
@@ -121,24 +121,27 @@ VALUE Queue_unshift(VALUE self, VALUE value) {
121
121
 
122
122
  VALUE Queue_shift(VALUE self) {
123
123
  Queue_t *queue;
124
- GetQueue(self, queue);
125
-
126
124
  VALUE fiber = rb_fiber_current();
127
125
  VALUE thread = rb_thread_current();
128
126
  VALUE backend = rb_ivar_get(thread, ID_ivar_backend);
127
+ VALUE value;
128
+
129
+ GetQueue(self, queue);
129
130
 
130
131
  while (1) {
132
+ VALUE switchpoint_result;
133
+
131
134
  if (queue->values.count) Fiber_make_runnable(fiber, Qnil);
132
135
 
133
136
  ring_buffer_push(&queue->shift_queue, fiber);
134
- VALUE switchpoint_result = Backend_wait_event(backend, Qnil);
137
+ switchpoint_result = Backend_wait_event(backend, Qnil);
135
138
  ring_buffer_delete(&queue->shift_queue, fiber);
136
139
 
137
140
  RAISE_IF_EXCEPTION(switchpoint_result);
138
141
  RB_GC_GUARD(switchpoint_result);
139
142
  if (queue->values.count) break;
140
143
  }
141
- VALUE value = ring_buffer_shift(&queue->values);
144
+ value = ring_buffer_shift(&queue->values);
142
145
  if ((queue->capacity) && (queue->capacity > queue->values.count))
143
146
  queue_schedule_first_blocked_fiber(&queue->push_queue);
144
147
  RB_GC_GUARD(value);
@@ -206,9 +209,11 @@ VALUE Queue_shift_each(VALUE self) {
206
209
 
207
210
  VALUE Queue_shift_all(VALUE self) {
208
211
  Queue_t *queue;
212
+ VALUE result;
213
+
209
214
  GetQueue(self, queue);
210
215
 
211
- VALUE result = ring_buffer_shift_all(&queue->values);
216
+ result = ring_buffer_shift_all(&queue->values);
212
217
  if (queue->capacity) queue_schedule_blocked_fibers_to_capacity(queue);
213
218
  return result;
214
219
  }
@@ -24,9 +24,11 @@ inline void runqueue_ring_buffer_clear(runqueue_ring_buffer *buffer) {
24
24
  static runqueue_entry nil_runqueue_entry = {(Qnil), (Qnil)};
25
25
 
26
26
  inline runqueue_entry runqueue_ring_buffer_shift(runqueue_ring_buffer *buffer) {
27
+ runqueue_entry value;
28
+
27
29
  if (buffer->count == 0) return nil_runqueue_entry;
28
30
 
29
- runqueue_entry value = buffer->entries[buffer->head];
31
+ value = buffer->entries[buffer->head];
30
32
  buffer->head = (buffer->head + 1) % buffer->size;
31
33
  buffer->count--;
32
34
  return value;
@@ -17,10 +17,13 @@ VALUE Socket_double_chevron(VALUE self, VALUE msg) {
17
17
  }
18
18
 
19
19
  void Init_SocketExtensions() {
20
+ VALUE cSocket;
21
+ VALUE cTCPSocket;
22
+
20
23
  rb_require("socket");
21
24
 
22
- VALUE cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
23
- VALUE cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
25
+ cSocket = rb_const_get(rb_cObject, rb_intern("Socket"));
26
+ cTCPSocket = rb_const_get(rb_cObject, rb_intern("TCPSocket"));
24
27
 
25
28
  rb_define_method(cSocket, "send", Socket_send, 2);
26
29
  rb_define_method(cTCPSocket, "send", Socket_send, 2);
@@ -5,17 +5,40 @@ require_relative '../core/exceptions'
5
5
  module Polyphony
6
6
  # Fiber control API
7
7
  module FiberControl
8
+ # Returns the fiber's monitoring mailbox queue, used for receiving fiber
9
+ # monitoring messages.
10
+ #
11
+ # @return [Polyphony::Queue] Monitoring mailbox queue
8
12
  def monitor_mailbox
9
13
  @monitor_mailbox ||= Polyphony::Queue.new
10
14
  end
11
15
 
16
+ # call-seq:
17
+ # fiber.stop(value = nil) -> fiber
18
+ # Fiber.interrupt(value = nil) -> fiber
19
+ #
20
+ # Stops the fiber by raising a Polyphony::MoveOn exception. The given value
21
+ # will become the fiber's return value.
22
+ #
23
+ # @param value [any] Fiber's eventual return value
24
+ # @return [Fiber] fiber
12
25
  def interrupt(value = nil)
13
26
  return if @running == false
14
27
 
15
28
  schedule Polyphony::MoveOn.new(value)
29
+ self
16
30
  end
17
31
  alias_method :stop, :interrupt
18
32
 
33
+ # call-seq:
34
+ # fiber.reset(value = nil) -> fiber
35
+ # fiber.restart(value = nil) -> fiber
36
+ #
37
+ # Restarts the fiber, with the given value serving as the first value passed
38
+ # to the fiber's block.
39
+ #
40
+ # @param value [any] value passed to fiber block
41
+ # @return [Fiber] restarted fiber
19
42
  def restart(value = nil)
20
43
  raise "Can't restart main fiber" if @main
21
44
 
@@ -31,32 +54,58 @@ module Polyphony
31
54
  end
32
55
  alias_method :reset, :restart
33
56
 
57
+ # Stops a fiber by raising a Polyphony::Cancel exception.
58
+ #
59
+ # @return [Fiber] fiber
34
60
  def cancel
35
61
  return if @running == false
36
62
 
37
63
  schedule Polyphony::Cancel.new
64
+ self
38
65
  end
39
66
 
67
+ # Sets the graceful shutdown flag for the fiber.
68
+ #
69
+ # @param graceful [bool] Whether or not to perform a graceful shutdown
40
70
  def graceful_shutdown=(graceful)
41
71
  @graceful_shutdown = graceful
42
72
  end
43
73
 
74
+ # Returns the graceful shutdown flag for the fiber.
75
+ #
76
+ # @return [bool]
44
77
  def graceful_shutdown?
45
78
  @graceful_shutdown
46
79
  end
47
80
 
81
+ # Terminates the fiber, optionally setting the graceful shutdown flag.
82
+ #
83
+ # @param graceful [bool] Whether to perform a graceful shutdown
84
+ # @return [Fiber]
48
85
  def terminate(graceful = false)
49
86
  return if @running == false
50
87
 
51
88
  @graceful_shutdown = graceful
52
89
  schedule Polyphony::Terminate.new
90
+ self
53
91
  end
54
92
 
93
+ # call-seq:
94
+ # fiber.raise(message) -> fiber
95
+ # fiber.raise(exception_class) -> fiber
96
+ # fiber.raise(exception_class, exception_message) -> fiber
97
+ # fiber.raise(exception) -> fiber
98
+ #
99
+ # Raises an exception in the context of the fiber.
100
+ #
101
+ # @return [Fiber]
55
102
  def raise(*args)
56
103
  error = error_from_raise_args(args)
57
104
  schedule(error)
105
+ self
58
106
  end
59
107
 
108
+ # :no-doc:
60
109
  def error_from_raise_args(args)
61
110
  case (arg = args.shift)
62
111
  when String then RuntimeError.new(arg)
@@ -125,6 +174,9 @@ module Polyphony
125
174
  # return values for all terminated fibers. If any of the awaited fibers
126
175
  # terminates with an uncaught exception, `Fiber.await` will await all the
127
176
  # other fibers to terminate, then reraise the exception.
177
+ #
178
+ # @param *fibers [Array<Fiber>] fibers to wait for
179
+ # @return [Array<any>] return values of given fibers
128
180
  def await(*fibers)
129
181
  return [] if fibers.empty?
130
182
 
@@ -158,6 +210,12 @@ module Polyphony
158
210
  end
159
211
  alias_method :join, :await
160
212
 
213
+ # Waits for at least one of the given fibers to terminate, returning an
214
+ # array containing the first terminated fiber and its return value. If an
215
+ # exception occurs in one of the given fibers, it will be reraised.
216
+ #
217
+ # @param *fibers [Array<Fiber>] Fibers to wait for
218
+ # @return [Array] Array containing the first terminated fiber and its return value
161
219
  def select(*fibers)
162
220
  return nil if fibers.empty?
163
221
 
@@ -31,7 +31,7 @@ class ::Socket
31
31
  alias_method :orig_read, :read
32
32
  def read(maxlen = nil, buf = nil, buf_pos = 0)
33
33
  return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
34
- return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
34
+ return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
35
35
 
36
36
  buf = +''
37
37
  len = buf.bytesize
@@ -120,8 +120,16 @@ class ::TCPSocket
120
120
 
121
121
  attr_reader :io
122
122
 
123
+ def self.open(*args)
124
+ new(*args)
125
+ end
126
+
127
+ def address_family(host)
128
+ host =~ /\:\:/ ? Socket::AF_INET6 : Socket::AF_INET
129
+ end
130
+
123
131
  def initialize(remote_host, remote_port, local_host = nil, local_port = nil)
124
- @io = Socket.new Socket::AF_INET, Socket::SOCK_STREAM
132
+ @io = Socket.new address_family(remote_host), Socket::SOCK_STREAM
125
133
  if local_host && local_port
126
134
  addr = Addrinfo.tcp(local_host, local_port)
127
135
  @io.bind(addr)
@@ -167,7 +175,7 @@ class ::TCPSocket
167
175
  alias_method :orig_read, :read
168
176
  def read(maxlen = nil, buf = nil, buf_pos = 0)
169
177
  return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
170
- return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
178
+ return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
171
179
 
172
180
  buf = +''
173
181
  len = buf.bytesize
@@ -223,8 +231,12 @@ end
223
231
 
224
232
  # Override stock TCPServer code by encapsulating a Socket instance.
225
233
  class ::TCPServer
234
+ def address_family(host)
235
+ host =~ /\:\:/ ? Socket::AF_INET6 : Socket::AF_INET
236
+ end
237
+
226
238
  def initialize(hostname = nil, port = 0)
227
- @io = Socket.new Socket::AF_INET, Socket::SOCK_STREAM
239
+ @io = Socket.new address_family(hostname), Socket::SOCK_STREAM
228
240
  @io.bind(Addrinfo.tcp(hostname, port))
229
241
  @io.listen(0)
230
242
  end
@@ -259,7 +271,7 @@ class ::UNIXSocket
259
271
  alias_method :orig_read, :read
260
272
  def read(maxlen = nil, buf = nil, buf_pos = 0)
261
273
  return Polyphony.backend_recv(self, buf, maxlen, buf_pos) if buf
262
- return Polyphony.backend_recv(self, buf || +'', maxlen, 0) if maxlen
274
+ return Polyphony.backend_recv(self, +'', maxlen, 0) if maxlen
263
275
 
264
276
  buf = +''
265
277
  len = buf.bytesize
@@ -18,14 +18,20 @@ class ::Thread
18
18
  def execute
19
19
  # backend must be created in the context of the new thread, therefore it
20
20
  # cannot be created in Thread#initialize
21
- @backend = Polyphony::Backend.new
21
+ raise_error = false
22
+ begin
23
+ @backend = Polyphony::Backend.new
24
+ rescue Exception => e
25
+ raise_error = true
26
+ raise e
27
+ end
22
28
  setup
23
29
  @ready = true
24
30
  result = @block.(*@args)
25
31
  rescue Polyphony::MoveOn, Polyphony::Terminate => e
26
32
  result = e.value
27
33
  rescue Exception => e
28
- result = e
34
+ raise_error ? (raise e) : (result = e)
29
35
  ensure
30
36
  @ready = true
31
37
  finalize(result)
@@ -48,7 +54,7 @@ class ::Thread
48
54
  @result = result
49
55
  signal_waiters(result)
50
56
  end
51
- @backend.finalize
57
+ @backend&.finalize
52
58
  end
53
59
 
54
60
  def signal_waiters(result)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polyphony
4
- VERSION = '0.73.1'
4
+ VERSION = '0.74'
5
5
  end
data/lib/polyphony.rb CHANGED
@@ -2,11 +2,12 @@
2
2
 
3
3
  require 'fiber'
4
4
  require_relative './polyphony_ext'
5
- require_relative './polyphony/extensions'
5
+ require_relative './polyphony/extensions/thread'
6
6
 
7
7
  Thread.current.setup_fiber_scheduling
8
8
  Thread.current.backend = Polyphony::Backend.new
9
9
 
10
+ require_relative './polyphony/extensions'
10
11
  require_relative './polyphony/core/exceptions'
11
12
  require_relative './polyphony/core/global_api'
12
13
  require_relative './polyphony/core/resource_pool'
data/test/test_backend.rb CHANGED
@@ -243,16 +243,14 @@ class BackendTest < MiniTest::Test
243
243
  end
244
244
 
245
245
  def test_timer_loop
246
- skip unless IS_LINUX
247
-
248
- i = 0
246
+ counter = 0
249
247
  f = spin do
250
- @backend.timer_loop(0.01) { i += 1 }
248
+ @backend.timer_loop(0.01) { counter += 1 }
251
249
  end
252
250
  @backend.sleep(0.05)
253
251
  f.stop
254
252
  f.await # TODO: check why this test sometimes segfaults if we don't a<wait fiber
255
- assert_in_range 4..6, i
253
+ assert_in_range 4..6, counter if IS_LINUX
256
254
  end
257
255
 
258
256
  class MyTimeoutException < Exception
@@ -162,7 +162,7 @@ class MoveOnAfterTest < MiniTest::Test
162
162
  end
163
163
  t1 = Time.now
164
164
  assert_equal 1, o
165
- assert_in_range 0.008..0.015, t1 - t0
165
+ assert_in_range 0.008..0.015, t1 - t0 if IS_LINUX
166
166
 
167
167
  t0 = Time.now
168
168
  o = move_on_after(0.05, with_value: 1) do
@@ -172,7 +172,7 @@ class MoveOnAfterTest < MiniTest::Test
172
172
  end
173
173
  t1 = Time.now
174
174
  assert_equal 2, o
175
- assert_in_range 0.008..0.013, t1 - t0
175
+ assert_in_range 0.008..0.013, t1 - t0 if IS_LINUX
176
176
  end
177
177
  end
178
178
 
@@ -297,7 +297,7 @@ class SpinLoopTest < MiniTest::Test
297
297
  f = spin_loop(rate: 100) { buffer << (counter += 1) }
298
298
  sleep 0.02
299
299
  f.stop
300
- assert_in_range 1..3, counter
300
+ assert_in_range 1..3, counter if IS_LINUX
301
301
  end
302
302
 
303
303
  def test_spin_loop_with_interval
@@ -307,7 +307,7 @@ class SpinLoopTest < MiniTest::Test
307
307
  f = spin_loop(interval: 0.01) { buffer << (counter += 1) }
308
308
  sleep 0.02
309
309
  f.stop
310
- assert_in_range 1..3, counter
310
+ assert_in_range 1..3, counter if IS_LINUX
311
311
  end
312
312
 
313
313
  def test_spin_loop_break
@@ -386,10 +386,10 @@ class ThrottledLoopTest < MiniTest::Test
386
386
  counter = 0
387
387
  t0 = Time.now
388
388
  f = spin do
389
- throttled_loop(100) { buffer << (counter += 1) }
389
+ throttled_loop(10) { buffer << (counter += 1) }
390
390
  end
391
- sleep 0.03
392
- assert_in_range 2..4, counter
391
+ sleep 0.3
392
+ assert_in_range 2..4, counter if IS_LINUX
393
393
  end
394
394
 
395
395
  def test_throttled_loop_with_count
@@ -417,8 +417,6 @@ class GlobalAPIEtcTest < MiniTest::Test
417
417
  end
418
418
 
419
419
  def test_every
420
- skip unless IS_LINUX
421
-
422
420
  buffer = []
423
421
  t0 = Time.now
424
422
  f = spin do
@@ -426,12 +424,10 @@ class GlobalAPIEtcTest < MiniTest::Test
426
424
  end
427
425
  sleep 0.05
428
426
  f.stop
429
- assert_in_range 4..6, buffer.size
427
+ assert_in_range 4..6, buffer.size if IS_LINUX
430
428
  end
431
429
 
432
430
  def test_every_with_slow_op
433
- skip unless IS_LINUX
434
-
435
431
  buffer = []
436
432
  t0 = Time.now
437
433
  f = spin do
@@ -439,14 +435,14 @@ class GlobalAPIEtcTest < MiniTest::Test
439
435
  end
440
436
  sleep 0.15
441
437
  f.stop
442
- assert_in_range 2..3, buffer.size
438
+ assert_in_range 2..3, buffer.size if IS_LINUX
443
439
  end
444
440
 
445
441
  def test_sleep
446
442
  t0 = Time.now
447
443
  sleep 0.1
448
444
  elapsed = Time.now - t0
449
- assert (0.05..0.15).include? elapsed if IS_LINUX
445
+ assert_in_range 0.05..0.15, elapsed if IS_LINUX
450
446
 
451
447
  f = spin { sleep }
452
448
  snooze
data/test/test_io.rb CHANGED
@@ -354,9 +354,9 @@ class IOClassMethodsTest < MiniTest::Test
354
354
  skip unless IS_LINUX
355
355
 
356
356
  counter = 0
357
- timer = spin { throttled_loop(200) { counter += 1 } }
357
+ timer = spin { throttled_loop(20) { counter += 1 } }
358
358
 
359
- IO.popen('sleep 0.05') { |io| io.read(8192) }
359
+ IO.popen('sleep 0.5') { |io| io.read(8192) }
360
360
  assert(counter >= 5)
361
361
 
362
362
  result = nil
data/test/test_kernel.rb CHANGED
@@ -51,8 +51,8 @@ class KernelTest < MiniTest::Test
51
51
  counter = 0
52
52
  timer = spin { throttled_loop(200) { counter += 1 } }
53
53
 
54
- `sleep 0.01`
55
- assert(counter >= 2)
54
+ `sleep 0.05`
55
+ assert_in_range 8..14, counter if IS_LINUX
56
56
 
57
57
  result = `echo "hello"`
58
58
  assert_equal "hello\n", result
data/test/test_socket.rb CHANGED
@@ -9,9 +9,9 @@ class SocketTest < MiniTest::Test
9
9
  super
10
10
  end
11
11
 
12
- def start_tcp_server_on_random_port
12
+ def start_tcp_server_on_random_port(host = '127.0.0.1')
13
13
  port = rand(1100..60000)
14
- server = TCPServer.new('127.0.0.1', port)
14
+ server = TCPServer.new(host, port)
15
15
  [port, server]
16
16
  rescue Errno::EADDRINUSE
17
17
  retry
@@ -40,6 +40,39 @@ class SocketTest < MiniTest::Test
40
40
  server&.close
41
41
  end
42
42
 
43
+ def test_tcpsocket_open_with_hostname
44
+ client = TCPSocket.open('google.com', 80)
45
+ client.write("GET / HTTP/1.0\r\nHost: google.com\r\n\r\n")
46
+ result = nil
47
+ move_on_after(1) {
48
+ result = client.read
49
+ }
50
+ assert result =~ /HTTP\/1.0 301 Moved Permanently/
51
+ end
52
+
53
+ def test_tcp_ipv6
54
+ port, server = start_tcp_server_on_random_port('::1')
55
+ server_fiber = spin do
56
+ while (socket = server.accept)
57
+ spin do
58
+ while (data = socket.gets(8192))
59
+ socket << data
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ snooze
66
+ client = TCPSocket.new('::1', port)
67
+ client.write("1234\n")
68
+ assert_equal "1234\n", client.recv(8192)
69
+ client.close
70
+ ensure
71
+ server_fiber&.stop
72
+ server_fiber&.await
73
+ server&.close
74
+ end
75
+
43
76
  def test_read
44
77
  port, server = start_tcp_server_on_random_port
45
78
  server_fiber = spin do
@@ -65,7 +65,7 @@ class ThreadPoolTest < MiniTest::Test
65
65
  end
66
66
  elapsed = Time.now - t0
67
67
 
68
- assert_in_range 0.0..0.009, elapsed
68
+ assert_in_range 0.0..0.009, elapsed if IS_LINUX
69
69
  assert buffer.size < 2
70
70
 
71
71
  sleep 0.15 # allow time for threads to spawn