lightio 0.2.2 → 0.3.0
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 +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"
|