mt-libuv 4.1.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.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/.gitmodules +6 -0
  4. data/.rspec +1 -0
  5. data/.travis.yml +24 -0
  6. data/Gemfile +9 -0
  7. data/LICENSE +24 -0
  8. data/README.md +195 -0
  9. data/Rakefile +31 -0
  10. data/ext/README.md +6 -0
  11. data/ext/Rakefile +28 -0
  12. data/lib/mt-libuv/async.rb +51 -0
  13. data/lib/mt-libuv/check.rb +59 -0
  14. data/lib/mt-libuv/coroutines.rb +79 -0
  15. data/lib/mt-libuv/dns.rb +98 -0
  16. data/lib/mt-libuv/error.rb +88 -0
  17. data/lib/mt-libuv/ext/ext.rb +322 -0
  18. data/lib/mt-libuv/ext/platform/darwin_x64.rb +61 -0
  19. data/lib/mt-libuv/ext/platform/unix.rb +69 -0
  20. data/lib/mt-libuv/ext/platform/windows.rb +83 -0
  21. data/lib/mt-libuv/ext/tasks/mac.rb +24 -0
  22. data/lib/mt-libuv/ext/tasks/unix.rb +42 -0
  23. data/lib/mt-libuv/ext/tasks/win.rb +29 -0
  24. data/lib/mt-libuv/ext/tasks.rb +27 -0
  25. data/lib/mt-libuv/ext/types.rb +253 -0
  26. data/lib/mt-libuv/fiber_pool.rb +83 -0
  27. data/lib/mt-libuv/file.rb +309 -0
  28. data/lib/mt-libuv/filesystem.rb +263 -0
  29. data/lib/mt-libuv/fs_event.rb +37 -0
  30. data/lib/mt-libuv/handle.rb +108 -0
  31. data/lib/mt-libuv/idle.rb +59 -0
  32. data/lib/mt-libuv/mixins/accessors.rb +41 -0
  33. data/lib/mt-libuv/mixins/assertions.rb +25 -0
  34. data/lib/mt-libuv/mixins/fs_checks.rb +96 -0
  35. data/lib/mt-libuv/mixins/listener.rb +69 -0
  36. data/lib/mt-libuv/mixins/net.rb +42 -0
  37. data/lib/mt-libuv/mixins/resource.rb +30 -0
  38. data/lib/mt-libuv/mixins/stream.rb +276 -0
  39. data/lib/mt-libuv/pipe.rb +217 -0
  40. data/lib/mt-libuv/prepare.rb +59 -0
  41. data/lib/mt-libuv/q.rb +475 -0
  42. data/lib/mt-libuv/reactor.rb +567 -0
  43. data/lib/mt-libuv/signal.rb +62 -0
  44. data/lib/mt-libuv/spawn.rb +113 -0
  45. data/lib/mt-libuv/tcp.rb +465 -0
  46. data/lib/mt-libuv/timer.rb +107 -0
  47. data/lib/mt-libuv/tty.rb +42 -0
  48. data/lib/mt-libuv/udp.rb +302 -0
  49. data/lib/mt-libuv/version.rb +5 -0
  50. data/lib/mt-libuv/work.rb +86 -0
  51. data/lib/mt-libuv.rb +80 -0
  52. data/mt-libuv.gemspec +62 -0
  53. data/spec/async_spec.rb +67 -0
  54. data/spec/coroutines_spec.rb +121 -0
  55. data/spec/cpu_spec.rb +10 -0
  56. data/spec/defer_spec.rb +906 -0
  57. data/spec/dns_spec.rb +110 -0
  58. data/spec/dsl_spec.rb +43 -0
  59. data/spec/filesystem_spec.rb +270 -0
  60. data/spec/idle_spec.rb +44 -0
  61. data/spec/pipe_spec.rb +151 -0
  62. data/spec/spawn_spec.rb +119 -0
  63. data/spec/tcp_spec.rb +272 -0
  64. data/spec/test.sh +4 -0
  65. data/spec/test_fail.sh +3 -0
  66. data/spec/test_read.sh +3 -0
  67. data/spec/timer_spec.rb +14 -0
  68. data/spec/udp_spec.rb +73 -0
  69. data/spec/zen_spec.rb +34 -0
  70. metadata +196 -0
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ class Handle < Q::DeferredPromise
5
+ include Assertions, Resource, Listener
6
+
7
+
8
+ attr_accessor :storage # A place for general storage
9
+ attr_reader :closed
10
+ attr_reader :reactor
11
+
12
+
13
+ define_callback function: :on_close
14
+
15
+
16
+ def initialize(pointer, error)
17
+ @pointer = pointer
18
+ @instance_id = @pointer.address
19
+
20
+ # Initialise the promise
21
+ super(reactor, reactor.defer)
22
+
23
+ # clean up on init error (always raise here)
24
+ if error
25
+ ::MTLibuv::Ext.free(pointer)
26
+ defer.reject(error)
27
+ @closed = true
28
+ raise error
29
+ end
30
+ end
31
+
32
+ # Public: Increment internal ref counter for the handle on the reactor. Useful for
33
+ # extending the reactor with custom watchers that need to make reactor not stop
34
+ #
35
+ # Returns self
36
+ def ref
37
+ return self if @closed
38
+ ::MTLibuv::Ext.ref(handle)
39
+ self
40
+ end
41
+
42
+ # Public: Decrement internal ref counter for the handle on the reactor, useful to stop
43
+ # reactor even when there are outstanding open handles
44
+ #
45
+ # Returns self
46
+ def unref
47
+ return self if @closed
48
+ ::MTLibuv::Ext.unref(handle)
49
+ self
50
+ end
51
+
52
+ def close
53
+ return self if @closed
54
+ @closed = true
55
+ ::MTLibuv::Ext.close(handle, callback(:on_close))
56
+ self
57
+ end
58
+
59
+ def closed?
60
+ !!@closed
61
+ end
62
+
63
+ def active?
64
+ ::MTLibuv::Ext.is_active(handle) > 0
65
+ end
66
+
67
+ def closing?
68
+ ::MTLibuv::Ext.is_closing(handle) > 0
69
+ end
70
+
71
+
72
+ protected
73
+
74
+
75
+ def handle; @pointer; end
76
+ def defer; @defer; end
77
+ def instance_id; @instance_id; end
78
+
79
+
80
+ private
81
+
82
+
83
+ # Clean up and throw an error
84
+ def reject(reason)
85
+ @close_error = reason
86
+ close
87
+ end
88
+
89
+ def on_close(pointer)
90
+ ::MTLibuv::Ext.free(pointer)
91
+ #clear_callbacks
92
+ cleanup_callbacks
93
+
94
+ @reactor.exec do
95
+ if @close_error
96
+ defer.reject(@close_error)
97
+ else
98
+ defer.resolve(nil)
99
+ end
100
+
101
+ if @coroutine
102
+ @coroutine.resolve(self)
103
+ @coroutine = nil
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ class Idle < Handle
5
+
6
+
7
+ define_callback function: :on_idle
8
+
9
+
10
+ # @param reactor [::MTLibuv::Reactor] reactor this idle handler will be associated
11
+ # @param callback [Proc] callback to be called when the reactor is idle
12
+ def initialize(reactor)
13
+ @reactor = reactor
14
+
15
+ idle_ptr = ::MTLibuv::Ext.allocate_handle_idle
16
+ error = check_result(::MTLibuv::Ext.idle_init(reactor.handle, idle_ptr))
17
+
18
+ super(idle_ptr, error)
19
+ end
20
+
21
+ # Enables the idle handler.
22
+ def start
23
+ return if @closed
24
+ error = check_result ::MTLibuv::Ext.idle_start(handle, callback(:on_idle))
25
+ reject(error) if error
26
+ self
27
+ end
28
+
29
+ # Disables the idle handler.
30
+ def stop
31
+ return if @closed
32
+ error = check_result ::MTLibuv::Ext.idle_stop(handle)
33
+ reject(error) if error
34
+ self
35
+ end
36
+
37
+ # Used to update the callback that will be triggered on idle
38
+ #
39
+ # @param callback [Proc] the callback to be called on idle trigger
40
+ def progress(&callback)
41
+ @callback = callback
42
+ self
43
+ end
44
+
45
+
46
+ private
47
+
48
+
49
+ def on_idle(handle)
50
+ @reactor.exec do
51
+ begin
52
+ @callback.call
53
+ rescue Exception => e
54
+ @reactor.log e, 'performing idle callback'
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ module Accessors
5
+ def reactor
6
+ thread = MTLibuv::Reactor.current
7
+ if thread.nil?
8
+ thread = MTLibuv::Reactor.default
9
+ if thread.reactor_running?
10
+ raise 'No reactor available on this thread'
11
+ end
12
+ end
13
+ thread.run { yield(thread) } if block_given?
14
+ thread
15
+ end
16
+
17
+ Functions = [
18
+ :defer, :all, :any, :finally, :update_time, :now, :lookup_error, :tcp,
19
+ :udp, :tty, :pipe, :timer, :prepare, :check, :idle, :async, :signal,
20
+ :work, :lookup, :fs_event, :file, :filesystem, :schedule, :next_tick,
21
+ :stop, :reactor_thread?, :reactor_running?, :run
22
+ ].freeze
23
+
24
+ Functions.each do |function|
25
+ define_method function do |*args|
26
+ thread = MTLibuv::Reactor.current
27
+
28
+ if thread
29
+ thread.send(function, *args)
30
+ else
31
+ thread = MTLibuv::Reactor.default
32
+ if thread.reactor_running?
33
+ raise 'attempted MTLibuv::Reactor access on non-reactor thread'
34
+ else
35
+ thread.send(function, *args)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ module Assertions
5
+ MSG_NO_PROC = 'no block given'
6
+
7
+ def assert_block(proc, msg = MSG_NO_PROC)
8
+ raise ArgumentError, msg, caller unless proc.respond_to? :call
9
+ end
10
+
11
+ def assert_type(type, actual, msg = nil)
12
+ if not actual.kind_of?(type)
13
+ msg ||= "value #{actual.inspect} is not a valid #{type}"
14
+ raise ArgumentError, msg, caller
15
+ end
16
+ end
17
+
18
+ def assert_boolean(actual, msg = nil)
19
+ if not (actual.kind_of?(TrueClass) || actual.kind_of?(FalseClass))
20
+ msg ||= "value #{actual.inspect} is not a valid Boolean"
21
+ raise ArgumentError, msg, caller
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ module FsChecks
5
+
6
+
7
+ module ClassMethods
8
+ def fs_lookup(ref)
9
+ ref.to_ptr.address
10
+ end
11
+ end
12
+
13
+ def self.included(base)
14
+ base.extend(ClassMethods)
15
+ end
16
+
17
+
18
+ def stat(wait: true)
19
+ @stat_deferred = @reactor.defer
20
+
21
+ request = ::MTLibuv::Ext.allocate_request_fs
22
+ pre_check @stat_deferred, request, ::MTLibuv::Ext.fs_fstat(@reactor.handle, request, @fileno, callback(:on_stat, request.address))
23
+ promise = @stat_deferred.promise
24
+
25
+ wait ? promise.value : promise
26
+ end
27
+
28
+
29
+ protected
30
+
31
+
32
+ def respond(wait, promise)
33
+ if wait
34
+ promise.value
35
+ self
36
+ else
37
+ promise
38
+ end
39
+ end
40
+
41
+
42
+ private
43
+
44
+
45
+ def on_stat(req)
46
+ if post_check(req, @stat_deferred)
47
+ uv_stat = req[:stat]
48
+ uv_members = uv_stat.members
49
+
50
+ stats = {}
51
+ uv_members.each do |key|
52
+ stats[key] = uv_stat[key]
53
+ end
54
+
55
+ cleanup(req)
56
+ @reactor.exec { @stat_deferred.resolve(stats) }
57
+ end
58
+ @stat_deferred = nil
59
+ end
60
+
61
+ def pre_check(deferrable, request, result)
62
+ error = check_result result
63
+ if error
64
+ @request_refs.delete request.address
65
+ ::MTLibuv::Ext.free(request)
66
+ deferrable.reject(error)
67
+ end
68
+ deferrable.promise
69
+ end
70
+
71
+ def cleanup(req)
72
+ cleanup_callbacks req.to_ptr.address
73
+
74
+ ::MTLibuv::Ext.fs_req_cleanup(req)
75
+ ::MTLibuv::Ext.free(req)
76
+ end
77
+
78
+ def post_check(req, deferrable)
79
+ error = check_result(req[:result])
80
+ if error
81
+ cleanup(req)
82
+
83
+ @reactor.exec do
84
+ deferrable.reject(error)
85
+ if @coroutine
86
+ @coroutine.resolve(deferrable.promise)
87
+ @coroutine = nil
88
+ end
89
+ end
90
+ false
91
+ else
92
+ true
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'concurrent'
4
+
5
+ module MTLibuv
6
+ module Listener
7
+
8
+
9
+ private
10
+
11
+
12
+ module ClassMethods
13
+ def dispatch_callback(func_name, lookup, args)
14
+ instance_id = __send__(lookup, *args)
15
+ inst = @callback_lookup[instance_id]
16
+ inst.__send__(func_name, *args)
17
+ end
18
+
19
+ def define_callback(function:, params: [:pointer], ret_val: :void, lookup: :default_lookup)
20
+ @callback_funcs[function] = ::FFI::Function.new(ret_val, params) do |*args|
21
+ dispatch_callback(function, lookup, args)
22
+ end
23
+ end
24
+
25
+ # Much like include to support inheritance properly
26
+ # We keep existing callbacks and inherit the lookup (as this will never clash)
27
+ def inherited(subclass)
28
+ subclass.instance_variable_set(:@callback_funcs, {}.merge(@callback_funcs))
29
+ subclass.instance_variable_set(:@callback_lookup, @callback_lookup)
30
+ subclass.instance_variable_set(:@callback_lock, @callback_lock)
31
+ end
32
+
33
+
34
+ # Provide accessor methods to the class level instance variables
35
+ attr_reader :callback_lookup, :callback_funcs, :callback_lock
36
+
37
+
38
+ # This function is used to work out the instance the callback is for
39
+ def default_lookup(req, *args)
40
+ req.address
41
+ end
42
+ end
43
+
44
+ def self.included(base)
45
+ base.instance_variable_set(:@callback_funcs, {})
46
+ base.instance_variable_set(:@callback_lookup, ::Concurrent::Hash.new)
47
+ base.instance_variable_set(:@callback_lock, ::Mutex.new)
48
+ base.extend(ClassMethods)
49
+ end
50
+
51
+
52
+
53
+ def callback(name, instance_id = @instance_id)
54
+ klass = self.class
55
+ klass.callback_lock.synchronize do
56
+ klass.callback_lookup[instance_id] = self
57
+ end
58
+ klass.callback_funcs[name]
59
+ end
60
+
61
+ def cleanup_callbacks(instance_id = @instance_id)
62
+ klass = self.class
63
+ klass.callback_lock.synchronize do
64
+ inst = klass.callback_lookup[instance_id]
65
+ klass.callback_lookup.delete(instance_id) if inst == self
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'socket'
4
+
5
+ module MTLibuv
6
+ module Net
7
+
8
+
9
+ IP_ARGUMENT_ERROR = "ip must be a String" # Arguments specifying an IP address
10
+ PORT_ARGUMENT_ERROR = "port must be an Integer" # Arguments specifying an IP port
11
+ INET_ADDRSTRLEN = 16
12
+ INET6_ADDRSTRLEN = 46
13
+
14
+
15
+ private
16
+
17
+
18
+ def get_sockaddr_and_len
19
+ sockaddr = FFI::MemoryPointer.new(::MTLibuv::Ext::Sockaddr)
20
+ len = FFI::MemoryPointer.new(:int)
21
+ len.put_int(0, ::MTLibuv::Ext::Sockaddr.size)
22
+ [sockaddr, len]
23
+ end
24
+
25
+ def get_ip_and_port(sockaddr, len = nil)
26
+ if sockaddr[:sa_family] == Socket::Constants::AF_INET6
27
+ len ||= INET6_ADDRSTRLEN
28
+ sockaddr_in6 = ::MTLibuv::Ext::SockaddrIn6.new(sockaddr.pointer)
29
+ ip_ptr = FFI::MemoryPointer.new(:char, len)
30
+ ::MTLibuv::Ext.ip6_name(sockaddr_in6, ip_ptr, len)
31
+ port = ::MTLibuv::Ext.ntohs(sockaddr_in6[:sin6_port])
32
+ else
33
+ len ||= INET_ADDRSTRLEN
34
+ sockaddr_in = ::MTLibuv::Ext::SockaddrIn.new(sockaddr.pointer)
35
+ ip_ptr = FFI::MemoryPointer.new(:char, len)
36
+ ::MTLibuv::Ext.ip4_name(sockaddr_in, ip_ptr, len)
37
+ port = ::MTLibuv::Ext.ntohs(sockaddr_in[:sin_port])
38
+ end
39
+ [ip_ptr.read_string, port]
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MTLibuv
4
+ module Resource
5
+
6
+
7
+ def resolve(deferred, rc)
8
+ if rc && rc < 0
9
+ deferred.reject(@reactor.lookup_error(rc))
10
+ else
11
+ deferred.resolve(nil)
12
+ end
13
+ end
14
+
15
+ def check_result!(rc)
16
+ e = @reactor.lookup_error(rc) unless rc.nil? || rc >= 0
17
+ raise e if e
18
+ end
19
+
20
+ def check_result(rc)
21
+ @reactor.lookup_error(rc) unless rc.nil? || rc >= 0
22
+ end
23
+
24
+ def to_ptr
25
+ @pointer
26
+ end
27
+
28
+
29
+ end
30
+ end