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.
@@ -4,196 +4,162 @@ module LightIO::Library
4
4
 
5
5
  class Addrinfo
6
6
  include LightIO::Wrap::Wrapper
7
- wrap ::Addrinfo
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
- def wrap_addrinfo_return_methods(*methods)
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
- wrap ::BasicSocket
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 :@io_watcher, :wait, :wait_writable
25
+ def_delegators :io_watcher, :wait, :wait_writable
72
26
 
73
27
  def shutdown(*args)
74
28
  # close watcher before io shutdown
75
- @io_watcher.close
76
- @io.shutdown(*args)
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 ::Socket::Constants
35
+ include Base
88
36
  include LightIO::Wrap::IOWrapper
89
- wrap ::Socket
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
- @io_watcher.wait_readable
106
- @io.sys_accept
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 LightIO::Wrap::Wrapper
115
- wrap ::Socket
48
+ include Base
49
+ mock ::Socket::Ifaddr
116
50
 
117
51
  def addr
118
- @io.addr && Addrinfo._wrap(@io.addr)
52
+ @obj.addr && Addrinfo._wrap(@obj.addr)
119
53
  end
120
54
 
121
55
  def broadaddr
122
- @io.broadaddr && Addrinfo._wrap(@io.broadaddr)
56
+ @obj.broadaddr && Addrinfo._wrap(@obj.broadaddr)
123
57
  end
124
58
 
125
59
  def dstaddr
126
- @io.dstaddr && Addrinfo._wrap(@io.dstaddr)
60
+ @obj.dstaddr && Addrinfo._wrap(@obj.dstaddr)
127
61
  end
128
62
 
129
63
  def netmask
130
- @io.netmask && Addrinfo._wrap(@io.netmask)
64
+ @obj.netmask && Addrinfo._wrap(@obj.netmask)
131
65
  end
132
66
  end
133
67
 
134
- class << self
135
- ## implement ::Socket class methods
136
- wrap_methods_run_in_threads_pool :getaddrinfo, :gethostbyaddr, :gethostbyname, :gethostname,
137
- :getnameinfo, :getservbyname
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
- def unix_server_socket(path)
150
- if block_given?
151
- raw_class.unix_server_socket(path) {|s| yield _wrap(s)}
152
- else
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
- def ip_sockets_port0(ai_list, reuseaddr)
158
- raw_class.ip_sockets_port0(ai_list, reuseaddr).map {|s| _wrap(s)}
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 LightIO::Wrap::IOWrapper
166
- wrap ::IPSocket
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 LightIO::Wrap::IOWrapper
175
- wrap ::TCPSocket
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 LightIO::Wrap::IOWrapper
181
- wrap ::TCPServer
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 = @io.accept_nonblock(*args)
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
- @io_watcher.wait_readable
196
- @io.sys_accept
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
- wrap ::ThreadGroup
9
-
10
- Default = ThreadGroup._wrap(::ThreadGroup::Default)
8
+ mock ::ThreadGroup
11
9
 
12
10
  def add(thread)
13
- if @io.enclosed?
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
- @io.add(thread)
17
+ @obj.add(thread)
20
18
  end
21
19
  self
22
20
  end
23
21
 
24
22
  def list
25
- @io.list + threads
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
- @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
- 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
- fallback_main_thread_methods :abort_on_exception,
155
- :abort_on_exception=,
156
- :pending_interrupt?,
157
- :add_trace_func,
158
- :backtrace,
159
- :backtrace_locations,
160
- :priority,
161
- :priority=,
162
- :safe_level
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 Thread.current == self
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, self.class.finalizer(self.object_id))
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