uringmachine 0.29.0 → 0.29.1

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: 6a6a6d78b632e43c1ac15e8745ede898e531ff9a731822fd22c5991ca0222d69
4
- data.tar.gz: 0acd35ee028ea519c2788c720336dbcb1c2fa8317912459b7a81f4afbe6b3747
3
+ metadata.gz: 248a2f0e2a780904f26f0183d08237039e18b76b736e7b3563c2699e30041d65
4
+ data.tar.gz: 2020b0c8cc9be25becddef80fa4c66f0bc49e30d0791ec2b2b2e618fbf3ab0b6
5
5
  SHA512:
6
- metadata.gz: ed9f7684132ee1e1aae9c7783131fd927e88604444d44bc889cdf8c362b0a5dd85b3e887873c0512946af2c08dd8189e6c3bf972f19f90a7f12daee4c44c5ccd
7
- data.tar.gz: f5bff069de535e906543a679266700bacbb715d0e72b14d4bf7cd042ab8d77e58d8c69feb1dbd65f16026aa4bcec20d024acffd2e2f18ac255f5b70190c25788
6
+ metadata.gz: 543a8adf2c628f080f9ec249e11ff7e4bd969f0eca9e47285ba0ef20c28575ddd6d1902a3890d49ccb1ccf5100d13cd721bbd03c472bde15205344524fd7795c
7
+ data.tar.gz: 4afbe860f29187507c57a8e319d02f2f843d27aa7d65176f0e0040914bf4d8e68ce894d4663b13d3ace530bf2aa4fe3ca547e58d5cbcb1daf5d89f6d5bb94ae2
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ # 0.29.1 2026-03-14
2
+
3
+ - Add support for exception instance in `#timeout`
4
+ - Improve buffer commit level handling
5
+
1
6
  # 0.29.0 2026-03-11
2
7
 
3
8
  - Reimplement streams based on buffer pool
@@ -0,0 +1,122 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/inline'
4
+
5
+ gemfile do
6
+ source 'https://rubygems.org'
7
+ gem 'uringmachine', path: '..'
8
+ gem 'benchmark'
9
+ end
10
+
11
+ require 'benchmark'
12
+ require 'uringmachine'
13
+
14
+ C = 10
15
+ N = 1000
16
+
17
+ CMD = <<~EOF
18
+ bash -c "for i in {1..#{C*2}}; do nc -l -p 1234 </dev/random & done; wait $(jobs -p)"
19
+ EOF
20
+
21
+ def start_server
22
+ @pid = fork {
23
+ p :server_launch
24
+ `#{CMD}`
25
+ puts
26
+ p :server_done
27
+ puts
28
+ }
29
+ sleep(0.5)
30
+ end
31
+
32
+ def stop_server
33
+ Process.kill('SIGINT', @pid)
34
+ Process.wait(@pid)
35
+ end
36
+
37
+ def io_gets
38
+ start_server
39
+ tt = C.times.map {
40
+ Thread.new do
41
+ s = TCPSocket.new('localhost', 1234)
42
+ # io = File.open('/dev/random', 'r')
43
+ N.times { s.gets }
44
+ ensure
45
+ s.close
46
+ end
47
+ }
48
+ tt.each(&:join)
49
+ ensure
50
+ stop_server
51
+ end
52
+
53
+ @machine = UM.new
54
+
55
+ def buf_gets(fd, buffer)
56
+ while true
57
+ idx = buffer.byteindex("\n")
58
+ if idx
59
+ line = buffer[0..(idx - 1)]
60
+
61
+ buffer = buffer[(idx + 1)..-1]
62
+ return line
63
+ end
64
+ @machine.read(fd, buffer, 65536, -1)
65
+ end
66
+ end
67
+
68
+ def um_read
69
+ start_server
70
+ ff = C.times.map {
71
+ @machine.spin do
72
+ # fd = @machine.open('/dev/random', UM::O_RDONLY)
73
+ fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
74
+ @machine.connect(fd, '127.0.0.1', 1234)
75
+ buffer = +''.encode(Encoding::US_ASCII)
76
+ N.times { buf_gets(fd, buffer) }
77
+ ensure
78
+ @machine.close(fd)
79
+ end
80
+ }
81
+ @machine.await(ff)
82
+ ensure
83
+ stop_server
84
+ end
85
+
86
+ @total_stream = 0
87
+ def um_stream_do
88
+ # fd = @machine.open('/dev/random', UM::O_RDONLY)
89
+ fd = @machine.socket(UM::AF_INET, UM::SOCK_STREAM, 0, 0)
90
+ @machine.connect(fd, '127.0.0.1', 1234)
91
+ stream = UM::Stream.new(@machine, fd)
92
+ N.times { @total_stream += stream.get_line(0)&.bytesize || 0 }
93
+ rescue => e
94
+ p e
95
+ p e.backtrace
96
+ ensure
97
+ stream.clear
98
+ @machine.close(fd)
99
+ end
100
+
101
+ def um_stream
102
+ start_server
103
+ ff = C.times.map {
104
+ @machine.snooze
105
+ @machine.spin { um_stream_do }
106
+ }
107
+ @machine.await(ff)
108
+ pp total: @total_stream
109
+ ensure
110
+ stop_server
111
+ end
112
+
113
+ p(C:, N:)
114
+ um_stream
115
+ pp @machine.metrics
116
+ exit
117
+
118
+ Benchmark.bm do
119
+ it.report('Thread/IO#gets') { io_gets }
120
+ it.report('Fiber/UM#read+buf') { um_read }
121
+ it.report('Fiber/UM::Stream') { um_stream }
122
+ end
data/ext/um/um.c CHANGED
@@ -540,15 +540,19 @@ VALUE um_timeout_complete(VALUE arg) {
540
540
  return Qnil;
541
541
  }
542
542
 
543
- VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
543
+ VALUE um_timeout(struct um *machine, VALUE interval, VALUE obj) {
544
544
  static ID ID_new = 0;
545
- if (unlikely(!ID_new)) ID_new = rb_intern("new");
545
+
546
+ if (TYPE(obj) == T_CLASS) {
547
+ if (unlikely(!ID_new)) ID_new = rb_intern("new");
548
+ obj = rb_funcall(obj, ID_new, 0);
549
+ }
546
550
 
547
551
  struct um_op *op = um_op_acquire(machine);
548
552
  um_prep_op(machine, op, OP_TIMEOUT, 2, 0);
549
553
  op->ts = um_double_to_timespec(NUM2DBL(interval));
550
554
  RB_OBJ_WRITE(machine->self, &op->fiber, rb_fiber_current());
551
- RB_OBJ_WRITE(machine->self, &op->value, rb_funcall(class, ID_new, 0));
555
+ RB_OBJ_WRITE(machine->self, &op->value, obj);
552
556
  RB_OBJ_WRITE(machine->self, &op->async_op, Qnil);
553
557
 
554
558
  struct io_uring_sqe *sqe = um_get_sqe(machine, op);
@@ -556,6 +560,7 @@ VALUE um_timeout(struct um *machine, VALUE interval, VALUE class) {
556
560
 
557
561
  struct op_ctx ctx = { .machine = machine, .op = op };
558
562
  return rb_ensure(rb_yield, Qnil, um_timeout_complete, (VALUE)&ctx);
563
+ RB_GC_GUARD(obj);
559
564
  }
560
565
 
561
566
  /*******************************************************************************
data/ext/um/um.h CHANGED
@@ -111,12 +111,10 @@ enum um_stream_mode {
111
111
 
112
112
  #define BP_BGID 0xF00B
113
113
  #define BP_BR_ENTRIES 1024
114
-
115
114
  #define BP_INITIAL_BUFFER_SIZE (1U << 14) // 16KB
116
- #define BP_INITIAL_COMMIT_THRESHOLD (1U << 16) // 64KB
115
+ #define BP_INITIAL_COMMIT_LEVEL (BP_INITIAL_BUFFER_SIZE * 16) // 256KB
117
116
  #define BP_MAX_BUFFER_SIZE (1U << 20) // 1MB
118
-
119
- #define BP_MAX_COMMIT_THRESHOLD (BP_MAX_BUFFER_SIZE * BP_BR_ENTRIES) // 1GB
117
+ #define BP_MAX_COMMIT_LEVEL (BP_MAX_BUFFER_SIZE * BP_BR_ENTRIES) // 1GB
120
118
  #define BP_AVAIL_BID_BITMAP_WORDS (BP_BR_ENTRIES / 64)
121
119
 
122
120
  struct um_buffer {
@@ -163,7 +161,7 @@ struct um_op {
163
161
  struct iovec *iovecs; // used for vectorized write/send
164
162
  siginfo_t siginfo; // used for waitid
165
163
  int int_value; // used for getsockopt
166
- size_t bp_commit_threshold; // buffer pool commit threshold
164
+ size_t bp_commit_level; // buffer pool commit threshold
167
165
  };
168
166
  };
169
167
 
@@ -234,7 +232,7 @@ struct um {
234
232
 
235
233
  struct io_uring_buf_ring *bp_br;
236
234
  size_t bp_buffer_size;
237
- size_t bp_commit_threshold;
235
+ size_t bp_commit_level;
238
236
  struct um_buffer **bp_commited_buffers;
239
237
  uint64_t bp_avail_bid_bitmap[BP_AVAIL_BID_BITMAP_WORDS];
240
238
 
@@ -437,7 +435,7 @@ void stream_teardown(struct um_stream *stream);
437
435
  void stream_clear(struct um_stream *stream);
438
436
  VALUE stream_get_line(struct um_stream *stream, VALUE buf, size_t maxlen);
439
437
  VALUE stream_get_string(struct um_stream *stream, VALUE out_buffer, ssize_t len, size_t inc, int safe_inc);
440
- VALUE stream_skip(struct um_stream *stream, size_t len);
438
+ void stream_skip(struct um_stream *stream, size_t inc, int safe_inc);
441
439
  VALUE resp_decode(struct um_stream *stream, VALUE out_buffer);
442
440
  void resp_encode(struct um_write_buffer *buf, VALUE obj);
443
441
  void resp_encode_cmd(struct um_write_buffer *buf, int argc, VALUE *argv);
@@ -31,7 +31,6 @@ inline struct um_buffer *bp_buffer_checkout(struct um *machine) {
31
31
  buffer->ref_count++;
32
32
  buffer->pos = 0;
33
33
  buffer->next = NULL;
34
-
35
34
  return buffer;
36
35
  }
37
36
 
@@ -76,7 +75,7 @@ inline void bp_setup(struct um *machine) {
76
75
  if (unlikely(!machine->bp_br)) rb_syserr_fail(ret, strerror(ret));
77
76
 
78
77
  machine->bp_buffer_size = BP_INITIAL_BUFFER_SIZE;
79
- machine->bp_commit_threshold = BP_INITIAL_COMMIT_THRESHOLD;
78
+ machine->bp_commit_level = BP_INITIAL_COMMIT_LEVEL;
80
79
  machine->bp_commited_buffers = malloc(sizeof(struct um_buffer) * BP_BR_ENTRIES);
81
80
  memset(machine->bp_commited_buffers, 0, sizeof(struct um_buffer) * BP_BR_ENTRIES);
82
81
  memset(machine->bp_avail_bid_bitmap, 0xFF, sizeof(machine->bp_avail_bid_bitmap));
@@ -160,10 +159,13 @@ inline struct um_buffer *get_buffer(struct um *machine, int bid) {
160
159
 
161
160
  inline int should_commit_more_p(struct um *machine) {
162
161
  return (machine->bp_buffer_count < BP_BR_ENTRIES) &&
163
- (machine->bp_total_commited < machine->bp_commit_threshold);
162
+ (machine->bp_total_commited < machine->bp_commit_level);
164
163
  }
165
164
 
166
165
  inline void bp_ensure_commit_level(struct um *machine) {
166
+ if (machine->bp_total_commited > (machine->bp_commit_level / 2))
167
+ return;
168
+
167
169
  int added = 0;
168
170
  while (should_commit_more_p(machine)) {
169
171
  if (likely(commit_buffer(machine, added))) added++;
@@ -178,11 +180,11 @@ inline void bp_ensure_commit_level(struct um *machine) {
178
180
  }
179
181
 
180
182
  inline void bp_handle_enobufs(struct um *machine) {
181
- if (unlikely(machine->bp_commit_threshold >= BP_MAX_COMMIT_THRESHOLD))
183
+ if (unlikely(machine->bp_commit_level >= BP_MAX_COMMIT_LEVEL))
182
184
  rb_raise(eUMError, "Buffer starvation");
183
185
 
184
- machine->bp_commit_threshold *= 2;
185
- while (machine->bp_buffer_size < machine->bp_commit_threshold / 4)
186
+ machine->bp_commit_level *= 2;
187
+ while (machine->bp_buffer_size < machine->bp_commit_level / 4)
186
188
  machine->bp_buffer_size *= 2;
187
189
  bp_discard_buffer_freelist(machine);
188
190
  }
data/ext/um/um_class.c CHANGED
@@ -334,17 +334,17 @@ VALUE UM_schedule(VALUE self, VALUE fiber, VALUE value) {
334
334
  }
335
335
 
336
336
  /* Runs the given block, interrupting its execution if its runtime exceeds the
337
- * given timeout interval (in seconds).
337
+ * given timeout interval (in seconds), raising the specified exception.
338
338
  *
339
339
  * - https://www.man7.org/linux/man-pages//man3/io_uring_prep_timeoute.3.html
340
340
  *
341
341
  * @param interval [Number] timeout interval in seconds
342
- * @param exception_class [any] timeout exception class
342
+ * @param exception [any] timeout exception class or instance
343
343
  * @return [any] block's return value
344
344
  */
345
- VALUE UM_timeout(VALUE self, VALUE interval, VALUE exception_class) {
345
+ VALUE UM_timeout(VALUE self, VALUE interval, VALUE exception) {
346
346
  struct um *machine = um_get_machine(self);
347
- return um_timeout(machine, interval, exception_class);
347
+ return um_timeout(machine, interval, exception);
348
348
  }
349
349
 
350
350
  /* Puts the current fiber to sleep for the given time duration (in seconds),
data/ext/um/um_stream.c CHANGED
@@ -50,7 +50,7 @@ void stream_multishot_op_start(struct um_stream *stream) {
50
50
  default:
51
51
  um_raise_internal_error("Invalid multishot op");
52
52
  }
53
- stream->op->bp_commit_threshold = stream->machine->bp_commit_threshold;
53
+ stream->op->bp_commit_level = stream->machine->bp_commit_level;
54
54
  }
55
55
 
56
56
  void stream_multishot_op_stop(struct um_stream *stream) {
@@ -157,15 +157,26 @@ int stream_get_more_segments_bp(struct um_stream *stream) {
157
157
  um_op_multishot_results_clear(stream->machine, stream->op);
158
158
  if (unlikely(enobufs)) {
159
159
  int should_restart = stream->pending_len < (stream->machine->bp_buffer_size * 4);
160
+ // int same_threshold = stream->op->bp_commit_level == stream->machine->bp_commit_level;
161
+
162
+ // fprintf(stderr, "%p enobufs total: %ld pending: %ld threshold: %ld bc: %d (same: %d, restart: %d)\n",
163
+ // stream,
164
+ // total_bytes, stream->pending_len, stream->machine->bp_commit_level,
165
+ // stream->machine->bp_buffer_count,
166
+ // same_threshold, should_restart
167
+ // );
160
168
 
161
169
  // If multiple stream ops are happening at the same time, they'll all get
162
170
  // ENOBUFS! We track the commit threshold in the op in order to prevent
163
171
  // running bp_handle_enobufs() more than once.
164
172
 
165
173
  if (should_restart) {
166
- if (stream->op->bp_commit_threshold == stream->machine->bp_commit_threshold)
174
+ if (stream->op->bp_commit_level == stream->machine->bp_commit_level)
167
175
  bp_handle_enobufs(stream->machine);
168
- stream_multishot_op_start(stream);
176
+
177
+ um_op_release(stream->machine, stream->op);
178
+ stream->op = NULL;
179
+ // stream_multishot_op_start(stream);
169
180
  }
170
181
  else {
171
182
  um_op_release(stream->machine, stream->op);
@@ -215,6 +226,44 @@ int stream_get_more_segments(struct um_stream *stream) {
215
226
 
216
227
  ///////////////////////////////////////////////////////////////////////////////////////
217
228
 
229
+ inline void stream_shift_head(struct um_stream *stream) {
230
+ struct um_segment *consumed = stream->head;
231
+ stream->head = consumed->next;
232
+ if (!stream->head) stream->tail = NULL;
233
+ um_segment_checkin(stream->machine, consumed);
234
+ stream->pos = 0;
235
+ }
236
+
237
+ inline void stream_skip(struct um_stream *stream, size_t inc, int safe_inc) {
238
+ while (inc) {
239
+ size_t segment_len = stream->head->len - stream->pos;
240
+ size_t inc_len = (segment_len <= inc) ? segment_len : inc;
241
+ inc -= inc_len;
242
+ stream->pos += inc_len;
243
+ stream->pending_len -= inc_len;
244
+ if (stream->pos == stream->head->len) {
245
+ stream_shift_head(stream);
246
+ if (inc && safe_inc && !stream->head) {
247
+ if (!stream_get_more_segments(stream)) break;
248
+ }
249
+ }
250
+ }
251
+ }
252
+
253
+ inline void stream_copy(struct um_stream *stream, char *dest, size_t len) {
254
+ while (len) {
255
+ char *segment_ptr = stream->head->ptr + stream->pos;
256
+ size_t segment_len = stream->head->len - stream->pos;
257
+ size_t cpy_len = (segment_len <= len) ? segment_len : len;
258
+ memcpy(dest, segment_ptr, cpy_len);
259
+
260
+ len -= cpy_len;
261
+ stream->pos += cpy_len;
262
+ stream->pending_len -= cpy_len;
263
+ dest += cpy_len;
264
+ if (stream->pos == stream->head->len) stream_shift_head(stream);
265
+ }
266
+ }
218
267
 
219
268
  VALUE stream_consume_string(struct um_stream *stream, VALUE out_buffer, size_t len, size_t inc, int safe_inc) {
220
269
  VALUE str = Qnil;
@@ -228,69 +277,22 @@ VALUE stream_consume_string(struct um_stream *stream, VALUE out_buffer, size_t l
228
277
  }
229
278
  else
230
279
  str = rb_str_new(NULL, len);
231
- char *str_ptr = RSTRING_PTR(str);
232
- while (len) {
233
- char *segment_ptr = stream->head->ptr + stream->pos;
234
- size_t segment_len = stream->head->len - stream->pos;
235
- size_t cpy_len = (segment_len <= len) ? segment_len : len;
236
- memcpy(str_ptr, segment_ptr, cpy_len);
280
+ char *dest = RSTRING_PTR(str);
237
281
 
238
- len -= cpy_len;
239
- stream->pos += cpy_len;
240
- stream->pending_len -= cpy_len;
241
- str_ptr += cpy_len;
242
- if (stream->pos == stream->head->len) {
243
- struct um_segment *consumed = stream->head;
244
- stream->head = consumed->next;
245
- if (!stream->head) stream->tail = NULL;
246
- um_segment_checkin(stream->machine, consumed);
247
- stream->pos = 0;
248
- }
249
- }
250
-
251
- while (inc) {
252
- size_t segment_len = stream->head->len - stream->pos;
253
- size_t inc_len = (segment_len <= inc) ? segment_len : inc;
254
- inc -= inc_len;
255
- stream->pos += inc_len;
256
- stream->pending_len -= inc_len;
257
- if (stream->pos == stream->head->len) {
258
- struct um_segment *consumed = stream->head;
259
- stream->head = consumed->next;
260
- um_segment_checkin(stream->machine, consumed);
261
- if (!stream->head) {
262
- stream->tail = NULL;
263
- if (inc && safe_inc) {
264
- if (!stream_get_more_segments(stream)) break;
265
- }
266
- }
267
- stream->pos = 0;
268
- }
269
- }
282
+ stream_copy(stream, dest, len);
283
+ stream_skip(stream, inc, safe_inc);
270
284
  return str;
271
285
  RB_GC_GUARD(str);
272
286
  }
273
287
 
274
- // inline void stream_advance(struct um_stream *stream, size_t inc) {
275
- // while (inc) {
276
- // size_t segment_len = stream->head->len - stream->pos;
277
- // size_t inc_len = (segment_len <= inc) ? segment_len : inc;
278
- // inc -= inc_len;
279
- // stream->pos += inc_len;
280
- // if (stream->pos == stream->head->len) {
281
- // struct um_segment *consumed = stream->head;
282
- // stream->head = consumed->next;
283
- // um_segment_checkin(stream->machine, consumed);
284
- // if (!stream->head) {
285
- // stream->tail = NULL;
286
- // if (!stream_get_more_segments(stream)) return;
287
- // }
288
- // stream->pos = 0;
289
- // }
290
- // }
291
- // }
292
-
293
288
  VALUE stream_get_line(struct um_stream *stream, VALUE out_buffer, size_t maxlen) {
289
+ // if (stream->head) {
290
+ // fprintf(stderr, "head: %p pos: %ld: %.*s\n",
291
+ // stream->head, stream->pos,
292
+ // (int)(stream->head->len - stream->pos), stream->head->ptr + stream->pos
293
+ // );
294
+ // }
295
+
294
296
  if (unlikely(stream->eof && !stream->head)) return Qnil;
295
297
  if (!stream->tail && !stream_get_more_segments(stream)) return Qnil;
296
298
 
data/grant-2025/tasks.md CHANGED
@@ -35,8 +35,9 @@
35
35
  - [v] Data processing through a rewritten stream implementation.
36
36
 
37
37
  - [ ] More benchmarks
38
- - Different reading methods in concurrent setting
39
- - SSL vs SSL-custom-BIO vs SSL-stream
38
+ - [ ] Different reading methods in concurrent setting
39
+ - [ ] SSL vs SSL-custom-BIO vs SSL-stream in concurrent setting
40
+ - [ ] stream resp client vs redis gem in concurrent setting
40
41
 
41
42
  - [v] Sidecar mode
42
43
  - [v] Convert `UM#initialize` to take kwargs
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class UringMachine
4
- VERSION = '0.29.0'
4
+ VERSION = '0.29.1'
5
5
  end
data/test/helper.rb CHANGED
@@ -103,3 +103,5 @@ class UMBaseTest < Minitest::Test
103
103
  dir
104
104
  end
105
105
  end
106
+
107
+ puts "Ruby: #{RUBY_VERSION}\nKernel: #{UringMachine.kernel_version}"
@@ -6,6 +6,7 @@ require 'securerandom'
6
6
  require 'socket'
7
7
  require 'net/http'
8
8
  require 'json'
9
+ require 'timeout'
9
10
 
10
11
  class MethodCallAuditor
11
12
  attr_reader :calls
@@ -722,12 +723,11 @@ class FiberSchedulerTest < UMBaseTest
722
723
  sleep 1
723
724
  end
724
725
  res = true
725
- rescue => e
726
- res = e
726
+ rescue => res
727
727
  end
728
728
  @scheduler.join
729
- assert_equal 3, machine.metrics[:total_ops]
730
729
  assert_kind_of Timeout::Error, res
730
+ assert_equal 3, machine.metrics[:total_ops]
731
731
  assert_equal({
732
732
  fiber: 1,
733
733
  timeout_after: 1,
data/test/test_stream.rb CHANGED
@@ -46,7 +46,10 @@ class StreamTest < StreamBaseTest
46
46
  assert stream.eof?
47
47
 
48
48
  stream.clear
49
- assert_equal [5, 0, 256, 16384 * 5, 16384 * 5 - 6], buffer_metrics
49
+
50
+ # initial buffer size: 6BKV, initial buffers commited: 16 (256KB)
51
+ # (plus an additional buffer commited after first usage)
52
+ assert_equal [16, 0, 256, 16384 * 16, 16384 * 16 - 6], buffer_metrics
50
53
  assert_equal 0, machine.metrics[:ops_pending]
51
54
  end
52
55
 
@@ -68,7 +71,7 @@ class StreamTest < StreamBaseTest
68
71
  assert_equal 0, machine.metrics[:ops_pending]
69
72
  assert_equal 256, machine.metrics[:segments_free]
70
73
 
71
- assert_equal [5, 0, 256, 16384 * 5, 16384 * 5 - 6], buffer_metrics
74
+ assert_equal [16, 0, 256, 16384 * 16, 16384 * 16 - 6], buffer_metrics
72
75
  ensure
73
76
  machine.close(rfd) rescue nil
74
77
  machine.close(wfd) rescue nil
@@ -118,11 +121,11 @@ class StreamTest < StreamBaseTest
118
121
  buf = stream.get_string(msg.bytesize)
119
122
  assert_equal msg, buf
120
123
 
121
- assert_equal 16, machine.metrics[:buffers_allocated]
122
- assert_equal 11, machine.metrics[:buffers_free]
124
+ stream.clear
125
+ # numbers may vary with different kernel versions
126
+ assert_in_range 24..32, machine.metrics[:buffers_allocated]
127
+ assert_in_range 10..18, machine.metrics[:buffers_free]
123
128
  assert_equal 256, machine.metrics[:segments_free]
124
- assert_equal 65536 * 4, machine.metrics[:buffer_space_allocated]
125
-
126
129
  ensure
127
130
  machine.terminate(f)
128
131
  machine.join(f)
@@ -136,7 +139,7 @@ class StreamTest < StreamBaseTest
136
139
 
137
140
  assert_equal 'foo', stream.get_line(0)
138
141
 
139
- assert_equal [5, 0, 255, 16384 * 5, 16384 * 5 - 12], buffer_metrics
142
+ assert_equal [16, 0, 255, 16384 * 16, 16384 * 16 - 12], buffer_metrics
140
143
  assert_equal 'bar', stream.get_line(0)
141
144
  assert_nil stream.get_line(0)
142
145
  assert_equal "baz", stream.get_string(-6)
@@ -152,11 +155,11 @@ class StreamTest < StreamBaseTest
152
155
  machine.close(@wfd)
153
156
 
154
157
  # three segments received
155
- assert_equal [5, 0, 253, 16384 * 5, 16384 * 5 - 13], buffer_metrics
158
+ assert_equal [16, 0, 253, 16384 * 16, 16384 * 16 - 13], buffer_metrics
156
159
  assert_equal 'bar', stream.get_line(0)
157
- assert_equal [5, 0, 255, 16384 * 5, 16384 * 5 - 13], buffer_metrics
160
+ assert_equal [16, 0, 255, 16384 * 16, 16384 * 16 - 13], buffer_metrics
158
161
  assert_equal 'baz', stream.get_line(0)
159
- assert_equal [5, 0, 256, 16384 * 5, 16384 * 5 - 13], buffer_metrics
162
+ assert_equal [16, 0, 256, 16384 * 16, 16384 * 16 - 13], buffer_metrics
160
163
  assert_nil stream.get_line(0)
161
164
  end
162
165
 
@@ -182,7 +185,7 @@ class StreamTest < StreamBaseTest
182
185
  assert_equal 'bizz', stream.get_line(5)
183
186
 
184
187
  assert_nil stream.get_line(8)
185
- assert_equal [5, 0, 256, 16384 * 5, 16384 * 5 - 17], buffer_metrics
188
+ assert_equal [16, 0, 256, 16384 * 16, 16384 * 16 - 17], buffer_metrics
186
189
  end
187
190
 
188
191
  def test_stream_get_string
@@ -467,6 +470,23 @@ class StreamDevRandomTest < UMBaseTest
467
470
  machine.close(fd) rescue nil
468
471
  end
469
472
 
473
+ def get_line_do(n, acc)
474
+ fd = @machine.open('/dev/random', UM::O_RDONLY)
475
+ stream = UM::Stream.new(@machine, fd)
476
+ n.times { acc << stream.get_line(0) }
477
+ end
478
+
479
+ def test_stream_dev_random_get_line_concurrent
480
+ acc = []
481
+ c = 1
482
+ n = 100000
483
+ ff = c.times.map {
484
+ machine.spin { get_line_do(n, acc) }
485
+ }
486
+ machine.await(ff)
487
+ assert_equal c * n, acc.size
488
+ end
489
+
470
490
  def test_stream_dev_random_get_string
471
491
  fd = machine.open('/dev/random', UM::O_RDONLY)
472
492
  stream = UM::Stream.new(machine, fd)
data/test/test_um.rb CHANGED
@@ -292,6 +292,20 @@ class ScheduleTest < UMBaseTest
292
292
  assert_kind_of TOError, e
293
293
  end
294
294
 
295
+ def test_timeout_with_exception_instance
296
+ res = nil
297
+ e = TOError.new
298
+ begin
299
+ res = machine.timeout(0.01, e) {
300
+ machine.sleep(1)
301
+ :foo
302
+ }
303
+ rescue => res
304
+ end
305
+
306
+ assert_equal e, res
307
+ end
308
+
295
309
  def test_timeout_with_raising_block
296
310
  e = nil
297
311
  begin
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uringmachine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.29.0
4
+ version: 0.29.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sharon Rosner
@@ -67,6 +67,7 @@ files:
67
67
  - benchmark/common.rb
68
68
  - benchmark/dns_client.rb
69
69
  - benchmark/gets.rb
70
+ - benchmark/gets_concurrent.rb
70
71
  - benchmark/http_parse.rb
71
72
  - benchmark/http_server_accept_queue.rb
72
73
  - benchmark/http_server_multi_accept.rb