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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e8936112cb188471884a6fa66ee0db2b61d5229ac75acb8953c78e5b76587bc8
4
- data.tar.gz: e76eb21f0f7f2a11e465ee3d4834b3abd48b54269949ee3623e2b2c2bdc1a17c
3
+ metadata.gz: 4bf62c9fb6b3813e464c25bcd2e99f860a7a106ff85ea3e8e564f8a0d16e160b
4
+ data.tar.gz: 1e1868a087396c56e176c9fff11d4086e4b30d6d5cc09968c48261212317e8dc
5
5
  SHA512:
6
- metadata.gz: d6ff8db4154e29a41a41b3878a93355ab3ce8092112f76f7fa4a61042a9747138f9a270217decf0e39cc5a9890f7ce5f34ebaa8a93e74aeb68d1cf5b0d470a09
7
- data.tar.gz: bbe432d09de33e607b7940005a1d29ee0c1de6c14d3a2a56105c5fa26e32ea81a6327a87a6e520163f34836ffe820296674bf29a46c72cc45c603872500f090f
6
+ metadata.gz: '0095b2e81e0f76c47fb8f3fc402945956b9865b16e119e85f2d1aa3e9ab1ff90e7ed63214871298bea7da759a7a7f9b8c38a57c87c0bf5d541d3ae6491be1956'
7
+ data.tar.gz: 5b21ab069f5be98a2f14fa596492654a73b90efb5e25a670cbb3aa81f034927ef77e954d589dab1504f627010933f335ba84f84e0749fe236c802b040d29a6eb
@@ -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
@@ -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
- len = @w.write_nonblock(serialize(object))
111
- @bytes.push(len)
112
- @counter.increment!(bytes_written: len)
113
- len.tap { @lock.release }
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
- len = @bytes.shift
161
- obj = deserialize(@r.read_nonblock(len.zero? ? 1 : len))
162
- @counter.increment!(bytes_read: len)
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
- # @return [Integer]
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
- # @endgroup
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Chan
4
- VERSION = "0.21.0"
4
+ VERSION = "0.23.0"
5
5
  end
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
- gem.add_runtime_dependency "lockf.rb", "~> 3.0"
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.21.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: lockf.rb
13
+ name: fiddle
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: '3.0'
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: '3.0'
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: 3.6.9
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: []