xchan.rb 0.23.0 → 0.24.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: 4bf62c9fb6b3813e464c25bcd2e99f860a7a106ff85ea3e8e564f8a0d16e160b
4
- data.tar.gz: 1e1868a087396c56e176c9fff11d4086e4b30d6d5cc09968c48261212317e8dc
3
+ metadata.gz: 181f4b9e1add150781f56e06f8d6d011a7474e55a501a6dce1713c975d52280d
4
+ data.tar.gz: 96b2056582afaa5f67f774c626a21cb9f8feadb09aea346150bcf685660e4dce
5
5
  SHA512:
6
- metadata.gz: '0095b2e81e0f76c47fb8f3fc402945956b9865b16e119e85f2d1aa3e9ab1ff90e7ed63214871298bea7da759a7a7f9b8c38a57c87c0bf5d541d3ae6491be1956'
7
- data.tar.gz: 5b21ab069f5be98a2f14fa596492654a73b90efb5e25a670cbb3aa81f034927ef77e954d589dab1504f627010933f335ba84f84e0749fe236c802b040d29a6eb
6
+ metadata.gz: ab568cfe894198659cb45e72759dfa7daa95b290d647a1d633225e83093eb86f28b1a2c13e47b38d8626d2a275cbd80364416b15dbff050c6e2ba4ac36aff76c
7
+ data.tar.gz: 2a45fd7441fb2312d1fcfce43ad6f53fe60ad7c304a833667a22e7024c06a74ad21b6b235b1950835e71ddd49f43b03c958662ed92b746bc52829cead23db9da
data/README.md CHANGED
@@ -1,4 +1,16 @@
1
- ## About
1
+ <p align="center">
2
+ <a href="https://r.uby.dev">
3
+ <img
4
+ src="rubydev.svg"
5
+ width="400"
6
+ height="200"
7
+ border="0"
8
+ alt="a r.uby.dev project"
9
+ >
10
+ </a>
11
+ </p>
12
+
13
+ > [r.uby.dev](https://r.uby.dev/llm) project.
2
14
 
3
15
  xchan.rb is an easy to use library for InterProcess Communication (IPC).
4
16
 
@@ -245,22 +257,12 @@ print "The maximum size of a single message is: ", sndbuf.int, " bytes.\n"
245
257
  # The maximum size of a single message is: 2048 bytes.
246
258
  ```
247
259
 
248
- ## Documentation
249
-
250
- A complete API reference is available at
251
- [0x1eef.github.io/x/xchan.rb](https://0x1eef.github.io/x/xchan.rb/)
252
-
253
260
  ## Install
254
261
 
255
262
  xchan.rb can be installed via rubygems.org:
256
263
 
257
264
  gem install xchan.rb
258
265
 
259
- ## Sources
260
-
261
- * [github.com/@0x1eef](https://github.com/0x1eef/xchan.rb#readme)
262
- * [gitlab.com/@0x1eef](https://gitlab.com/0x1eef/xchan.rb#about)
263
-
264
266
  ## License
265
267
 
266
268
  [BSD Zero Clause](https://choosealicense.com/licenses/0bsd/)
@@ -285,13 +285,35 @@ class Chan::UNIXSocket
285
285
  end
286
286
 
287
287
  ##
288
- # Waits for the channel to become lockable
288
+ # Waits for the channel to become lockable, and takes the lock.
289
+ #
290
+ # Without a timeout the wait is `lockf(F_LOCK)`, which blocks in the
291
+ # kernel: the releaser wakes the waiter, so there is no interval to poll
292
+ # on - a lock held for microseconds is released with a wakeup rather than
293
+ # up to a tick of the loop below.
294
+ #
295
+ # **The caller comes back holding the lock**, which is what the retry in
296
+ # `send` and `recv` expects, and why the release paths are theirs. With a
297
+ # timeout the channel comes back as it was, because that loop gives up
298
+ # rather than acquires.
299
+ #
300
+ # The acquisition is no longer under `@mutex`, where it used to be - only
301
+ # the release is. With threads the two ends can therefore belong to
302
+ # different threads, which is a redundant retry at worst: `lockf` locks
303
+ # are held per process and give no intra-process exclusion at all, and
304
+ # every socket operation still happens under a successfully taken
305
+ # `F_TLOCK`.
306
+ #
289
307
  # @param [Float, Integer, nil] timeout
290
308
  # The number of seconds to wait before timeout.
291
309
  # Waits indefinitely with no arguments
292
310
  # @return [Chan::UNIXSocket, nil]
293
311
  # Returns self when the channel is lockable, otherwise returns nil
294
312
  def wait_lockable(timeout = nil)
313
+ if timeout.nil?
314
+ @lock.lock
315
+ return self
316
+ end
295
317
  start = (timeout ? gettime : nil)
296
318
  loop do
297
319
  break(nil) if start && (gettime - start) >= timeout
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.23.0"
4
+ VERSION = "0.24.0"
5
5
  end
data/test/xchan_test.rb CHANGED
@@ -227,6 +227,8 @@ end
227
227
  ##
228
228
  # Chan::UNIXSocket#wait_lockable
229
229
  class Chan::WaitLockableTest < Chan::Test
230
+ include Timeout
231
+
230
232
  def test_wait_lockable_on_lockable_channel
231
233
  assert_instance_of Chan::UNIXSocket, ch.wait_lockable
232
234
  end
@@ -241,6 +243,27 @@ class Chan::WaitLockableTest < Chan::Test
241
243
  aux.close
242
244
  end
243
245
 
246
+ ##
247
+ # Without a timeout the wait is a blocking lock rather than a loop, so
248
+ # the answer can only arrive because the release woke the child - a lock
249
+ # that was never contended would answer either way, and a timeout would
250
+ # answer before the release at all.
251
+ def test_wait_lockable_without_a_timeout_on_a_locked_channel
252
+ aux = xchan(:pure)
253
+ lock! do
254
+ pid = fork { aux.send ch.wait_lockable.class.to_s }
255
+ ##
256
+ # Long enough that the child is inside the lock rather than between
257
+ # two calls, and then the release.
258
+ sleep 0.1
259
+ release!
260
+ Process.wait(pid)
261
+ end
262
+ assert_equal "Chan::UNIXSocket", timeout(5) { aux.recv }
263
+ ensure
264
+ aux.close
265
+ end
266
+
244
267
  def test_wait_lockable_on_null_lock
245
268
  ch = xchan(:pure, lock: :null)
246
269
  assert_instance_of Chan::UNIXSocket, ch.wait_lockable
@@ -261,4 +284,3 @@ class Chan::WaitLockableTest < Chan::Test
261
284
  ch.instance_variable_get(:@lock).release
262
285
  end
263
286
  end
264
-
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.23.0
4
+ version: 0.24.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - '0x1eef'