lightio 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +2 -1
- data/Gemfile +6 -0
- data/Gemfile.lock +47 -3
- data/Guardfile +10 -0
- data/README.md +1 -1
- data/bin/_guard-core +21 -0
- data/bin/guard +21 -0
- data/lib/lightio/core/backend/nio.rb +14 -2
- data/lib/lightio/core/beam.rb +22 -5
- data/lib/lightio/core/ioloop.rb +14 -26
- data/lib/lightio/core/light_fiber.rb +14 -0
- data/lib/lightio/library/io.rb +87 -14
- data/lib/lightio/library/kernel_ext.rb +2 -2
- data/lib/lightio/library/mutex.rb +62 -0
- data/lib/lightio/library/queue.rb +2 -2
- data/lib/lightio/library/sized_queue.rb +64 -0
- data/lib/lightio/library/socket.rb +32 -3
- data/lib/lightio/library/thread.rb +295 -0
- data/lib/lightio/library/threads_wait.rb +59 -0
- data/lib/lightio/library.rb +3 -0
- data/lib/lightio/version.rb +1 -1
- data/lib/lightio/watchers/io.rb +68 -15
- data/lib/lightio/wrap.rb +13 -23
- data/lightio.gemspec +1 -1
- metadata +11 -4
@@ -0,0 +1,64 @@
|
|
1
|
+
require_relative 'queue'
|
2
|
+
|
3
|
+
module LightIO::Library
|
4
|
+
class SizedQueue < LightIO::Library::Queue
|
5
|
+
attr_accessor :max
|
6
|
+
|
7
|
+
def initialize(max)
|
8
|
+
raise ArgumentError, 'queue size must be positive' unless max > 0
|
9
|
+
super()
|
10
|
+
@max = max
|
11
|
+
@enqueue_waiters = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def push(object)
|
15
|
+
raise ClosedQueueError, "queue closed" if @close
|
16
|
+
if size >= max
|
17
|
+
future = LightIO::Future.new
|
18
|
+
@enqueue_waiters << future
|
19
|
+
future.value
|
20
|
+
end
|
21
|
+
super
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
alias enq push
|
26
|
+
alias << push
|
27
|
+
|
28
|
+
def pop(non_block=false)
|
29
|
+
result = super
|
30
|
+
check_release_enqueue_waiter
|
31
|
+
result
|
32
|
+
end
|
33
|
+
|
34
|
+
alias deq pop
|
35
|
+
alias shift pop
|
36
|
+
|
37
|
+
def clear
|
38
|
+
result = super
|
39
|
+
check_release_enqueue_waiter
|
40
|
+
result
|
41
|
+
end
|
42
|
+
|
43
|
+
def max=(value)
|
44
|
+
@max = value
|
45
|
+
check_release_enqueue_waiter if size < max
|
46
|
+
end
|
47
|
+
|
48
|
+
def num_waiting
|
49
|
+
super + @enqueue_waiters.size
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
def check_release_enqueue_waiter
|
54
|
+
if @enqueue_waiters.any?
|
55
|
+
future = LightIO::Future.new
|
56
|
+
LightIO::IOloop.current.add_callback {
|
57
|
+
@enqueue_waiters.shift.transfer
|
58
|
+
future.transfer
|
59
|
+
}
|
60
|
+
future.value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -65,9 +65,11 @@ module LightIO::Library
|
|
65
65
|
class BasicSocket < IO
|
66
66
|
include LightIO::Wrap::IOWrapper
|
67
67
|
wrap ::BasicSocket
|
68
|
-
|
69
68
|
wrap_blocking_methods :recv, :recvmsg, :sendmsg
|
70
69
|
|
70
|
+
extend Forwardable
|
71
|
+
def_delegators :@io_watcher, :wait, :wait_writable
|
72
|
+
|
71
73
|
def shutdown(*args)
|
72
74
|
# close watcher before io shutdown
|
73
75
|
@io_watcher.close
|
@@ -99,13 +101,40 @@ module LightIO::Library
|
|
99
101
|
@io.sys_accept
|
100
102
|
end
|
101
103
|
|
102
|
-
|
104
|
+
Option = ::Socket::Option
|
105
|
+
UDPSource = ::Socket::UDPSource
|
106
|
+
SocketError = ::SocketError
|
107
|
+
|
108
|
+
class Ifaddr
|
109
|
+
include LightIO::Wrap::Wrapper
|
110
|
+
wrap ::Socket
|
111
|
+
|
112
|
+
def addr
|
113
|
+
@io.addr && Addrinfo._wrap(@io.addr)
|
114
|
+
end
|
115
|
+
|
116
|
+
def broadaddr
|
117
|
+
@io.broadaddr && Addrinfo._wrap(@io.broadaddr)
|
118
|
+
end
|
119
|
+
|
120
|
+
def dstaddr
|
121
|
+
@io.dstaddr && Addrinfo._wrap(@io.dstaddr)
|
122
|
+
end
|
123
|
+
|
124
|
+
def netmask
|
125
|
+
@io.netmask && Addrinfo._wrap(@io.netmask)
|
126
|
+
end
|
127
|
+
end
|
103
128
|
|
104
129
|
class << self
|
105
130
|
## implement ::Socket class methods
|
106
|
-
wrap_methods_run_in_threads_pool :getaddrinfo, :gethostbyaddr, :gethostbyname, :gethostname,
|
131
|
+
wrap_methods_run_in_threads_pool :getaddrinfo, :gethostbyaddr, :gethostbyname, :gethostname,
|
107
132
|
:getnameinfo, :getservbyname
|
108
133
|
|
134
|
+
def getifaddrs
|
135
|
+
raw_class.getifaddrs.map {|ifaddr| Ifaddr._wrap(ifaddr)}
|
136
|
+
end
|
137
|
+
|
109
138
|
def socketpair(domain, type, protocol)
|
110
139
|
raw_class.socketpair(domain, type, protocol).map {|s| _wrap(s)}
|
111
140
|
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require_relative 'mutex'
|
3
|
+
require_relative 'queue'
|
4
|
+
|
5
|
+
module LightIO::Library
|
6
|
+
class ThreadGroup
|
7
|
+
include LightIO::Wrap::Wrapper
|
8
|
+
wrap ::ThreadGroup
|
9
|
+
|
10
|
+
Default = ThreadGroup._wrap(::ThreadGroup::Default)
|
11
|
+
|
12
|
+
def add(thread)
|
13
|
+
if @io.enclosed?
|
14
|
+
raise ThreadError, "can't move from the enclosed thread group"
|
15
|
+
elsif thread.is_a?(LightIO::Library::Thread)
|
16
|
+
# let thread decide how to add to group
|
17
|
+
thread.send(:add_to_group, self)
|
18
|
+
else
|
19
|
+
@io.add(thread)
|
20
|
+
end
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def list
|
25
|
+
@io.list + threads
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
def threads
|
30
|
+
@threads ||= []
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
class Thread
|
36
|
+
RAW_THREAD = ::Thread
|
37
|
+
|
38
|
+
# constants
|
39
|
+
ThreadError = ::ThreadError
|
40
|
+
Queue = LightIO::Library::Queue
|
41
|
+
Backtrace = ::Thread::Backtrace
|
42
|
+
SizedQueue = LightIO::Library::SizedQueue
|
43
|
+
|
44
|
+
@current_thread = nil
|
45
|
+
|
46
|
+
module FallbackHelper
|
47
|
+
module ClassMethods
|
48
|
+
def fallback_method(obj, method, warning_text)
|
49
|
+
define_method method do |*args|
|
50
|
+
warn warning_text
|
51
|
+
obj.public_send method, *args
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def fallback_thread_class_methods(*methods)
|
56
|
+
methods.each {|m| fallback_method(RAW_THREAD.main, m, "This method is fallback to native Thread class,"\
|
57
|
+
" it may cause unexpected behaviour,"\
|
58
|
+
" open issues on https://github.com/socketry/lightio/issues"\
|
59
|
+
" if this behaviour not approach you purpose")}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
include ClassMethods
|
64
|
+
|
65
|
+
def fallback_main_thread_methods(*methods)
|
66
|
+
methods.each {|m| fallback_method(main, m, "This method is fallback to native main thread,"\
|
67
|
+
" it may cause unexpected behaviour,"\
|
68
|
+
" open issues on https://github.com/socketry/lightio/issues"\
|
69
|
+
" if this behaviour not approach you purpose")}
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.included(base)
|
73
|
+
base.send :extend, ClassMethods
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class << self
|
78
|
+
extend Forwardable
|
79
|
+
def_delegators :'LightIO::Library::Thread::RAW_THREAD', :DEBUG, :DEBUG=
|
80
|
+
|
81
|
+
include FallbackHelper
|
82
|
+
fallback_thread_class_methods :abort_on_exception, :abort_on_exception=
|
83
|
+
|
84
|
+
def fork(*args, &blk)
|
85
|
+
obj = allocate
|
86
|
+
obj.send(:init_core, *args, &blk)
|
87
|
+
obj
|
88
|
+
end
|
89
|
+
|
90
|
+
alias start fork
|
91
|
+
|
92
|
+
def kill(thr)
|
93
|
+
thr.kill
|
94
|
+
end
|
95
|
+
|
96
|
+
def current
|
97
|
+
return main if LightIO::Core::LightFiber.is_root?(Fiber.current)
|
98
|
+
@current_thread || RAW_THREAD.current
|
99
|
+
end
|
100
|
+
|
101
|
+
def exclusive(&blk)
|
102
|
+
@thread_mutex.synchronize(&blk)
|
103
|
+
end
|
104
|
+
|
105
|
+
def list
|
106
|
+
thread_list = []
|
107
|
+
threads.keys.each {|id|
|
108
|
+
begin
|
109
|
+
thr = ObjectSpace._id2ref(id)
|
110
|
+
unless thr.alive?
|
111
|
+
# manually remove thr from threads
|
112
|
+
thr.kill
|
113
|
+
next
|
114
|
+
end
|
115
|
+
thread_list << thr
|
116
|
+
rescue RangeError
|
117
|
+
# mean object is recycled
|
118
|
+
# just wait ruby GC call finalizer to remove it from threads
|
119
|
+
next
|
120
|
+
end
|
121
|
+
}
|
122
|
+
thread_list
|
123
|
+
end
|
124
|
+
|
125
|
+
def pass
|
126
|
+
LightIO::Beam.pass
|
127
|
+
end
|
128
|
+
|
129
|
+
alias stop pass
|
130
|
+
|
131
|
+
def finalizer(object_id)
|
132
|
+
proc {threads.delete(object_id)}
|
133
|
+
end
|
134
|
+
|
135
|
+
def main
|
136
|
+
RAW_THREAD.main
|
137
|
+
end
|
138
|
+
|
139
|
+
private
|
140
|
+
|
141
|
+
# threads and threads variables
|
142
|
+
def threads
|
143
|
+
@threads ||= {}
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
extend Forwardable
|
148
|
+
|
149
|
+
def initialize(*args, &blk)
|
150
|
+
init_core(*args, &blk)
|
151
|
+
end
|
152
|
+
|
153
|
+
@thread_mutex = LightIO::Library::Mutex.new
|
154
|
+
def_delegators :@beam, :alive?, :value
|
155
|
+
|
156
|
+
fallback_main_thread_methods :abort_on_exception,
|
157
|
+
:abort_on_exception=,
|
158
|
+
:handle_interrupt,
|
159
|
+
:pending_interrupt,
|
160
|
+
:add_trace_func,
|
161
|
+
:backtrace,
|
162
|
+
:backtrace_locations,
|
163
|
+
:priority,
|
164
|
+
:priority=,
|
165
|
+
:safe_level
|
166
|
+
|
167
|
+
def kill
|
168
|
+
@beam.kill && self
|
169
|
+
end
|
170
|
+
|
171
|
+
alias exit kill
|
172
|
+
alias terminate kill
|
173
|
+
|
174
|
+
def status
|
175
|
+
if Thread.current == self
|
176
|
+
'run'
|
177
|
+
elsif alive?
|
178
|
+
@beam.error.nil? ? 'sleep' : 'abouting'
|
179
|
+
else
|
180
|
+
@beam.error.nil? ? false : nil
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def thread_variables
|
185
|
+
thread_values.keys
|
186
|
+
end
|
187
|
+
|
188
|
+
def thread_variable_get(name)
|
189
|
+
thread_values[name.to_sym]
|
190
|
+
end
|
191
|
+
|
192
|
+
def thread_variable_set(name, value)
|
193
|
+
thread_values[name.to_sym] = value
|
194
|
+
end
|
195
|
+
|
196
|
+
def thread_variable?(key)
|
197
|
+
thread_values.key?(key)
|
198
|
+
end
|
199
|
+
|
200
|
+
def [](name)
|
201
|
+
fiber_values[name.to_sym]
|
202
|
+
end
|
203
|
+
|
204
|
+
def []=(name, val)
|
205
|
+
fiber_values[name.to_sym] = val
|
206
|
+
end
|
207
|
+
|
208
|
+
def group
|
209
|
+
@group
|
210
|
+
end
|
211
|
+
|
212
|
+
def inspect
|
213
|
+
"#<LightIO::Library::Thread:0x00#{object_id.to_s(16)} #{status}>"
|
214
|
+
end
|
215
|
+
|
216
|
+
def join(limit=nil)
|
217
|
+
@beam.join(limit) && self
|
218
|
+
end
|
219
|
+
|
220
|
+
def key?(sym)
|
221
|
+
fiber_values.has_key?(sym)
|
222
|
+
end
|
223
|
+
|
224
|
+
def keys
|
225
|
+
fiber_values.keys
|
226
|
+
end
|
227
|
+
|
228
|
+
def raise(exception, message=nil, backtrace=nil)
|
229
|
+
@beam.raise(LightIO::Beam::BeamError.new(exception), message, backtrace)
|
230
|
+
end
|
231
|
+
|
232
|
+
def run
|
233
|
+
Kernel.raise ThreadError, 'killed thread' unless alive?
|
234
|
+
Thread.pass
|
235
|
+
end
|
236
|
+
|
237
|
+
alias wakeup run
|
238
|
+
|
239
|
+
def stop?
|
240
|
+
!alive? || status == 'sleep'
|
241
|
+
end
|
242
|
+
|
243
|
+
private
|
244
|
+
def init_core(*args, &blk)
|
245
|
+
@beam = LightIO::Beam.new(*args, &blk)
|
246
|
+
@beam.on_dead = proc {on_dead}
|
247
|
+
@beam.on_transfer = proc {|from, to| on_transfer(from, to)}
|
248
|
+
# register this thread
|
249
|
+
thread_values
|
250
|
+
# add self to ThreadGroup::Default
|
251
|
+
add_to_group(ThreadGroup::Default)
|
252
|
+
# remove thread and thread variables
|
253
|
+
ObjectSpace.define_finalizer(self, self.class.finalizer(self.object_id))
|
254
|
+
end
|
255
|
+
|
256
|
+
# add self to thread group
|
257
|
+
def add_to_group(group)
|
258
|
+
# remove from old group
|
259
|
+
remove_from_group
|
260
|
+
@group = group
|
261
|
+
@group.send(:threads) << self
|
262
|
+
end
|
263
|
+
|
264
|
+
# remove thread from group when dead
|
265
|
+
def remove_from_group
|
266
|
+
@group.send(:threads).delete(self) if @group
|
267
|
+
end
|
268
|
+
|
269
|
+
def on_dead
|
270
|
+
# release references
|
271
|
+
remove_from_group
|
272
|
+
end
|
273
|
+
|
274
|
+
def on_transfer(from, to)
|
275
|
+
Thread.instance_variable_set(:@current_thread, self)
|
276
|
+
end
|
277
|
+
|
278
|
+
def thread_values
|
279
|
+
Thread.send(:threads)[object_id] ||= {}
|
280
|
+
end
|
281
|
+
|
282
|
+
def fibers_and_values
|
283
|
+
@fibers_and_values ||= {}
|
284
|
+
end
|
285
|
+
|
286
|
+
def fiber_values
|
287
|
+
beam_or_fiber = LightIO::Beam.current
|
288
|
+
# only consider non-root fiber
|
289
|
+
if !beam_or_fiber.instance_of?(::Fiber) || LightIO::LightFiber.is_root?(beam_or_fiber)
|
290
|
+
beam_or_fiber = @beam
|
291
|
+
end
|
292
|
+
fibers_and_values[beam_or_fiber] ||= {}
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'thwait'
|
2
|
+
|
3
|
+
module LightIO::Library
|
4
|
+
class ThreadsWait
|
5
|
+
ErrNoWaitingThread = ::ThreadsWait::ErrNoWaitingThread
|
6
|
+
ErrNoFinishedThread = ::ThreadsWait::ErrNoFinishedThread
|
7
|
+
|
8
|
+
attr_reader :threads
|
9
|
+
|
10
|
+
def initialize(*threads)
|
11
|
+
@threads = threads
|
12
|
+
end
|
13
|
+
|
14
|
+
def all_waits
|
15
|
+
until empty?
|
16
|
+
thr = next_wait
|
17
|
+
yield thr if block_given?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def empty?
|
22
|
+
@threads.empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
def finished?
|
26
|
+
@threads.any? {|thr| !thr.alive?}
|
27
|
+
end
|
28
|
+
|
29
|
+
def join(*threads)
|
30
|
+
join_nowait(*threads)
|
31
|
+
next_wait
|
32
|
+
end
|
33
|
+
|
34
|
+
def join_nowait(*threads)
|
35
|
+
@threads.concat(threads)
|
36
|
+
end
|
37
|
+
|
38
|
+
def next_wait(nonblock=nil)
|
39
|
+
raise ThreadsWait::ErrNoWaitingThread, 'No threads for waiting.' if empty?
|
40
|
+
@threads.each do |thr|
|
41
|
+
if thr.alive? && nonblock
|
42
|
+
next
|
43
|
+
elsif thr.alive?
|
44
|
+
thr.join
|
45
|
+
end
|
46
|
+
# thr should dead
|
47
|
+
@threads.delete(thr)
|
48
|
+
return thr
|
49
|
+
end
|
50
|
+
raise ThreadsWait::ErrNoFinishedThread, 'No finished threads.'
|
51
|
+
end
|
52
|
+
|
53
|
+
class << self
|
54
|
+
def all_waits(*threads, &blk)
|
55
|
+
new(*threads).all_waits(&blk)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/lightio/library.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
require_relative 'library/queue'
|
2
|
+
require_relative 'library/sized_queue'
|
2
3
|
require_relative 'library/kernel_ext'
|
3
4
|
require_relative 'library/timeout'
|
4
5
|
require_relative 'library/io'
|
5
6
|
require_relative 'library/socket'
|
7
|
+
require_relative 'library/thread'
|
8
|
+
require_relative 'library/threads_wait'
|
6
9
|
|
7
10
|
module LightIO
|
8
11
|
# Library include modules can cooperative with LightIO::Beam
|
data/lib/lightio/version.rb
CHANGED
data/lib/lightio/watchers/io.rb
CHANGED
@@ -21,12 +21,17 @@ module LightIO::Watchers
|
|
21
21
|
@io = io
|
22
22
|
@ioloop = LightIO::Core::IOloop.current
|
23
23
|
@waiting = false
|
24
|
-
# NIO monitor
|
25
|
-
@monitor = @ioloop.add_io_wait(@io, interests) {callback_on_waiting}
|
26
24
|
ObjectSpace.define_finalizer(self, self.class.finalizer(@monitor))
|
27
25
|
@error = nil
|
28
26
|
end
|
29
27
|
|
28
|
+
# NIO::Monitor
|
29
|
+
def monitor(interests=:rw)
|
30
|
+
@monitor ||= begin
|
31
|
+
@ioloop.add_io_wait(@io, interests) {callback_on_waiting}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
30
35
|
class << self
|
31
36
|
def finalizer(monitor)
|
32
37
|
proc {monitor.close if monitor && !monitor.close?}
|
@@ -34,8 +39,19 @@ module LightIO::Watchers
|
|
34
39
|
end
|
35
40
|
|
36
41
|
extend Forwardable
|
37
|
-
def_delegators
|
42
|
+
def_delegators :monitor, :interests, :interests=, :closed?
|
43
|
+
|
44
|
+
def readable?
|
45
|
+
check_monitor_read
|
46
|
+
monitor.readable?
|
47
|
+
end
|
38
48
|
|
49
|
+
def writable?
|
50
|
+
check_monitor_write
|
51
|
+
monitor.writable?
|
52
|
+
end
|
53
|
+
|
54
|
+
alias :writeable? :writable?
|
39
55
|
|
40
56
|
# Blocking until io is readable
|
41
57
|
# @param [Numeric] timeout return nil after timeout seconds, otherwise return self
|
@@ -53,9 +69,10 @@ module LightIO::Watchers
|
|
53
69
|
|
54
70
|
def wait(timeout=nil, mode=:read)
|
55
71
|
LightIO::Timeout.timeout(timeout) do
|
56
|
-
|
57
|
-
|
58
|
-
|
72
|
+
check_monitor(mode)
|
73
|
+
in_waiting(mode) do
|
74
|
+
wait_in_ioloop
|
75
|
+
end
|
59
76
|
self
|
60
77
|
end
|
61
78
|
rescue Timeout::Error
|
@@ -64,7 +81,7 @@ module LightIO::Watchers
|
|
64
81
|
|
65
82
|
def close
|
66
83
|
return if closed?
|
67
|
-
|
84
|
+
monitor.close
|
68
85
|
@error = IOError.new('closed stream')
|
69
86
|
callback_on_waiting
|
70
87
|
end
|
@@ -80,34 +97,70 @@ module LightIO::Watchers
|
|
80
97
|
end
|
81
98
|
|
82
99
|
private
|
100
|
+
def check_monitor(mode)
|
101
|
+
case mode
|
102
|
+
when :read
|
103
|
+
check_monitor_read
|
104
|
+
when :write
|
105
|
+
check_monitor_write
|
106
|
+
when :read_write
|
107
|
+
check_monitor_read_write
|
108
|
+
else
|
109
|
+
raise ArgumentError, "get unknown value #{mode}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def check_monitor_read
|
114
|
+
if monitor(:r).interests == :w
|
115
|
+
monitor.interests = :rw
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def check_monitor_write
|
120
|
+
if monitor(:w).interests == :r
|
121
|
+
monitor.interests = :rw
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def check_monitor_read_write
|
126
|
+
if monitor(:rw).interests != :rw
|
127
|
+
monitor.interests = :rw
|
128
|
+
end
|
129
|
+
end
|
83
130
|
|
84
131
|
# Blocking until io interests is satisfied
|
85
132
|
def wait_in_ioloop
|
86
133
|
raise LightIO::Error, "Watchers::IO can't cross threads" if @ioloop != LightIO::Core::IOloop.current
|
87
134
|
raise EOFError, "can't wait closed IO watcher" if @monitor.closed?
|
88
|
-
@waiting = true
|
89
135
|
@ioloop.wait(self)
|
136
|
+
end
|
137
|
+
|
138
|
+
def in_waiting(mode)
|
139
|
+
@waiting = mode
|
140
|
+
yield
|
90
141
|
@waiting = false
|
91
142
|
end
|
92
143
|
|
93
144
|
def callback_on_waiting
|
94
145
|
# only call callback on waiting
|
95
|
-
return unless
|
146
|
+
return unless io_is_ready?
|
96
147
|
if @error
|
97
148
|
# if error occurred in io waiting, send it to callback, see IOloop#wait
|
98
|
-
callback
|
149
|
+
callback&.call(LightIO::Core::Beam::BeamError.new(@error))
|
99
150
|
else
|
100
|
-
callback
|
151
|
+
callback&.call
|
101
152
|
end
|
102
153
|
end
|
103
154
|
|
104
155
|
def io_is_ready?
|
105
|
-
|
156
|
+
return false unless @waiting
|
157
|
+
return true if closed?
|
158
|
+
if @waiting == :r
|
106
159
|
readable?
|
107
|
-
elsif
|
108
|
-
|
160
|
+
elsif @waiting == :w
|
161
|
+
writable?
|
109
162
|
else
|
110
|
-
readable? ||
|
163
|
+
readable? || writable?
|
111
164
|
end
|
112
165
|
end
|
113
166
|
end
|
data/lib/lightio/wrap.rb
CHANGED
@@ -85,26 +85,16 @@ module LightIO::Wrap
|
|
85
85
|
#
|
86
86
|
# @param [Symbol] method method name, example: wait_nonblock
|
87
87
|
# @param [args] args arguments pass to method
|
88
|
-
def wait_nonblock(method, *args
|
88
|
+
def wait_nonblock(method, *args)
|
89
89
|
loop do
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
@io_watcher.wait_readable
|
99
|
-
when :wait_writable
|
100
|
-
@io_watcher.wait_writable
|
101
|
-
else
|
102
|
-
return result
|
103
|
-
end
|
104
|
-
rescue RAW_IO::WaitReadable
|
105
|
-
@io_watcher.wait_readable
|
106
|
-
rescue RAW_IO::WaitWritable
|
107
|
-
@io_watcher.wait_writable
|
90
|
+
result = @io.__send__(method, *args, exception: false)
|
91
|
+
case result
|
92
|
+
when :wait_readable
|
93
|
+
@io_watcher.wait_readable
|
94
|
+
when :wait_writable
|
95
|
+
@io_watcher.wait_writable
|
96
|
+
else
|
97
|
+
return result
|
108
98
|
end
|
109
99
|
end
|
110
100
|
end
|
@@ -115,14 +105,14 @@ module LightIO::Wrap
|
|
115
105
|
# wrap blocking method with "#{method}_nonblock"
|
116
106
|
#
|
117
107
|
# @param [Symbol] method method name, example: wait
|
118
|
-
def wrap_blocking_method(method
|
108
|
+
def wrap_blocking_method(method)
|
119
109
|
define_method method do |*args|
|
120
|
-
wait_nonblock(:"#{method}_nonblock", *args
|
110
|
+
wait_nonblock(:"#{method}_nonblock", *args)
|
121
111
|
end
|
122
112
|
end
|
123
113
|
|
124
|
-
def wrap_blocking_methods(*methods
|
125
|
-
methods.each {|m| wrap_blocking_method(m
|
114
|
+
def wrap_blocking_methods(*methods)
|
115
|
+
methods.each {|m| wrap_blocking_method(m)}
|
126
116
|
end
|
127
117
|
end
|
128
118
|
|
data/lightio.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_runtime_dependency "nio4r", "~> 2.
|
24
|
+
spec.add_runtime_dependency "nio4r", "~> 2.2"
|
25
25
|
spec.add_development_dependency "bundler", "~> 1.16"
|
26
26
|
spec.add_development_dependency "rake", "~> 10.0"
|
27
27
|
spec.add_development_dependency "rspec", "~> 3.0"
|