lightio 0.3.2 → 0.4.0.pre
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/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
|