xchan.rb 0.21.0 → 0.23.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.
- checksums.yaml +4 -4
- data/lib/xchan/lockf.rb +91 -0
- data/lib/xchan/unix_socket.rb +47 -15
- data/lib/xchan/version.rb +1 -1
- data/lib/xchan.rb +2 -1
- data/xchan.rb.gemspec +2 -1
- metadata +6 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4bf62c9fb6b3813e464c25bcd2e99f860a7a106ff85ea3e8e564f8a0d16e160b
|
|
4
|
+
data.tar.gz: 1e1868a087396c56e176c9fff11d4086e4b30d6d5cc09968c48261212317e8dc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0095b2e81e0f76c47fb8f3fc402945956b9865b16e119e85f2d1aa3e9ab1ff90e7ed63214871298bea7da759a7a7f9b8c38a57c87c0bf5d541d3ae6491be1956'
|
|
7
|
+
data.tar.gz: 5b21ab069f5be98a2f14fa596492654a73b90efb5e25a670cbb3aa81f034927ef77e954d589dab1504f627010933f335ba84f84e0749fe236c802b040d29a6eb
|
data/lib/xchan/lockf.rb
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fiddle/import"
|
|
4
|
+
require "tempfile"
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
# @private
|
|
8
|
+
# {Chan::Lockf Chan::Lockf} provides an object-oriented
|
|
9
|
+
# [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3)
|
|
10
|
+
# interface backed by Fiddle from the standard library.
|
|
11
|
+
# It supersedes the runtime dependency on the lockf.rb gem.
|
|
12
|
+
class Chan::Lockf
|
|
13
|
+
module LibC
|
|
14
|
+
extend Fiddle::Importer
|
|
15
|
+
dlload Fiddle.dlopen(nil)
|
|
16
|
+
extern "int lockf(int fd, int cmd, int size)"
|
|
17
|
+
end
|
|
18
|
+
private_constant :LibC
|
|
19
|
+
|
|
20
|
+
F_ULOCK = 0x0
|
|
21
|
+
F_LOCK = 0x1
|
|
22
|
+
F_TLOCK = 0x2
|
|
23
|
+
F_TEST = 0x3
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
# @return [<#fileno>]
|
|
27
|
+
# Returns a file handle
|
|
28
|
+
attr_reader :file
|
|
29
|
+
|
|
30
|
+
##
|
|
31
|
+
# @param [<#fileno>] file
|
|
32
|
+
# @param [Integer] size
|
|
33
|
+
# @return [Chan::Lockf]
|
|
34
|
+
# Returns an instance of {Chan::Lockf Chan::Lockf}
|
|
35
|
+
def initialize(file, size = 0)
|
|
36
|
+
@file = file
|
|
37
|
+
@size = size
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Acquire lock (blocking)
|
|
42
|
+
# @raise [SystemCallError]
|
|
43
|
+
# Might raise a subclass of SystemCallError
|
|
44
|
+
# @return [Boolean]
|
|
45
|
+
# Returns true when successful
|
|
46
|
+
def lock = try(F_LOCK)
|
|
47
|
+
|
|
48
|
+
##
|
|
49
|
+
# Acquire lock (non-blocking)
|
|
50
|
+
# @raise [SystemCallError]
|
|
51
|
+
# Might raise a subclass of SystemCallError
|
|
52
|
+
# @return [Boolean]
|
|
53
|
+
# Returns true when successful
|
|
54
|
+
def lock_nonblock = try(F_TLOCK)
|
|
55
|
+
|
|
56
|
+
##
|
|
57
|
+
# Release lock
|
|
58
|
+
# @raise [SystemCallError]
|
|
59
|
+
# Might raise a subclass of SystemCallError
|
|
60
|
+
# @return [Boolean]
|
|
61
|
+
# Returns true when successful
|
|
62
|
+
def release = try(F_ULOCK)
|
|
63
|
+
|
|
64
|
+
##
|
|
65
|
+
# @return [Boolean]
|
|
66
|
+
# Returns true when lock can be acquired
|
|
67
|
+
def lockable?
|
|
68
|
+
try(F_TEST)
|
|
69
|
+
true
|
|
70
|
+
rescue Errno::EACCES, Errno::EAGAIN, Errno::EWOULDBLOCK
|
|
71
|
+
false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
##
|
|
75
|
+
# Closes {Chan::Lockf#file Chan::Lockf#file}
|
|
76
|
+
# @return [void]
|
|
77
|
+
def close
|
|
78
|
+
@file.respond_to?(:close) ? @file.close : nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
def try(function, attempts: 3)
|
|
84
|
+
fileno = @file.respond_to?(:fileno) ? @file.fileno : @file
|
|
85
|
+
LibC.lockf(fileno, function, @size).zero? ||
|
|
86
|
+
raise(SystemCallError.new("lockf", Fiddle.last_error))
|
|
87
|
+
rescue Errno::EINTR => ex
|
|
88
|
+
attempts -= 1
|
|
89
|
+
(attempts.zero? ? raise(ex) : retry)
|
|
90
|
+
end
|
|
91
|
+
end
|
data/lib/xchan/unix_socket.rb
CHANGED
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
# An easy-to-use InterProcess Communication (IPC) library
|
|
5
5
|
class Chan::UNIXSocket
|
|
6
6
|
require "socket"
|
|
7
|
-
require "lockf"
|
|
8
7
|
require_relative "bytes"
|
|
9
8
|
|
|
10
9
|
##
|
|
@@ -46,6 +45,8 @@ class Chan::UNIXSocket
|
|
|
46
45
|
@counter = Chan::Counter.new(tmpdir)
|
|
47
46
|
@lock = Chan.locks[lock]&.call(tmpdir) || lock
|
|
48
47
|
@mutex = Mutex.new
|
|
48
|
+
@partial = nil
|
|
49
|
+
@partial_len = 0
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
##
|
|
@@ -107,10 +108,12 @@ class Chan::UNIXSocket
|
|
|
107
108
|
@mutex.synchronize do
|
|
108
109
|
@lock.lock_nonblock
|
|
109
110
|
raise IOError, "channel closed" if closed?
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
@
|
|
113
|
-
|
|
111
|
+
data = serialize(object)
|
|
112
|
+
head = [data.bytesize].pack("Q>")
|
|
113
|
+
n = @w.write_nonblock(head << data)
|
|
114
|
+
@bytes.push(data.bytesize)
|
|
115
|
+
@counter.increment!(bytes_written: data.bytesize)
|
|
116
|
+
data.bytesize.tap { @lock.release }
|
|
114
117
|
rescue IOError, IO::WaitWritable, Errno::ENOBUFS => ex
|
|
115
118
|
@lock.release
|
|
116
119
|
raise Chan::WaitWritable, ex.message
|
|
@@ -157,15 +160,35 @@ class Chan::UNIXSocket
|
|
|
157
160
|
@mutex.synchronize do
|
|
158
161
|
@lock.lock_nonblock
|
|
159
162
|
raise IOError, "closed channel" if closed?
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
+
stream = @r.local_address.socktype == Socket::SOCK_STREAM
|
|
164
|
+
unless @partial
|
|
165
|
+
if stream
|
|
166
|
+
head = String.new
|
|
167
|
+
while head.bytesize < 8
|
|
168
|
+
head << @r.read_nonblock(8 - head.bytesize)
|
|
169
|
+
end
|
|
170
|
+
@partial_len = head.unpack1("Q>")
|
|
171
|
+
@partial = String.new(capacity: @partial_len)
|
|
172
|
+
else
|
|
173
|
+
buf = @r.read_nonblock(65536)
|
|
174
|
+
@partial_len = buf[0, 8].unpack1("Q>")
|
|
175
|
+
@partial = buf[8, @partial_len]
|
|
176
|
+
end
|
|
177
|
+
@bytes.shift
|
|
178
|
+
end
|
|
179
|
+
if stream
|
|
180
|
+
while @partial.bytesize < @partial_len
|
|
181
|
+
@partial << @r.read_nonblock(@partial_len - @partial.bytesize)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
obj = deserialize(@partial)
|
|
185
|
+
@counter.increment!(bytes_read: @partial.bytesize)
|
|
186
|
+
@partial = nil
|
|
163
187
|
obj.tap { @lock.release }
|
|
164
188
|
rescue IOError => ex
|
|
165
189
|
@lock.release
|
|
166
190
|
raise(ex)
|
|
167
191
|
rescue IO::WaitReadable => ex
|
|
168
|
-
@bytes.unshift(len)
|
|
169
192
|
@lock.release
|
|
170
193
|
raise Chan::WaitReadable, ex.message
|
|
171
194
|
rescue Errno::EAGAIN => ex
|
|
@@ -198,6 +221,13 @@ class Chan::UNIXSocket
|
|
|
198
221
|
lock { size.zero? }
|
|
199
222
|
end
|
|
200
223
|
|
|
224
|
+
##
|
|
225
|
+
# @return [Integer]
|
|
226
|
+
# Returns the number of elements waiting to be read
|
|
227
|
+
def size
|
|
228
|
+
@bytes.size
|
|
229
|
+
end
|
|
230
|
+
|
|
201
231
|
##
|
|
202
232
|
# @group Stat methods
|
|
203
233
|
|
|
@@ -218,14 +248,16 @@ class Chan::UNIXSocket
|
|
|
218
248
|
alias_method :bytes_read, :bytes_received
|
|
219
249
|
|
|
220
250
|
##
|
|
221
|
-
# @
|
|
222
|
-
# Returns the number of objects waiting to be read
|
|
223
|
-
def size
|
|
224
|
-
lock { @bytes.size }
|
|
225
|
-
end
|
|
251
|
+
# @endgroup
|
|
226
252
|
|
|
227
253
|
##
|
|
228
|
-
# @
|
|
254
|
+
# @return [void]
|
|
255
|
+
def flush
|
|
256
|
+
@lock.lock
|
|
257
|
+
to_a
|
|
258
|
+
ensure
|
|
259
|
+
@lock.release
|
|
260
|
+
end
|
|
229
261
|
|
|
230
262
|
##
|
|
231
263
|
# @group Wait methods
|
data/lib/xchan/version.rb
CHANGED
data/lib/xchan.rb
CHANGED
|
@@ -5,6 +5,7 @@ module Chan
|
|
|
5
5
|
require_relative "xchan/unix_socket"
|
|
6
6
|
require_relative "xchan/null_lock"
|
|
7
7
|
require_relative "xchan/tempfile"
|
|
8
|
+
require_relative "xchan/lockf"
|
|
8
9
|
|
|
9
10
|
WaitReadable = Class.new(IO::EAGAINWaitReadable)
|
|
10
11
|
WaitWritable = Class.new(IO::EAGAINWaitWritable)
|
|
@@ -65,7 +66,7 @@ module Chan
|
|
|
65
66
|
def self.locks
|
|
66
67
|
{
|
|
67
68
|
null: lambda { |_tmpdir| Chan::NullLock },
|
|
68
|
-
file: lambda { |tmpdir| Lockf.new Chan.temporary_file(%w[xchan lock], tmpdir:) }
|
|
69
|
+
file: lambda { |tmpdir| Chan::Lockf.new Chan.temporary_file(%w[xchan lock], tmpdir:) }
|
|
69
70
|
}
|
|
70
71
|
end
|
|
71
72
|
end
|
data/xchan.rb.gemspec
CHANGED
|
@@ -18,7 +18,8 @@ Gem::Specification.new do |gem|
|
|
|
18
18
|
gem.require_paths = ["lib"]
|
|
19
19
|
gem.summary = "An easy to use InterProcess Communication (IPC) library"
|
|
20
20
|
gem.description = gem.summary
|
|
21
|
-
|
|
21
|
+
|
|
22
|
+
gem.add_runtime_dependency "fiddle", "~> 1.1"
|
|
22
23
|
gem.add_development_dependency "test-unit", "~> 3.5.7"
|
|
23
24
|
gem.add_development_dependency "yard", "~> 0.9"
|
|
24
25
|
gem.add_development_dependency "kramdown", "~> 2.5"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: xchan.rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.23.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- '0x1eef'
|
|
@@ -10,19 +10,19 @@ cert_chain: []
|
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
|
-
name:
|
|
13
|
+
name: fiddle
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
16
|
- - "~>"
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '
|
|
18
|
+
version: '1.1'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '
|
|
25
|
+
version: '1.1'
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: test-unit
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -132,6 +132,7 @@ files:
|
|
|
132
132
|
- lib/xchan.rb
|
|
133
133
|
- lib/xchan/bytes.rb
|
|
134
134
|
- lib/xchan/counter.rb
|
|
135
|
+
- lib/xchan/lockf.rb
|
|
135
136
|
- lib/xchan/null_lock.rb
|
|
136
137
|
- lib/xchan/tempfile.rb
|
|
137
138
|
- lib/xchan/unix_socket.rb
|
|
@@ -167,7 +168,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
167
168
|
- !ruby/object:Gem::Version
|
|
168
169
|
version: '0'
|
|
169
170
|
requirements: []
|
|
170
|
-
rubygems_version:
|
|
171
|
+
rubygems_version: 4.0.16
|
|
171
172
|
specification_version: 4
|
|
172
173
|
summary: An easy to use InterProcess Communication (IPC) library
|
|
173
174
|
test_files: []
|