cztop 1.1.1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 066d9600730db24e49b9b83fee30840882432df13dde7372f9e7f969b3774b33
4
- data.tar.gz: 67ee0941443c6a9eadf7d27b4bc084e00d20c2dc7ca4448fc6459edc93a88efb
3
+ metadata.gz: 3f398a80bc75445bfd115544ca7f3e4c9f894cd1b9d58a9f0e2a90f6c0841275
4
+ data.tar.gz: 4d6b4c393b573c8bd64f4a65317bd6bbf258c5c2a7137ecabc681be6713c6f6a
5
5
  SHA512:
6
- metadata.gz: c8852f4b214935ef5b0302a7a6481a2f51148dfc6fac939ca9d9b5f665ab06d8242418bdbe996edb9ad6fe010a84a540fd9b24e379cdd5b3197fd3c7a80f0478
7
- data.tar.gz: 506f6e6b9a927e8c68d60c410d3ed84abfae1edef435c43baae8855eb2f02409815692eb4cf18501298ab5c8f9c988cdd48d308a93eb20d1ae136bf51c8283fe
6
+ metadata.gz: 12567ad2f7cadeb6067edcf61fb3ba975635d236edd4a5dd5465b6dcb931cf7c8b4f5852892c5bd4c0c5f0aaa87488f21b7ccb81a73a5d4134928b55f276ce4a
7
+ data.tar.gz: 99d6274e17d86865e80328184825f525f2959dbe926e052c9af88423f40e0fbf6f53531ef5de8eb22225315f2629e3580fd34f094031c21bbb37a665946d58b7
data/CHANGES.md CHANGED
@@ -1,3 +1,8 @@
1
+ 1.1.2 (1/5/2024)
2
+ -----
3
+ * refactor to make code Fiber Scheduler agnostic
4
+ * remove Async::IO::CZTopSocket
5
+
1
6
  1.1.1 (1/4/2024)
2
7
  -----
3
8
  * speed up Async::IO#wait_readable and #wait_writable
data/README.md CHANGED
@@ -13,22 +13,22 @@ mechanisms (like CURVE).
13
13
 
14
14
  ## Example with Async
15
15
 
16
+ See [this example](https://github.com/paddor/cztop/blob/master/examples/async.rb):
17
+
16
18
  ```ruby
17
19
  #! /usr/bin/env ruby
18
20
 
19
- require 'cztop/async'
21
+ require 'cztop'
20
22
 
21
23
  Async do |task|
22
24
  task.async do |t|
23
25
  socket = CZTop::Socket::REP.new("inproc://req_rep_example")
24
- io = Async::IO.try_convert socket
25
-
26
26
  socket.options.rcvtimeo = 50 # ms
27
27
 
28
28
  loop do
29
- msg = io.receive
29
+ msg = socket.receive
30
30
  puts "<<< #{msg.to_a.inspect}"
31
- io << msg.to_a.map(&:upcase)
31
+ socket << msg.to_a.map(&:upcase)
32
32
  rescue IO::TimeoutError
33
33
  break
34
34
  end
@@ -38,11 +38,10 @@ Async do |task|
38
38
 
39
39
  task.async do
40
40
  socket = CZTop::Socket::REQ.new("inproc://req_rep_example")
41
- io = Async::IO.try_convert socket
42
41
 
43
42
  10.times do |i|
44
- io << "foobar ##{i}"
45
- msg = io.receive
43
+ socket << "foobar ##{i}"
44
+ msg = socket.receive
46
45
  puts ">>> #{msg.to_a.inspect}"
47
46
  end
48
47
 
@@ -54,6 +53,8 @@ end
54
53
 
55
54
  Output:
56
55
  ```
56
+ $ cd examples
57
+ $ time ./async.rb
57
58
  <<< ["foobar #0"]
58
59
  >>> ["FOOBAR #0"]
59
60
  <<< ["foobar #1"]
@@ -76,61 +77,20 @@ Output:
76
77
  >>> ["FOOBAR #9"]
77
78
  REQ done.
78
79
  REP done.
79
- 0.46user 0.09system 0:00.60elapsed 90%CPU (0avgtext+0avgdata 47296maxresident)k
80
- 0inputs+0outputs (0major+13669minor)pagefaults 0swaps
81
- ```
82
-
83
- ## Overview
84
-
85
- ### Class Hierarchy
86
80
 
87
- Here's an overview of the core classes:
81
+ ________________________________________________________
82
+ Executed in 401.51 millis fish external
83
+ usr time 308.44 millis 605.00 micros 307.83 millis
84
+ sys time 40.08 millis 278.00 micros 39.81 millis
88
85
 
89
- * [CZTop](http://www.rubydoc.info/gems/cztop/CZTop)
90
- * [Actor](http://www.rubydoc.info/gems/cztop/CZTop)
91
- * [Authenticator](http://www.rubydoc.info/gems/cztop/CZTop/Authenticator)
92
- * [Beacon](http://www.rubydoc.info/gems/cztop/CZTop/Beacon)
93
- * [Certificate](http://www.rubydoc.info/gems/cztop/CZTop/Certificate)
94
- * [CertStore](http://www.rubydoc.info/gems/cztop/CZTop/CertStore)
95
- * [Config](http://www.rubydoc.info/gems/cztop/CZTop/Config)
96
- * [Frame](http://www.rubydoc.info/gems/cztop/CZTop/Frame)
97
- * [Message](http://www.rubydoc.info/gems/cztop/CZTop/Message)
98
- * [Monitor](http://www.rubydoc.info/gems/cztop/CZTop/Monitor)
99
- * [Metadata](http://www.rubydoc.info/gems/cztop/CZTop/Metadata)
100
- * [Proxy](http://www.rubydoc.info/gems/cztop/CZTop/Proxy)
101
- * [Poller](http://www.rubydoc.info/gems/cztop/CZTop/Poller) (based on `zmq_poller_*()` functions)
102
- * [Aggregated](http://www.rubydoc.info/gems/cztop/CZTop/Poller/Aggregated)
103
- * [ZPoller](http://www.rubydoc.info/gems/cztop/CZTop/Poller/ZPoller)
104
- * [Socket](http://www.rubydoc.info/gems/cztop/CZTop/Socket)
105
- * [REQ](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REQ) < Socket
106
- * [REP](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REP) < Socket
107
- * [ROUTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/ROUTER) < Socket
108
- * [DEALER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DEALER) < Socket
109
- * [PUSH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUSH) < Socket
110
- * [PULL](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PULL) < Socket
111
- * [PUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUB) < Socket
112
- * [SUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SUB) < Socket
113
- * [XPUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XPUB) < Socket
114
- * [XSUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XSUB) < Socket
115
- * [PAIR](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PAIR) < Socket
116
- * [STREAM](http://www.rubydoc.info/gems/cztop/CZTop/Socket/STREAM) < Socket
117
- * [CLIENT](http://www.rubydoc.info/gems/cztop/CZTop/Socket/CLIENT) < Socket
118
- * [SERVER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SERVER) < Socket
119
- * [RADIO](http://www.rubydoc.info/gems/cztop/CZTop/Socket/RADIO) < Socket
120
- * [DISH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DISH) < Socket
121
- * [SCATTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SCATTER) < Socket
122
- * [GATHER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/GATHER) < Socket
123
- * [Z85](http://www.rubydoc.info/gems/cztop/CZTop/Z85)
124
- * [Padded](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Padded) < Z85
125
- * [Pipe](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Pipe)
126
- * [ZAP](http://www.rubydoc.info/gems/cztop/CZTop/ZAP)
86
+ ```
127
87
 
128
- More information in the [API documentation](http://www.rubydoc.info/github/paddor/cztop).
88
+ ## Overview
129
89
 
130
90
  ### Features
131
91
 
132
92
  * Ruby idiomatic API
133
- * compatible with [Async](https://github.com/socketry/async) / [Async::IO](https://github.com/socketry/async-io)
93
+ * Fiber Scheduler aware
134
94
  * errors as exceptions
135
95
  * CURVE security
136
96
  * supports CZMQ DRAFT API
@@ -175,6 +135,51 @@ Or install it yourself as:
175
135
 
176
136
  $ gem install cztop
177
137
 
138
+ ### Class Hierarchy
139
+
140
+ Here's an overview of the core classes:
141
+
142
+ * [CZTop](http://www.rubydoc.info/gems/cztop/CZTop)
143
+ * [Actor](http://www.rubydoc.info/gems/cztop/CZTop)
144
+ * [Authenticator](http://www.rubydoc.info/gems/cztop/CZTop/Authenticator)
145
+ * [Beacon](http://www.rubydoc.info/gems/cztop/CZTop/Beacon)
146
+ * [Certificate](http://www.rubydoc.info/gems/cztop/CZTop/Certificate)
147
+ * [CertStore](http://www.rubydoc.info/gems/cztop/CZTop/CertStore)
148
+ * [Config](http://www.rubydoc.info/gems/cztop/CZTop/Config)
149
+ * [Frame](http://www.rubydoc.info/gems/cztop/CZTop/Frame)
150
+ * [Message](http://www.rubydoc.info/gems/cztop/CZTop/Message)
151
+ * [Monitor](http://www.rubydoc.info/gems/cztop/CZTop/Monitor)
152
+ * [Metadata](http://www.rubydoc.info/gems/cztop/CZTop/Metadata)
153
+ * [Proxy](http://www.rubydoc.info/gems/cztop/CZTop/Proxy)
154
+ * [Poller](http://www.rubydoc.info/gems/cztop/CZTop/Poller) (based on `zmq_poller_*()` functions)
155
+ * [Aggregated](http://www.rubydoc.info/gems/cztop/CZTop/Poller/Aggregated)
156
+ * [ZPoller](http://www.rubydoc.info/gems/cztop/CZTop/Poller/ZPoller)
157
+ * [Socket](http://www.rubydoc.info/gems/cztop/CZTop/Socket)
158
+ * [REQ](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REQ) < Socket
159
+ * [REP](http://www.rubydoc.info/gems/cztop/CZTop/Socket/REP) < Socket
160
+ * [ROUTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/ROUTER) < Socket
161
+ * [DEALER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DEALER) < Socket
162
+ * [PUSH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUSH) < Socket
163
+ * [PULL](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PULL) < Socket
164
+ * [PUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PUB) < Socket
165
+ * [SUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SUB) < Socket
166
+ * [XPUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XPUB) < Socket
167
+ * [XSUB](http://www.rubydoc.info/gems/cztop/CZTop/Socket/XSUB) < Socket
168
+ * [PAIR](http://www.rubydoc.info/gems/cztop/CZTop/Socket/PAIR) < Socket
169
+ * [STREAM](http://www.rubydoc.info/gems/cztop/CZTop/Socket/STREAM) < Socket
170
+ * [CLIENT](http://www.rubydoc.info/gems/cztop/CZTop/Socket/CLIENT) < Socket
171
+ * [SERVER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SERVER) < Socket
172
+ * [RADIO](http://www.rubydoc.info/gems/cztop/CZTop/Socket/RADIO) < Socket
173
+ * [DISH](http://www.rubydoc.info/gems/cztop/CZTop/Socket/DISH) < Socket
174
+ * [SCATTER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/SCATTER) < Socket
175
+ * [GATHER](http://www.rubydoc.info/gems/cztop/CZTop/Socket/GATHER) < Socket
176
+ * [Z85](http://www.rubydoc.info/gems/cztop/CZTop/Z85)
177
+ * [Padded](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Padded) < Z85
178
+ * [Pipe](http://www.rubydoc.info/gems/cztop/CZTop/Z85/Pipe)
179
+ * [ZAP](http://www.rubydoc.info/gems/cztop/CZTop/ZAP)
180
+
181
+ More information in the [API documentation](http://www.rubydoc.info/github/paddor/cztop).
182
+
178
183
  ## Documentation
179
184
 
180
185
  The API should be fairly straight-forward to anyone who is familiar with CZMQ
data/cztop.gemspec CHANGED
@@ -36,6 +36,5 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  if RUBY_VERSION >= '3.1'
38
38
  spec.add_development_dependency "async", ">= 2.0.1"
39
- spec.add_development_dependency "async-io"
40
39
  end
41
40
  end
data/lib/cztop/message.rb CHANGED
@@ -61,6 +61,8 @@ module CZTop
61
61
  # returns with failure. Please report as bug.
62
62
  #
63
63
  def send_to(destination)
64
+ destination.wait_writable if Fiber.scheduler
65
+
64
66
  rc = Zmsg.send(ffi_delegate, destination)
65
67
  return if rc.zero?
66
68
 
@@ -79,6 +81,8 @@ module CZTop
79
81
  # @raise [SystemCallError] for any other error code set after +zmsg_recv+
80
82
  # returns with failure. Please report as bug.
81
83
  def self.receive_from(source)
84
+ source.wait_readable if Fiber.scheduler
85
+
82
86
  delegate = Zmsg.recv(source)
83
87
  return from_ffi_delegate(delegate) unless delegate.null?
84
88
 
@@ -35,5 +35,80 @@ module CZTop
35
35
  Message.receive_from(self)
36
36
  end
37
37
 
38
+
39
+ # Waits for socket to become readable.
40
+ def wait_readable(timeout = read_timeout)
41
+ return true if readable?
42
+
43
+ @fd_io ||= to_io
44
+
45
+ if timeout
46
+ timeout_at = now + timeout
47
+
48
+ while true
49
+ @fd_io.wait_readable(timeout)
50
+ break if readable? # NOTE: ZMQ FD can't be trusted 100%
51
+ raise ::IO::TimeoutError if now >= timeout_at
52
+ end
53
+ else
54
+ @fd_io.wait_readable until readable?
55
+ end
56
+ end
57
+
58
+
59
+ # Waits for socket to become writable.
60
+ def wait_writable(timeout = write_timeout)
61
+ return true if writable?
62
+
63
+ @fd_io ||= to_io
64
+
65
+ if timeout
66
+ timeout_at = now + timeout
67
+
68
+ while true
69
+ @fd_io.wait_writable(timeout)
70
+ break if writable? # NOTE: ZMQ FD can't be trusted 100%
71
+ raise ::IO::TimeoutError if now >= timeout_at
72
+ end
73
+ else
74
+ @fd_io.wait_writable until writable?
75
+ end
76
+ end
77
+
78
+
79
+ # @return [Float, nil] the timeout in seconds used by {IO#wait_readable}
80
+ def read_timeout
81
+ timeout = options.rcvtimeo
82
+
83
+ if timeout <= 0
84
+ timeout = nil
85
+ else
86
+ timeout = timeout.to_f / 1000
87
+ end
88
+
89
+ timeout
90
+ end
91
+
92
+
93
+ # @return [Float, nil] the timeout in seconds used by {IO#wait_writable}
94
+ def write_timeout
95
+ timeout = options.sndtimeo
96
+
97
+ if timeout <= 0
98
+ timeout = nil
99
+ else
100
+ timeout = timeout.to_f / 1000
101
+ end
102
+
103
+ timeout
104
+ end
105
+
106
+
107
+ private
108
+
109
+
110
+ def now
111
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
112
+ end
38
113
  end
39
114
  end
data/lib/cztop/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CZTop
4
4
 
5
- VERSION = '1.1.1'
5
+ VERSION = '1.1.2'
6
6
 
7
7
  end
@@ -43,6 +43,12 @@ module CZTop
43
43
  end
44
44
 
45
45
 
46
+ # @return [IO] IO for FD
47
+ def to_io
48
+ IO.for_fd fd, autoclose: false
49
+ end
50
+
51
+
46
52
  # Used to access the options of a {Socket} or {Actor}.
47
53
  class OptionsAccessor
48
54
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cztop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Patrik Wenger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-01-04 00:00:00.000000000 Z
11
+ date: 2024-01-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: czmq-ffi-gen
@@ -150,20 +150,6 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: 2.0.1
153
- - !ruby/object:Gem::Dependency
154
- name: async-io
155
- requirement: !ruby/object:Gem::Requirement
156
- requirements:
157
- - - ">="
158
- - !ruby/object:Gem::Version
159
- version: '0'
160
- type: :development
161
- prerelease: false
162
- version_requirements: !ruby/object:Gem::Requirement
163
- requirements:
164
- - - ">="
165
- - !ruby/object:Gem::Version
166
- version: '0'
167
153
  description: CZMQ binding based on the generated low-level FFI bindings of CZMQ
168
154
  email:
169
155
  - paddor@gmail.com
@@ -192,10 +178,6 @@ files:
192
178
  - ci/install-libczmq
193
179
  - ci/install-libzmq
194
180
  - cztop.gemspec
195
- - examples/async/.gitignore
196
- - examples/async/Gemfile
197
- - examples/async/README.md
198
- - examples/async/async.rb
199
181
  - examples/ruby_actor/actor.rb
200
182
  - examples/simple_req_rep/rep.rb
201
183
  - examples/simple_req_rep/req.rb
@@ -214,7 +196,6 @@ files:
214
196
  - exe/z85encode
215
197
  - lib/cztop.rb
216
198
  - lib/cztop/actor.rb
217
- - lib/cztop/async.rb
218
199
  - lib/cztop/authenticator.rb
219
200
  - lib/cztop/beacon.rb
220
201
  - lib/cztop/cert_store.rb
@@ -1 +0,0 @@
1
- /Gemfile.lock
@@ -1,5 +0,0 @@
1
- source 'https://rubygems.org'
2
-
3
- gem 'async'
4
- gem 'cztop', path: '../../'
5
- gem 'async-io'
@@ -1 +0,0 @@
1
- Run: `bundle exec ./async.rb`
@@ -1,35 +0,0 @@
1
- #! /usr/bin/env ruby
2
-
3
- require 'cztop/async'
4
-
5
- Async do |task|
6
- task.async do |t|
7
- socket = CZTop::Socket::REP.new("inproc://req_rep_example")
8
- io = Async::IO.try_convert socket
9
-
10
- socket.options.rcvtimeo = 50 # ms
11
-
12
- loop do
13
- msg = io.receive
14
- puts "<<< #{msg.to_a.inspect}"
15
- io << msg.to_a.map(&:upcase)
16
- rescue IO::TimeoutError
17
- break
18
- end
19
-
20
- puts "REP done."
21
- end
22
-
23
- task.async do
24
- socket = CZTop::Socket::REQ.new("inproc://req_rep_example")
25
- io = Async::IO.try_convert socket
26
-
27
- 10.times do |i|
28
- io << "foobar ##{i}"
29
- msg = io.receive
30
- puts ">>> #{msg.to_a.inspect}"
31
- end
32
-
33
- puts "REQ done."
34
- end
35
- end
data/lib/cztop/async.rb DELETED
@@ -1,124 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'cztop'
4
- require 'async/io'
5
-
6
- module Async
7
- module IO
8
-
9
- # Wrapper for CZTop sockets.
10
- #
11
- # @example
12
- # Async do |task|
13
- # socket = CZTop::Socket::REP.new("ipc:///tmp/req_rep_example")
14
- # socket.options.rcvtimeo = 3
15
- # io = Async::IO.try_convert socket
16
- # msg = io.receive
17
- # io << msg.to_a.map(&:upcase)
18
- # end
19
-
20
- class CZTopSocket < Generic
21
- wraps ::CZTop::Socket::REQ
22
- wraps ::CZTop::Socket::REP
23
- wraps ::CZTop::Socket::PAIR
24
- wraps ::CZTop::Socket::ROUTER
25
- wraps ::CZTop::Socket::DEALER
26
- wraps ::CZTop::Socket::PUSH
27
- wraps ::CZTop::Socket::PULL
28
- wraps ::CZTop::Socket::PUB
29
- wraps ::CZTop::Socket::SUB
30
- wraps ::CZTop::Socket::XPUB
31
- wraps ::CZTop::Socket::XSUB
32
-
33
-
34
- # @see {CZTop::SendReceiveMethods#receive}
35
- def receive
36
- wait_readable
37
- @io.receive
38
- end
39
-
40
-
41
- # @see {CZTop::SendReceiveMethods#<<}
42
- def <<(...)
43
- wait_writable
44
- @io.<<(...)
45
- end
46
-
47
-
48
- # Waits for socket to become readable.
49
- def wait_readable(timeout = read_timeout)
50
- @io_fd ||= ::IO.for_fd @io.fd, autoclose: false
51
-
52
- return true if @io.readable?
53
-
54
- if timeout
55
- timeout_at = now + timeout
56
-
57
- while true
58
- @io_fd.wait_readable(timeout)
59
- break if @io.readable?
60
- raise ::IO::TimeoutError if now >= timeout_at
61
- end
62
- else
63
- @io_fd.wait_readable until @io.readable?
64
- end
65
- end
66
-
67
-
68
- # Waits for socket to become writable.
69
- def wait_writable(timeout = write_timeout)
70
- @io_fd ||= ::IO.for_fd @io.fd, autoclose: false
71
-
72
- return true if @io.writable?
73
-
74
- if timeout
75
- timeout_at = now + timeout
76
-
77
- while true
78
- @io_fd.wait_writable(timeout)
79
- break if @io.writable?
80
- raise ::IO::TimeoutError if now >= timeout_at
81
- end
82
- else
83
- @io_fd.wait_writable until @io.writable?
84
- end
85
- end
86
-
87
-
88
- # @return [Float, nil] the timeout in seconds used by {IO#wait_readable}
89
- def read_timeout
90
- timeout = @io.options.rcvtimeo
91
-
92
- if timeout <= 0
93
- timeout = nil
94
- else
95
- timeout = timeout.to_f / 1000
96
- end
97
-
98
- timeout
99
- end
100
-
101
-
102
- # @return [Float, nil] the timeout in seconds used by {IO#wait_writable}
103
- def write_timeout
104
- timeout = @io.options.sndtimeo
105
-
106
- if timeout <= 0
107
- timeout = nil
108
- else
109
- timeout = timeout.to_f / 1000
110
- end
111
-
112
- timeout
113
- end
114
-
115
-
116
- private
117
-
118
-
119
- def now
120
- Process.clock_gettime(Process::CLOCK_MONOTONIC)
121
- end
122
- end
123
- end
124
- end