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.
@@ -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