lightio 0.3.2 → 0.4.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +5 -3
- data/Rakefile +9 -1
- data/examples/echo_server.rb +2 -0
- data/examples/echo_server_with_raw_socket.rb +2 -1
- data/examples/monkey_patch.rb +26 -0
- data/lib/lightio.rb +3 -0
- data/lib/lightio/core/beam.rb +1 -1
- data/lib/lightio/core/ioloop.rb +11 -5
- data/lib/lightio/library.rb +2 -0
- data/lib/lightio/library/base.rb +96 -0
- data/lib/lightio/library/file.rb +9 -0
- data/lib/lightio/library/io.rb +14 -85
- data/lib/lightio/library/queue.rb +4 -1
- data/lib/lightio/library/sized_queue.rb +3 -0
- data/lib/lightio/library/socket.rb +93 -127
- data/lib/lightio/library/thread.rb +153 -122
- data/lib/lightio/library/threads_wait.rb +7 -8
- data/lib/lightio/module.rb +11 -0
- data/lib/lightio/module/base.rb +40 -0
- data/lib/lightio/module/file.rb +10 -0
- data/lib/lightio/module/io.rb +88 -0
- data/lib/lightio/module/socket.rb +165 -0
- data/lib/lightio/module/thread.rb +76 -0
- data/lib/lightio/module/threads_wait.rb +13 -0
- data/lib/lightio/monkey.rb +150 -0
- data/lib/lightio/raw_proxy.rb +24 -0
- data/lib/lightio/version.rb +1 -1
- data/lib/lightio/wrap.rb +16 -63
- data/lightio.gemspec +2 -0
- metadata +17 -6
- data/lib/lightio/library/mutex.rb +0 -93
@@ -4,196 +4,162 @@ module LightIO::Library
|
|
4
4
|
|
5
5
|
class Addrinfo
|
6
6
|
include LightIO::Wrap::Wrapper
|
7
|
-
|
8
|
-
|
9
|
-
module WrapperHelper
|
10
|
-
protected
|
11
|
-
def wrap_socket_method(method)
|
12
|
-
define_method method do |*args|
|
13
|
-
socket = Socket._wrap(@io.send(method, *args))
|
14
|
-
if block_given?
|
15
|
-
begin
|
16
|
-
yield socket
|
17
|
-
ensure
|
18
|
-
socket.close
|
19
|
-
end
|
20
|
-
else
|
21
|
-
socket
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def wrap_socket_methods(*methods)
|
27
|
-
methods.each {|m| wrap_socket_method(m)}
|
28
|
-
end
|
29
|
-
|
30
|
-
def wrap_addrinfo_return_method(method)
|
31
|
-
define_method method do |*args|
|
32
|
-
result = (@io || raw_class).send(method, *args)
|
33
|
-
if result.is_a?(raw_class)
|
34
|
-
_wrap(result)
|
35
|
-
elsif result.respond_to?(:map)
|
36
|
-
result.map {|r| _wrap(r)}
|
37
|
-
else
|
38
|
-
result
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
7
|
+
include Base
|
8
|
+
mock ::Addrinfo
|
42
9
|
|
43
|
-
|
44
|
-
methods.each {|m| wrap_addrinfo_return_method(m)}
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
extend WrapperHelper
|
10
|
+
extend LightIO::Module::Addrinfo::WrapperHelper
|
49
11
|
|
50
12
|
wrap_socket_methods :bind, :connect, :connect_from, :connect_to, :listen
|
51
|
-
|
52
13
|
wrap_addrinfo_return_methods :family_addrinfo, :ipv6_to_ipv4
|
53
|
-
|
54
|
-
class << self
|
55
|
-
extend WrapperHelper
|
56
|
-
|
57
|
-
def foreach(*args, &block)
|
58
|
-
Addrinfo.getaddrinfo(*args).each(&block)
|
59
|
-
end
|
60
|
-
|
61
|
-
wrap_addrinfo_return_methods :getaddrinfo, :ip, :udp, :tcp, :unix
|
62
|
-
end
|
63
14
|
end
|
64
15
|
|
65
|
-
class BasicSocket < IO
|
16
|
+
class BasicSocket < LightIO::Library::IO
|
17
|
+
include Base
|
66
18
|
include LightIO::Wrap::IOWrapper
|
67
|
-
|
19
|
+
mock ::BasicSocket
|
20
|
+
extend LightIO::Module::BasicSocket::ClassMethods
|
21
|
+
|
68
22
|
wrap_blocking_methods :recv, :recvmsg, :sendmsg
|
69
23
|
|
70
24
|
extend Forwardable
|
71
|
-
def_delegators
|
25
|
+
def_delegators :io_watcher, :wait, :wait_writable
|
72
26
|
|
73
27
|
def shutdown(*args)
|
74
28
|
# close watcher before io shutdown
|
75
|
-
|
76
|
-
@
|
77
|
-
end
|
78
|
-
|
79
|
-
class << self
|
80
|
-
def for_fd(fd)
|
81
|
-
self._wrap(raw_class.for_fd(fd))
|
82
|
-
end
|
29
|
+
io_watcher.close
|
30
|
+
@obj.shutdown(*args)
|
83
31
|
end
|
84
32
|
end
|
85
33
|
|
86
34
|
class Socket < BasicSocket
|
87
|
-
include
|
35
|
+
include Base
|
88
36
|
include LightIO::Wrap::IOWrapper
|
89
|
-
|
37
|
+
mock ::Socket
|
38
|
+
extend LightIO::Module::Socket::ClassMethods
|
90
39
|
|
91
|
-
wrap_blocking_methods :connect, :recvfrom
|
92
|
-
|
93
|
-
## implement ::Socket instance methods
|
94
|
-
def accept
|
95
|
-
socket, addrinfo = wait_nonblock(:accept_nonblock)
|
96
|
-
[self.class._wrap(socket), Addrinfo._wrap(addrinfo)]
|
97
|
-
end
|
98
|
-
|
99
|
-
def accept_nonblock(*args)
|
100
|
-
socket, addrinfo = @io.accept_nonblock(*args)
|
101
|
-
[self.class._wrap(socket), Addrinfo._wrap(addrinfo)]
|
102
|
-
end
|
40
|
+
wrap_blocking_methods :connect, :recvfrom, :accept
|
103
41
|
|
104
42
|
def sys_accept
|
105
|
-
|
106
|
-
@
|
43
|
+
io_watcher.wait_readable
|
44
|
+
@obj.sys_accept
|
107
45
|
end
|
108
46
|
|
109
|
-
Option = ::Socket::Option
|
110
|
-
UDPSource = ::Socket::UDPSource
|
111
|
-
SocketError = ::SocketError
|
112
|
-
|
113
47
|
class Ifaddr
|
114
|
-
include
|
115
|
-
|
48
|
+
include Base
|
49
|
+
mock ::Socket::Ifaddr
|
116
50
|
|
117
51
|
def addr
|
118
|
-
@
|
52
|
+
@obj.addr && Addrinfo._wrap(@obj.addr)
|
119
53
|
end
|
120
54
|
|
121
55
|
def broadaddr
|
122
|
-
@
|
56
|
+
@obj.broadaddr && Addrinfo._wrap(@obj.broadaddr)
|
123
57
|
end
|
124
58
|
|
125
59
|
def dstaddr
|
126
|
-
@
|
60
|
+
@obj.dstaddr && Addrinfo._wrap(@obj.dstaddr)
|
127
61
|
end
|
128
62
|
|
129
63
|
def netmask
|
130
|
-
@
|
64
|
+
@obj.netmask && Addrinfo._wrap(@obj.netmask)
|
131
65
|
end
|
132
66
|
end
|
133
67
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
def getifaddrs
|
140
|
-
raw_class.getifaddrs.map {|ifaddr| Ifaddr._wrap(ifaddr)}
|
141
|
-
end
|
142
|
-
|
143
|
-
def socketpair(domain, type, protocol)
|
144
|
-
raw_class.socketpair(domain, type, protocol).map {|s| _wrap(s)}
|
145
|
-
end
|
146
|
-
|
147
|
-
alias_method :pair, :socketpair
|
68
|
+
include ::Socket::Constants
|
69
|
+
Option = ::Socket::Option
|
70
|
+
UDPSource = ::Socket::UDPSource
|
71
|
+
SocketError = ::SocketError
|
72
|
+
Addrinfo = Addrinfo
|
148
73
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
_wrap(raw_class.unix_server_socket(path))
|
154
|
-
end
|
155
|
-
end
|
74
|
+
def accept
|
75
|
+
socket, addrinfo = wait_nonblock(:accept_nonblock)
|
76
|
+
[self.class._wrap(socket), Addrinfo._wrap(addrinfo)]
|
77
|
+
end
|
156
78
|
|
157
|
-
|
158
|
-
|
79
|
+
def accept_nonblock(*args)
|
80
|
+
socket, addrinfo = @obj.accept_nonblock(*args)
|
81
|
+
if socket.is_a?(Symbol)
|
82
|
+
[socket, nil]
|
83
|
+
else
|
84
|
+
[self.class._wrap(socket), Addrinfo._wrap(addrinfo)]
|
159
85
|
end
|
160
86
|
end
|
161
87
|
end
|
162
88
|
|
163
89
|
|
164
90
|
class IPSocket < BasicSocket
|
165
|
-
include
|
166
|
-
|
167
|
-
|
168
|
-
class << self
|
169
|
-
wrap_methods_run_in_threads_pool :getaddress
|
170
|
-
end
|
91
|
+
include Base
|
92
|
+
mock ::IPSocket
|
171
93
|
end
|
172
94
|
|
173
95
|
class TCPSocket < IPSocket
|
174
|
-
include
|
175
|
-
|
96
|
+
include Base
|
97
|
+
mock ::TCPSocket
|
176
98
|
wrap_methods_run_in_threads_pool :gethostbyname
|
177
99
|
end
|
178
100
|
|
179
101
|
class TCPServer < TCPSocket
|
180
|
-
include
|
181
|
-
|
102
|
+
include Base
|
103
|
+
mock ::TCPServer
|
182
104
|
|
183
|
-
## implement ::Socket instance methods
|
184
105
|
def accept
|
185
106
|
socket = wait_nonblock(:accept_nonblock)
|
186
107
|
TCPSocket._wrap(socket)
|
187
108
|
end
|
188
109
|
|
189
110
|
def accept_nonblock(*args)
|
190
|
-
socket = @
|
191
|
-
TCPSocket._wrap(socket)
|
111
|
+
socket = @obj.accept_nonblock(*args)
|
112
|
+
socket.is_a?(Symbol) ? socket : TCPSocket._wrap(socket)
|
192
113
|
end
|
193
114
|
|
194
115
|
def sys_accept
|
195
|
-
|
196
|
-
@
|
116
|
+
io_watcher.wait_readable
|
117
|
+
@obj.sys_accept
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class UDPSocket < IPSocket
|
122
|
+
include Base
|
123
|
+
mock ::UDPSocket
|
124
|
+
|
125
|
+
wrap_blocking_methods :recvfrom
|
126
|
+
end
|
127
|
+
|
128
|
+
class UNIXSocket < ::BasicSocket
|
129
|
+
include Base
|
130
|
+
mock ::UNIXSocket
|
131
|
+
|
132
|
+
def send_io(io)
|
133
|
+
io = io.instance_variable_get(:@obj) || io
|
134
|
+
@obj.send_io(io)
|
135
|
+
end
|
136
|
+
|
137
|
+
def recv_io(*args)
|
138
|
+
io = @obj.recv_io(*args)
|
139
|
+
if (wrapper = LightIO.const_get(io.class.to_s))
|
140
|
+
return wrapper._wrap(io) if wrapper.respond_to?(:_wrap)
|
141
|
+
end
|
142
|
+
io
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class UNIXServer < UNIXSocket
|
147
|
+
include Base
|
148
|
+
mock ::UNIXServer
|
149
|
+
|
150
|
+
def sys_accept
|
151
|
+
io_watcher.wait_readable
|
152
|
+
@obj.sys_accpet
|
153
|
+
end
|
154
|
+
|
155
|
+
def accept
|
156
|
+
socket = wait_nonblock(:accept_nonblock)
|
157
|
+
UNIXSocket._wrap(socket)
|
158
|
+
end
|
159
|
+
|
160
|
+
def accept_nonblock(*args)
|
161
|
+
socket = @obj.accept_nonblock(*args)
|
162
|
+
socket.is_a?(Symbol) ? socket : UNIXSocket._wrap(socket)
|
197
163
|
end
|
198
164
|
end
|
199
165
|
end
|
@@ -1,165 +1,66 @@
|
|
1
1
|
require 'thread'
|
2
|
-
require_relative 'mutex'
|
3
2
|
require_relative 'queue'
|
4
3
|
|
5
4
|
module LightIO::Library
|
6
5
|
class ThreadGroup
|
6
|
+
include Base
|
7
7
|
include LightIO::Wrap::Wrapper
|
8
|
-
|
9
|
-
|
10
|
-
Default = ThreadGroup._wrap(::ThreadGroup::Default)
|
8
|
+
mock ::ThreadGroup
|
11
9
|
|
12
10
|
def add(thread)
|
13
|
-
if @
|
11
|
+
if @obj.enclosed?
|
14
12
|
raise ThreadError, "can't move from the enclosed thread group"
|
15
13
|
elsif thread.is_a?(LightIO::Library::Thread)
|
16
14
|
# let thread decide how to add to group
|
17
15
|
thread.send(:add_to_group, self)
|
18
16
|
else
|
19
|
-
@
|
17
|
+
@obj.add(thread)
|
20
18
|
end
|
21
19
|
self
|
22
20
|
end
|
23
21
|
|
24
22
|
def list
|
25
|
-
@
|
23
|
+
@obj.list + threads
|
26
24
|
end
|
27
25
|
|
28
26
|
private
|
29
27
|
def threads
|
30
28
|
@threads ||= []
|
31
29
|
end
|
30
|
+
|
31
|
+
Default = ThreadGroup._wrap(::ThreadGroup::Default)
|
32
32
|
end
|
33
33
|
|
34
34
|
|
35
35
|
class Thread
|
36
|
-
RAW_THREAD = ::Thread
|
37
|
-
|
38
36
|
# constants
|
39
37
|
ThreadError = ::ThreadError
|
40
38
|
Queue = LightIO::Library::Queue
|
41
39
|
Backtrace = ::Thread::Backtrace
|
42
40
|
SizedQueue = LightIO::Library::SizedQueue
|
43
41
|
|
44
|
-
|
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
|
-
end
|
55
|
-
|
56
|
-
include ClassMethods
|
57
|
-
|
58
|
-
def fallback_main_thread_methods(*methods)
|
59
|
-
methods.each {|m| fallback_method(main, m, "This method is fallback to native main thread,"\
|
60
|
-
" it may cause unexpected behaviour,"\
|
61
|
-
" open issues on https://github.com/socketry/lightio/issues"\
|
62
|
-
" if this behaviour not approach you purpose")}
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.included(base)
|
66
|
-
base.send :extend, ClassMethods
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
class << self
|
71
|
-
extend Forwardable
|
72
|
-
def_delegators :'LightIO::Library::Thread::RAW_THREAD',
|
73
|
-
:DEBUG,
|
74
|
-
:DEBUG=,
|
75
|
-
:handle_interrupt,
|
76
|
-
:abort_on_exception,
|
77
|
-
:abort_on_exception=,
|
78
|
-
:pending_interrupt?
|
79
|
-
|
80
|
-
include FallbackHelper
|
81
|
-
|
82
|
-
def fork(*args, &blk)
|
83
|
-
obj = allocate
|
84
|
-
obj.send(:init_core, *args, &blk)
|
85
|
-
obj
|
86
|
-
end
|
87
|
-
|
88
|
-
alias start fork
|
89
|
-
|
90
|
-
def kill(thr)
|
91
|
-
thr.kill
|
92
|
-
end
|
93
|
-
|
94
|
-
def current
|
95
|
-
return main if LightIO::Core::LightFiber.is_root?(Fiber.current)
|
96
|
-
@current_thread || RAW_THREAD.current
|
97
|
-
end
|
98
|
-
|
99
|
-
def exclusive(&blk)
|
100
|
-
@thread_mutex.synchronize(&blk)
|
101
|
-
end
|
102
|
-
|
103
|
-
def list
|
104
|
-
thread_list = []
|
105
|
-
threads.keys.each {|id|
|
106
|
-
begin
|
107
|
-
thr = ObjectSpace._id2ref(id)
|
108
|
-
unless thr.alive?
|
109
|
-
# manually remove thr from threads
|
110
|
-
thr.kill
|
111
|
-
next
|
112
|
-
end
|
113
|
-
thread_list << thr
|
114
|
-
rescue RangeError
|
115
|
-
# mean object is recycled
|
116
|
-
# just wait ruby GC call finalizer to remove it from threads
|
117
|
-
next
|
118
|
-
end
|
119
|
-
}
|
120
|
-
thread_list
|
121
|
-
end
|
122
|
-
|
123
|
-
def pass
|
124
|
-
LightIO::Beam.pass
|
125
|
-
end
|
126
|
-
|
127
|
-
alias stop pass
|
128
|
-
|
129
|
-
def finalizer(object_id)
|
130
|
-
proc {threads.delete(object_id)}
|
131
|
-
end
|
132
|
-
|
133
|
-
def main
|
134
|
-
RAW_THREAD.main
|
135
|
-
end
|
136
|
-
|
137
|
-
private
|
138
|
-
|
139
|
-
# threads and threads variables
|
140
|
-
def threads
|
141
|
-
@threads ||= {}
|
142
|
-
end
|
143
|
-
end
|
42
|
+
extend Base::MockMethods
|
43
|
+
mock ::Thread
|
144
44
|
|
45
|
+
extend LightIO::Module::Thread::ClassMethods
|
145
46
|
extend Forwardable
|
146
47
|
|
147
48
|
def initialize(*args, &blk)
|
148
49
|
init_core(*args, &blk)
|
149
50
|
end
|
150
51
|
|
151
|
-
@thread_mutex = LightIO::Library::Mutex.new
|
152
52
|
def_delegators :@beam, :alive?, :value
|
153
53
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
54
|
+
def_delegators :"Thread.main",
|
55
|
+
:abort_on_exception,
|
56
|
+
:abort_on_exception=,
|
57
|
+
:pending_interrupt?,
|
58
|
+
:add_trace_func,
|
59
|
+
:backtrace,
|
60
|
+
:backtrace_locations,
|
61
|
+
:priority,
|
62
|
+
:priority=,
|
63
|
+
:safe_level
|
163
64
|
|
164
65
|
def kill
|
165
66
|
@beam.kill && self
|
@@ -169,7 +70,7 @@ module LightIO::Library
|
|
169
70
|
alias terminate kill
|
170
71
|
|
171
72
|
def status
|
172
|
-
if
|
73
|
+
if self.class.current == self
|
173
74
|
'run'
|
174
75
|
elsif alive?
|
175
76
|
@beam.error.nil? ? 'sleep' : 'abouting'
|
@@ -245,9 +146,9 @@ module LightIO::Library
|
|
245
146
|
# register this thread
|
246
147
|
thread_values
|
247
148
|
# add self to ThreadGroup::Default
|
248
|
-
add_to_group(ThreadGroup::Default)
|
149
|
+
add_to_group(LightIO::Library::ThreadGroup::Default)
|
249
150
|
# remove thread and thread variables
|
250
|
-
ObjectSpace.define_finalizer(self,
|
151
|
+
ObjectSpace.define_finalizer(self, LightIO::Library::Thread.finalizer(self.object_id))
|
251
152
|
end
|
252
153
|
|
253
154
|
# add self to thread group
|
@@ -288,5 +189,135 @@ module LightIO::Library
|
|
288
189
|
end
|
289
190
|
fibers_and_values[beam_or_fiber] ||= {}
|
290
191
|
end
|
192
|
+
|
193
|
+
class << self
|
194
|
+
extend Forwardable
|
195
|
+
def_delegators :'::Thread',
|
196
|
+
:DEBUG,
|
197
|
+
:DEBUG=,
|
198
|
+
:handle_interrupt,
|
199
|
+
:abort_on_exception,
|
200
|
+
:abort_on_exception=,
|
201
|
+
:pending_interrupt?
|
202
|
+
|
203
|
+
def method_missing(*args)
|
204
|
+
::Thread.__send__(*args)
|
205
|
+
end
|
206
|
+
|
207
|
+
def respond_to?(*args)
|
208
|
+
::Thread.respond_to?(*args)
|
209
|
+
end
|
210
|
+
|
211
|
+
def respond_to_missing?(method, *)
|
212
|
+
::Thread.respond_to?(method)
|
213
|
+
end
|
214
|
+
|
215
|
+
private
|
216
|
+
|
217
|
+
# threads and threads variables
|
218
|
+
def threads
|
219
|
+
thrs = Thread.instance_variable_get(:@threads)
|
220
|
+
thrs || Thread.instance_variable_set(:@threads, {})
|
221
|
+
end
|
222
|
+
|
223
|
+
def thread_mutex
|
224
|
+
mutex = Thread.instance_variable_get(:@thread_mutex)
|
225
|
+
mutex || Thread.instance_variable_set(:@thread_mutex, LightIO::Library::Mutex.new)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
class Mutex
|
230
|
+
extend Base::MockMethods
|
231
|
+
mock ::Mutex
|
232
|
+
|
233
|
+
def initialize
|
234
|
+
@queue = LightIO::Library::Queue.new
|
235
|
+
@queue << true
|
236
|
+
@locked_thread = nil
|
237
|
+
end
|
238
|
+
|
239
|
+
def lock
|
240
|
+
raise ThreadError, "deadlock; recursive locking" if owned?
|
241
|
+
@queue.pop
|
242
|
+
@locked_thread = LightIO::Thread.current
|
243
|
+
self
|
244
|
+
end
|
245
|
+
|
246
|
+
def unlock
|
247
|
+
raise ThreadError, "Attempt to unlock a mutex which is not locked" unless owned?
|
248
|
+
@locked_thread = nil
|
249
|
+
@queue << true
|
250
|
+
self
|
251
|
+
end
|
252
|
+
|
253
|
+
def locked?
|
254
|
+
!@locked_thread.nil?
|
255
|
+
end
|
256
|
+
|
257
|
+
def owned?
|
258
|
+
@locked_thread == LightIO::Thread.current
|
259
|
+
end
|
260
|
+
|
261
|
+
def sleep(timeout=nil)
|
262
|
+
unlock
|
263
|
+
LightIO.sleep(timeout)
|
264
|
+
lock
|
265
|
+
end
|
266
|
+
|
267
|
+
def synchronize
|
268
|
+
raise ThreadError, 'must be called with a block' unless block_given?
|
269
|
+
lock
|
270
|
+
begin
|
271
|
+
yield
|
272
|
+
ensure
|
273
|
+
unlock
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def try_lock
|
278
|
+
if @locked_thread.nil?
|
279
|
+
lock
|
280
|
+
true
|
281
|
+
else
|
282
|
+
false
|
283
|
+
end
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
class ConditionVariable
|
288
|
+
extend Base::MockMethods
|
289
|
+
mock ::ConditionVariable
|
290
|
+
|
291
|
+
def initialize
|
292
|
+
@queue = LightIO::Library::Queue.new
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
def broadcast
|
297
|
+
signal until @queue.num_waiting == 0
|
298
|
+
self
|
299
|
+
end
|
300
|
+
|
301
|
+
def signal
|
302
|
+
@queue << true unless @queue.num_waiting == 0
|
303
|
+
self
|
304
|
+
end
|
305
|
+
|
306
|
+
def wait(mutex, timeout=nil)
|
307
|
+
mutex.unlock
|
308
|
+
begin
|
309
|
+
LightIO::Library::Timeout.timeout(timeout) do
|
310
|
+
@queue.pop
|
311
|
+
end
|
312
|
+
rescue Timeout::Error
|
313
|
+
nil
|
314
|
+
end
|
315
|
+
mutex.lock
|
316
|
+
self
|
317
|
+
end
|
318
|
+
end
|
291
319
|
end
|
320
|
+
|
321
|
+
Mutex = Thread::Mutex
|
322
|
+
ConditionVariable = Thread::ConditionVariable
|
292
323
|
end
|