event 0.2.3 → 0.4.3

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: 9a363339a1d384ea4d844450be2ff46cbc091bc0aca240e869491bf6a5d61300
4
- data.tar.gz: b1b3c431481f4499bf6605010392283acfb6f54a59aed232f25217d2cce4a221
3
+ metadata.gz: db1ee17a5921d3aa6c3ff4314099a1879d4c7ff76f43c3001f6f7872501d1f4c
4
+ data.tar.gz: 3fda0f1769bfc7b489425b9b432d6225772011c8bbaaa34f0dfd5193c8ed940a
5
5
  SHA512:
6
- metadata.gz: 3321631a8be1353038cdc9c63a2b6b17f02ea66924b11f5fb9126f9db1072ea4ee59141858f26e8879e1b52fe265471a2552afcab56cddd84b1e28d1611235d9
7
- data.tar.gz: 7196977bd770153c5be35d16701e32a635c84cf53edf2880b4c5f095b8644825c7dcd1254a4da8f72655fb48e3ac3ec529d2ae2496691fb9ead30bb595cae357
6
+ metadata.gz: 768501ac864f0436b95050721b14cbf4ce0ba6a3b79d2f0d8e244523477f55fd71f82ae3e7ab088c94aa40a6d0200acc4138caff472c95426a01fa784a50911c
7
+ data.tar.gz: f876ffe91ed99aa0e013ddaed5e2c4e6a72724891cc3bdceae9cb3bb1b30909716c92b8d551d23a171870b2e548dec32455de028bf5ea60964969d4aed919a9a
data/ext/event/Makefile CHANGED
@@ -139,8 +139,8 @@ target_prefix = /event
139
139
  LOCAL_LIBS =
140
140
  LIBS =
141
141
  ORIG_SRCS = event.c
142
- SRCS = $(ORIG_SRCS) event.c kqueue.c
143
- OBJS = event.o kqueue.o
142
+ SRCS = $(ORIG_SRCS) event.c backend.c kqueue.c
143
+ OBJS = event.o backend.o kqueue.o
144
144
  HDRS = $(srcdir)/event.h $(srcdir)/extconf.h
145
145
  LOCAL_HDRS =
146
146
  TARGET = event
Binary file
@@ -0,0 +1,39 @@
1
+ // Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ // of this software and associated documentation files (the "Software"), to deal
5
+ // in the Software without restriction, including without limitation the rights
6
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ // copies of the Software, and to permit persons to whom the Software is
8
+ // furnished to do so, subject to the following conditions:
9
+ //
10
+ // The above copyright notice and this permission notice shall be included in
11
+ // all copies or substantial portions of the Software.
12
+ //
13
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ // THE SOFTWARE.
20
+
21
+ #include "backend.h"
22
+
23
+ static ID id_transfer, id_alive_p;
24
+
25
+ void Init_Event_Backend(VALUE Event_Backend) {
26
+ id_transfer = rb_intern("transfer");
27
+ id_alive_p = rb_intern("alive?");
28
+ }
29
+
30
+ VALUE
31
+ Event_Backend_resume_safe(VALUE fiber, VALUE result) {
32
+ VALUE alive = rb_funcall(fiber, id_alive_p, 0);
33
+
34
+ if (RTEST(alive)) {
35
+ return rb_funcall(fiber, id_transfer, 1, result);
36
+ } else {
37
+ return Qnil;
38
+ }
39
+ }
@@ -18,6 +18,9 @@
18
18
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  // THE SOFTWARE.
20
20
 
21
+ #include <ruby.h>
22
+ #include <ruby/thread.h>
23
+
21
24
  enum Event {
22
25
  READABLE = 1,
23
26
  PRIORITY = 2,
@@ -26,4 +29,8 @@ enum Event {
26
29
  HANGUP = 16
27
30
  };
28
31
 
29
- #include <ruby/thread.h>
32
+ void
33
+ Init_Event_Backend();
34
+
35
+ VALUE
36
+ Event_Backend_resume_safe(VALUE fiber, VALUE argument);
@@ -41,13 +41,19 @@ void Event_Backend_EPoll_Type_mark(void *_data)
41
41
  rb_gc_mark(data->loop);
42
42
  }
43
43
 
44
+ static
45
+ void close_internal(struct Event_Backend_EPoll *data) {
46
+ if (data->descriptor >= 0) {
47
+ close(data->descriptor);
48
+ data->descriptor = -1;
49
+ }
50
+ }
51
+
44
52
  void Event_Backend_EPoll_Type_free(void *_data)
45
53
  {
46
54
  struct Event_Backend_EPoll *data = _data;
47
55
 
48
- if (data->descriptor >= 0) {
49
- close(data->descriptor);
50
- }
56
+ close_internal(data);
51
57
 
52
58
  free(data);
53
59
  }
@@ -96,6 +102,15 @@ VALUE Event_Backend_EPoll_initialize(VALUE self, VALUE loop) {
96
102
  return self;
97
103
  }
98
104
 
105
+ VALUE Event_Backend_EPoll_close(VALUE self) {
106
+ struct Event_Backend_EPoll *data = NULL;
107
+ TypedData_Get_Struct(self, struct Event_Backend_EPoll, &Event_Backend_EPoll_Type, data);
108
+
109
+ close_internal(data);
110
+
111
+ return Qnil;
112
+ }
113
+
99
114
  static inline
100
115
  uint32_t epoll_flags_from_events(int events) {
101
116
  uint32_t flags = 0;
@@ -257,13 +272,13 @@ VALUE Event_Backend_EPoll_select(VALUE self, VALUE duration) {
257
272
  .timeout = 0
258
273
  };
259
274
 
260
- select_internal_without_gvl(&arguments);
275
+ select_internal_with_gvl(&arguments);
261
276
 
262
277
  if (arguments.count == 0) {
263
278
  arguments.timeout = make_timeout(duration);
264
279
 
265
280
  if (arguments.timeout != 0) {
266
- select_internal_with_gvl(&arguments);
281
+ select_internal_without_gvl(&arguments);
267
282
  }
268
283
  }
269
284
 
@@ -273,7 +288,7 @@ VALUE Event_Backend_EPoll_select(VALUE self, VALUE duration) {
273
288
 
274
289
  // fprintf(stderr, "-> fiber=%p descriptor=%d\n", (void*)fiber, events[i].data.fd);
275
290
 
276
- rb_funcall(fiber, id_transfer, 1, result);
291
+ Event_Backend_resume_safe(fiber, result);
277
292
  }
278
293
 
279
294
  return INT2NUM(arguments.count);
@@ -287,6 +302,7 @@ void Init_Event_Backend_EPoll(VALUE Event_Backend) {
287
302
 
288
303
  rb_define_alloc_func(Event_Backend_EPoll, Event_Backend_EPoll_allocate);
289
304
  rb_define_method(Event_Backend_EPoll, "initialize", Event_Backend_EPoll_initialize, 1);
305
+ rb_define_method(Event_Backend_EPoll, "close", Event_Backend_EPoll_close, 0);
290
306
 
291
307
  rb_define_method(Event_Backend_EPoll, "io_wait", Event_Backend_EPoll_io_wait, 3);
292
308
  rb_define_method(Event_Backend_EPoll, "select", Event_Backend_EPoll_select, 1);
@@ -41,13 +41,19 @@ void Event_Backend_KQueue_Type_mark(void *_data)
41
41
  rb_gc_mark(data->loop);
42
42
  }
43
43
 
44
+ static
45
+ void close_internal(struct Event_Backend_KQueue *data) {
46
+ if (data->descriptor >= 0) {
47
+ close(data->descriptor);
48
+ data->descriptor = -1;
49
+ }
50
+ }
51
+
44
52
  void Event_Backend_KQueue_Type_free(void *_data)
45
53
  {
46
54
  struct Event_Backend_KQueue *data = _data;
47
55
 
48
- if (data->descriptor >= 0) {
49
- close(data->descriptor);
50
- }
56
+ close_internal(data);
51
57
 
52
58
  free(data);
53
59
  }
@@ -97,6 +103,15 @@ VALUE Event_Backend_KQueue_initialize(VALUE self, VALUE loop) {
97
103
  return self;
98
104
  }
99
105
 
106
+ VALUE Event_Backend_KQueue_close(VALUE self) {
107
+ struct Event_Backend_KQueue *data = NULL;
108
+ TypedData_Get_Struct(self, struct Event_Backend_KQueue, &Event_Backend_KQueue_Type, data);
109
+
110
+ close_internal(data);
111
+
112
+ return Qnil;
113
+ }
114
+
100
115
  static
101
116
  int io_add_filters(int descriptor, int ident, int events, VALUE fiber) {
102
117
  int count = 0;
@@ -310,7 +325,8 @@ VALUE Event_Backend_KQueue_select(VALUE self, VALUE duration) {
310
325
  for (int i = 0; i < arguments.count; i += 1) {
311
326
  VALUE fiber = (VALUE)arguments.events[i].udata;
312
327
  VALUE result = INT2NUM(arguments.events[i].filter);
313
- rb_funcall(fiber, id_transfer, 1, result);
328
+
329
+ Event_Backend_resume_safe(fiber, result);
314
330
  }
315
331
 
316
332
  return INT2NUM(arguments.count);
@@ -324,6 +340,7 @@ void Init_Event_Backend_KQueue(VALUE Event_Backend) {
324
340
 
325
341
  rb_define_alloc_func(Event_Backend_KQueue, Event_Backend_KQueue_allocate);
326
342
  rb_define_method(Event_Backend_KQueue, "initialize", Event_Backend_KQueue_initialize, 1);
343
+ rb_define_method(Event_Backend_KQueue, "close", Event_Backend_KQueue_close, 0);
327
344
 
328
345
  rb_define_method(Event_Backend_KQueue, "io_wait", Event_Backend_KQueue_io_wait, 3);
329
346
  rb_define_method(Event_Backend_KQueue, "select", Event_Backend_KQueue_select, 1);
@@ -28,8 +28,8 @@
28
28
  static VALUE Event_Backend_URing = Qnil;
29
29
  static ID id_fileno, id_transfer;
30
30
 
31
- enum {URING_ENTRIES = 64};
32
- enum {URING_MAX_EVENTS = 64};
31
+ enum {URING_ENTRIES = 128};
32
+ enum {URING_MAX_EVENTS = 128};
33
33
 
34
34
  struct Event_Backend_URing {
35
35
  VALUE loop;
@@ -42,14 +42,19 @@ void Event_Backend_URing_Type_mark(void *_data)
42
42
  rb_gc_mark(data->loop);
43
43
  }
44
44
 
45
- void Event_Backend_URing_Type_free(void *_data)
46
- {
47
- struct Event_Backend_URing *data = _data;
48
-
45
+ static
46
+ void close_internal(struct Event_Backend_URing *data) {
49
47
  if (data->ring.ring_fd >= 0) {
50
48
  io_uring_queue_exit(&data->ring);
51
49
  data->ring.ring_fd = -1;
52
50
  }
51
+ }
52
+
53
+ void Event_Backend_URing_Type_free(void *_data)
54
+ {
55
+ struct Event_Backend_URing *data = _data;
56
+
57
+ close_internal(data);
53
58
 
54
59
  free(data);
55
60
  }
@@ -97,6 +102,15 @@ VALUE Event_Backend_URing_initialize(VALUE self, VALUE loop) {
97
102
  return self;
98
103
  }
99
104
 
105
+ VALUE Event_Backend_URing_close(VALUE self) {
106
+ struct Event_Backend_URing *data = NULL;
107
+ TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
108
+
109
+ close_internal(data);
110
+
111
+ return Qnil;
112
+ }
113
+
100
114
  static inline
101
115
  short poll_flags_from_events(int events) {
102
116
  short flags = 0;
@@ -128,12 +142,22 @@ struct io_wait_arguments {
128
142
  short flags;
129
143
  };
130
144
 
145
+ struct io_uring_sqe * io_get_sqe(struct Event_Backend_URing *data) {
146
+ struct io_uring_sqe *sqe = io_uring_get_sqe(&data->ring);
147
+
148
+ while (sqe == NULL) {
149
+ sqe = io_uring_get_sqe(&data->ring);
150
+ }
151
+
152
+ return sqe;
153
+ }
154
+
131
155
  static
132
156
  VALUE io_wait_rescue(VALUE _arguments, VALUE exception) {
133
157
  struct io_wait_arguments *arguments = (struct io_wait_arguments *)_arguments;
134
158
  struct Event_Backend_URing *data = arguments->data;
135
159
 
136
- struct io_uring_sqe *sqe = Event_Backend_URing_io_uring_get_sqe(data);
160
+ struct io_uring_sqe *sqe = io_get_sqe(data);
137
161
 
138
162
  // fprintf(stderr, "poll_remove(%p, %p)\n", sqe, (void*)arguments->fiber);
139
163
 
@@ -157,25 +181,14 @@ VALUE io_wait_transfer(VALUE _arguments) {
157
181
  return INT2NUM(events_from_poll_flags(flags));
158
182
  };
159
183
 
160
- struct io_uring_sqe *Event_Backend_URing_io_uring_get_sqe(struct Event_Backend_URing *data) {
161
- struct io_uring_sqe *sqe = NULL;
162
-
163
- while (true) {
164
- sqe = io_uring_get_sqe(&data->ring);
165
- if (sqe != NULL) {
166
- return sqe;
167
- }
168
- // The sqe is full, we need to poll before submitting more events.
169
- Event_Backend_URing_select(self, INT2NUM(0));
170
- }
171
- }
172
-
173
184
  VALUE Event_Backend_URing_io_wait(VALUE self, VALUE fiber, VALUE io, VALUE events) {
174
185
  struct Event_Backend_URing *data = NULL;
175
186
  TypedData_Get_Struct(self, struct Event_Backend_URing, &Event_Backend_URing_Type, data);
176
187
 
177
188
  int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
178
- struct io_uring_sqe *sqe = Event_Backend_URing_io_uring_get_sqe(data);
189
+ struct io_uring_sqe *sqe = io_get_sqe(data);
190
+
191
+ if (!sqe) return INT2NUM(0);
179
192
 
180
193
  short flags = poll_flags_from_events(NUM2INT(events));
181
194
 
@@ -224,7 +237,7 @@ VALUE Event_Backend_URing_io_read(VALUE self, VALUE fiber, VALUE io, VALUE buffe
224
237
  resize_to_capacity(buffer, NUM2SIZET(offset), NUM2SIZET(length));
225
238
 
226
239
  int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
227
- struct io_uring_sqe *sqe = Event_Backend_URing_io_uring_get_sqe(data);
240
+ struct io_uring_sqe *sqe = io_get_sqe(data);
228
241
 
229
242
  struct iovec iovecs[1];
230
243
  iovecs[0].iov_base = RSTRING_PTR(buffer) + NUM2SIZET(offset);
@@ -256,7 +269,7 @@ VALUE Event_Backend_URing_io_write(VALUE self, VALUE fiber, VALUE io, VALUE buff
256
269
  }
257
270
 
258
271
  int descriptor = NUM2INT(rb_funcall(io, id_fileno, 0));
259
- struct io_uring_sqe *sqe = Event_Backend_URing_io_uring_get_sqe(data);
272
+ struct io_uring_sqe *sqe = io_get_sqe(data);
260
273
 
261
274
  struct iovec iovecs[1];
262
275
  iovecs[0].iov_base = RSTRING_PTR(buffer) + NUM2SIZET(offset);
@@ -384,7 +397,7 @@ VALUE Event_Backend_URing_select(VALUE self, VALUE duration) {
384
397
 
385
398
  io_uring_cqe_seen(&data->ring, cqes[i]);
386
399
 
387
- rb_funcall(fiber, id_transfer, 1, result);
400
+ Event_Backend_resume_safe(fiber, result);
388
401
  }
389
402
 
390
403
  return INT2NUM(result);
@@ -398,6 +411,7 @@ void Init_Event_Backend_URing(VALUE Event_Backend) {
398
411
 
399
412
  rb_define_alloc_func(Event_Backend_URing, Event_Backend_URing_allocate);
400
413
  rb_define_method(Event_Backend_URing, "initialize", Event_Backend_URing_initialize, 1);
414
+ rb_define_method(Event_Backend_URing, "close", Event_Backend_URing_close, 0);
401
415
 
402
416
  rb_define_method(Event_Backend_URing, "io_wait", Event_Backend_URing_io_wait, 3);
403
417
  rb_define_method(Event_Backend_URing, "select", Event_Backend_URing_select, 1);
Binary file
data/ext/event/event.c CHANGED
@@ -19,6 +19,7 @@
19
19
  // THE SOFTWARE.
20
20
 
21
21
  #include "event.h"
22
+ #include "backend/backend.h"
22
23
 
23
24
  VALUE Event = Qnil;
24
25
  VALUE Event_Backend = Qnil;
@@ -32,6 +33,8 @@ void Init_event()
32
33
  Event = rb_define_module("Event");
33
34
  Event_Backend = rb_define_module_under(Event, "Backend");
34
35
 
36
+ Init_Event_Backend(Event_Backend);
37
+
35
38
  #ifdef EVENT_BACKEND_URING
36
39
  Init_Event_Backend_URing(Event_Backend);
37
40
  #endif
data/ext/event/event.o CHANGED
Binary file
data/ext/event/extconf.rb CHANGED
@@ -30,7 +30,7 @@ dir_config(extension_name)
30
30
 
31
31
  $CFLAGS << " -Wall"
32
32
 
33
- $srcs = ["event.c"]
33
+ $srcs = ["event.c", "backend/backend.c"]
34
34
  $VPATH << "$(srcdir)/backend"
35
35
 
36
36
  if have_library('uring') and have_header('liburing.h')
data/ext/event/kqueue.o CHANGED
Binary file
data/lib/event.rb CHANGED
@@ -19,7 +19,7 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require_relative 'event/version'
22
- require_relative 'event/backend/select'
22
+ require_relative 'event/backend'
23
23
 
24
24
  module Event
25
25
  # These constants are the same as those defined in IO.
@@ -0,0 +1,49 @@
1
+ # Copyright, 2021, by Samuel G. D. Williams. <http://www.codeotaku.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ require_relative 'backend/select'
22
+
23
+ module Event
24
+ module Backend
25
+ def self.default(env = ENV)
26
+ if backend = env['EVENT_BACKEND']&.to_sym
27
+ if Event::Backend.const_defined?(backend)
28
+ return Event::Backend.const_get(backend)
29
+ else
30
+ warn "Could not find EVENT_BACKEND=#{backend}!"
31
+ end
32
+ end
33
+
34
+ if self.const_defined?(:URing)
35
+ return Event::Backend::URing
36
+ elsif self.const_defined?(:KQueue)
37
+ return Event::Backend::KQueue
38
+ elsif self.const_defined?(:EPoll)
39
+ return Event::Backend::EPoll
40
+ else
41
+ return Event::Backend::Select
42
+ end
43
+ end
44
+
45
+ def self.new(...)
46
+ default.new(...)
47
+ end
48
+ end
49
+ end
@@ -28,6 +28,12 @@ module Event
28
28
  @writable = {}
29
29
  end
30
30
 
31
+ def close
32
+ @loop = nil
33
+ @readable = nil
34
+ @writable = nil
35
+ end
36
+
31
37
  def io_wait(fiber, io, events)
32
38
  remove_readable = remove_writable = false
33
39
 
@@ -42,7 +48,6 @@ module Event
42
48
  end
43
49
 
44
50
  @loop.transfer
45
-
46
51
  ensure
47
52
  @readable.delete(io) if remove_readable
48
53
  @writable.delete(io) if remove_writable
@@ -64,7 +69,7 @@ module Event
64
69
  end
65
70
 
66
71
  ready.each do |fiber, events|
67
- fiber.transfer(events)
72
+ fiber.transfer(events) if fiber.alive?
68
73
  end
69
74
  end
70
75
  end
@@ -31,6 +31,15 @@ module Event
31
31
  @priority = {}
32
32
  end
33
33
 
34
+ def close
35
+ if @selector.nil?
36
+ raise "Selector already closed!"
37
+ end
38
+
39
+ @selector.close
40
+ @selector = nil
41
+ end
42
+
34
43
  def io_wait(fiber, io, events)
35
44
  register_readable(fiber, io, events)
36
45
  end
data/lib/event/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Event
2
- VERSION = "0.2.3"
2
+ VERSION = "0.4.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: event
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-05-03 00:00:00.000000000 Z
11
+ date: 2021-05-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bake
@@ -74,6 +74,8 @@ extensions:
74
74
  extra_rdoc_files: []
75
75
  files:
76
76
  - ext/event/Makefile
77
+ - ext/event/backend.o
78
+ - ext/event/backend/backend.c
77
79
  - ext/event/backend/backend.h
78
80
  - ext/event/backend/epoll.c
79
81
  - ext/event/backend/epoll.h
@@ -90,6 +92,7 @@ files:
90
92
  - ext/event/kqueue.o
91
93
  - ext/event/mkmf.log
92
94
  - lib/event.rb
95
+ - lib/event/backend.rb
93
96
  - lib/event/backend/select.rb
94
97
  - lib/event/debug/selector.rb
95
98
  - lib/event/selector.rb
@@ -113,7 +116,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
116
  - !ruby/object:Gem::Version
114
117
  version: '0'
115
118
  requirements: []
116
- rubygems_version: 3.2.15
119
+ rubygems_version: 3.2.3
117
120
  signing_key:
118
121
  specification_version: 4
119
122
  summary: An event loop.