xchan.rb 0.18.0 → 0.20.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/README.md +92 -19
- data/lib/xchan/bytes.rb +7 -12
- data/lib/xchan/counter.rb +32 -18
- data/lib/xchan/null_lock.rb +44 -0
- data/lib/xchan/tempfile.rb +2 -2
- data/lib/xchan/unix_socket.rb +45 -50
- data/lib/xchan/version.rb +1 -1
- data/lib/xchan.rb +14 -5
- data/share/xchan.rb/examples/read_operations/1_blocking_read.rb +1 -0
- data/share/xchan.rb/examples/read_operations/2_nonblocking_read.rb +1 -0
- data/share/xchan.rb/examples/serialization/1_serializers.rb +1 -1
- data/share/xchan.rb/examples/socket/{2_options.rb → 1_options.rb} +3 -0
- data/share/xchan.rb/examples/write_operations/1_blocking_write.rb +2 -1
- data/share/xchan.rb/examples/write_operations/2_nonblocking_write.rb +2 -1
- data/test/readme_test.rb +3 -3
- data/test/xchan_test.rb +40 -1
- data/xchan.rb.gemspec +10 -3
- metadata +24 -20
- data/.github/workflows/tests.yml +0 -26
- data/.gitignore +0 -8
- data/.projectile +0 -5
- data/.rubocop.yml +0 -34
- data/.yardopts +0 -4
- data/Gemfile +0 -4
- data/LICENSE +0 -15
- data/Rakefile.rb +0 -9
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3faafc7100339e243744b476b137e7ee96591179027c862509006c60df6c7fe1
|
|
4
|
+
data.tar.gz: b7abc06e3a789f1f80a171e520c2cd3a64126c11e8bc01795bf90c4fcb5601bc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1a14ea31ccd8ae96a56d4dfc667fe0141906a8d0123f3ba184e524ad07b4586b205501c870aec02f0af33d47d6ac8b788f023174afcddf8d6d1b90e853a3b40b
|
|
7
|
+
data.tar.gz: 98c9e23a2abd39852fdd315011c44385b6c57a1a9a000e0d9430580a36a3970091857482d7866c58c765015fce7cbb6523a9b3e411daa2c5520b79f911efaf05
|
data/README.md
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
|
+
> **Designed for minimalism** <br>
|
|
2
|
+
> One direct runtime dependency ([lockf.rb](https://github.com/0x1eef/lockf.rb#readme)) <br>
|
|
3
|
+
> Zero indirect dependencies outside Ruby's standard library
|
|
4
|
+
|
|
1
5
|
## About
|
|
2
6
|
|
|
3
|
-
xchan.rb is an easy to use library for
|
|
4
|
-
Communication (IPC). The library provides a channel
|
|
7
|
+
xchan.rb is an easy to use, minimalist library for
|
|
8
|
+
InterProcess Communication (IPC). The library provides a channel
|
|
5
9
|
that can help facilitate communication between Ruby
|
|
6
10
|
processes who have a parent <=> child relationship.
|
|
11
|
+
A channel lock is provided by
|
|
12
|
+
[lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3) and a temporary, unlinked file to protect against race conditions
|
|
13
|
+
that can happen when multiple processes access the same channel
|
|
14
|
+
at the same time.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
* Minimalist Inter-Process Communication (IPC) for parent <=> child processes.
|
|
19
|
+
* Channel-based communication.
|
|
20
|
+
* Support for multiple serializers (`:marshal`, `:json`, `:yaml`) and raw string communication (`:pure`).
|
|
21
|
+
* Blocking (`#send`, `#recv`) and non-blocking (`#send_nonblock`, `#recv_nonblock`) operations.
|
|
22
|
+
* Built-in file-based locking ([lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3)) to prevent race conditions.
|
|
23
|
+
* Option to use a null lock for scenarios where locking is not needed.
|
|
24
|
+
* Access to underlying UNIX sockets for fine-grained control over socket options.
|
|
25
|
+
* Mac, BSD, and Linux support.
|
|
26
|
+
* Good docs.
|
|
7
27
|
|
|
8
28
|
## Examples
|
|
9
29
|
|
|
@@ -19,13 +39,14 @@ serializers are available by default: `xchan(:marshal)`,
|
|
|
19
39
|
`xchan(:json)`, and `xchan(:yaml)`.
|
|
20
40
|
|
|
21
41
|
```ruby
|
|
42
|
+
#!/usr/bin/env ruby
|
|
22
43
|
require "xchan"
|
|
23
44
|
|
|
24
45
|
##
|
|
25
46
|
# Marshal as the serializer
|
|
26
47
|
ch = xchan(:marshal)
|
|
27
48
|
Process.wait fork { ch.send(5) }
|
|
28
|
-
|
|
49
|
+
puts "#{ch.recv} + 7 = 12"
|
|
29
50
|
ch.close
|
|
30
51
|
|
|
31
52
|
##
|
|
@@ -39,11 +60,12 @@ ch.close
|
|
|
39
60
|
The `ch.recv` method performs a blocking read. A read
|
|
40
61
|
can block when a lock is held by another process, or
|
|
41
62
|
when a read from
|
|
42
|
-
[Chan::UNIXSocket#r](https://0x1eef.github
|
|
63
|
+
[Chan::UNIXSocket#r](https://0x1eef.github.io/x/xchan.rb/Chan/UNIXSocket.html#r-instance_method)
|
|
43
64
|
blocks. The example performs a read that blocks until
|
|
44
65
|
the parent process writes to the channel:
|
|
45
66
|
|
|
46
67
|
```ruby
|
|
68
|
+
#!/usr/bin/env ruby
|
|
47
69
|
require "xchan"
|
|
48
70
|
|
|
49
71
|
ch = xchan(:marshal)
|
|
@@ -51,7 +73,7 @@ fork do
|
|
|
51
73
|
print "Received a random number (child process): ", ch.recv, "\n"
|
|
52
74
|
end
|
|
53
75
|
sleep(1)
|
|
54
|
-
|
|
76
|
+
puts "Send a random number (from parent process)"
|
|
55
77
|
ch.send(rand(21))
|
|
56
78
|
ch.close
|
|
57
79
|
Process.wait
|
|
@@ -67,20 +89,22 @@ The non-blocking counterpart to `#recv` is `#recv_nonblock`.
|
|
|
67
89
|
The `#recv_nonblock` method raises `Chan::WaitLockable` when
|
|
68
90
|
a read blocks because of a lock held by another process, and
|
|
69
91
|
the method raises `Chan::WaitReadable` when a read from
|
|
70
|
-
[Chan::UNIXSocket#r](https://0x1eef.github
|
|
92
|
+
[Chan::UNIXSocket#r](https://0x1eef.github.io/x/xchan.rb/Chan/UNIXSocket.html#r-instance_method)
|
|
71
93
|
blocks:
|
|
72
94
|
|
|
73
95
|
```ruby
|
|
96
|
+
#!/usr/bin/env ruby
|
|
74
97
|
require "xchan"
|
|
75
98
|
|
|
76
99
|
def read(ch)
|
|
77
100
|
ch.recv_nonblock
|
|
78
101
|
rescue Chan::WaitReadable
|
|
79
|
-
|
|
102
|
+
puts "Wait 1 second for channel to be readable"
|
|
80
103
|
ch.wait_readable(1)
|
|
81
104
|
retry
|
|
82
105
|
rescue Chan::WaitLockable
|
|
83
|
-
|
|
106
|
+
puts "Wait 1 second for channel to be lockable"
|
|
107
|
+
ch.wait_lockable(1)
|
|
84
108
|
retry
|
|
85
109
|
end
|
|
86
110
|
trap("SIGINT") { exit(1) }
|
|
@@ -99,13 +123,14 @@ read(xchan(:marshal))
|
|
|
99
123
|
The `ch.send` method performs a blocking write.
|
|
100
124
|
A write can block when a lock is held by another
|
|
101
125
|
process, or when a write to
|
|
102
|
-
[Chan::UNIXSocket#w](https://0x1eef.github
|
|
126
|
+
[Chan::UNIXSocket#w](https://0x1eef.github.io/x/xchan.rb/Chan/UNIXSocket.html#w-instance_method)
|
|
103
127
|
blocks. The example fills the send buffer:
|
|
104
128
|
|
|
105
129
|
```ruby
|
|
130
|
+
#!/usr/bin/env ruby
|
|
106
131
|
require "xchan"
|
|
107
132
|
|
|
108
|
-
ch = xchan(:marshal,
|
|
133
|
+
ch = xchan(:marshal, sock: Socket::SOCK_STREAM)
|
|
109
134
|
sndbuf = ch.w.getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF)
|
|
110
135
|
while ch.bytes_sent <= sndbuf.int
|
|
111
136
|
ch.send(1)
|
|
@@ -119,24 +144,25 @@ The non-blocking counterpart to `#send` is
|
|
|
119
144
|
`Chan::WaitLockable` when a write blocks because of
|
|
120
145
|
a lock held by another process, and the method raises
|
|
121
146
|
`Chan::WaitWritable` when a write to
|
|
122
|
-
[Chan::UNIXSocket#w](https://0x1eef.github
|
|
147
|
+
[Chan::UNIXSocket#w](https://0x1eef.github.io/x/xchan.rb/Chan/UNIXSocket.html#w-instance_method)
|
|
123
148
|
blocks. The example frees space on the send buffer:
|
|
124
149
|
|
|
125
150
|
```ruby
|
|
151
|
+
#!/usr/bin/env ruby
|
|
126
152
|
require "xchan"
|
|
127
153
|
|
|
128
154
|
def send_nonblock(ch, buf)
|
|
129
155
|
ch.send_nonblock(buf)
|
|
130
156
|
rescue Chan::WaitWritable
|
|
131
|
-
|
|
157
|
+
puts "Blocked - free send buffer"
|
|
132
158
|
ch.recv
|
|
133
159
|
retry
|
|
134
160
|
rescue Chan::WaitLockable
|
|
135
|
-
|
|
161
|
+
ch.wait_lockable
|
|
136
162
|
retry
|
|
137
163
|
end
|
|
138
164
|
|
|
139
|
-
ch = xchan(:marshal,
|
|
165
|
+
ch = xchan(:marshal, sock: Socket::SOCK_STREAM)
|
|
140
166
|
sndbuf = ch.w.getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF)
|
|
141
167
|
while ch.bytes_sent <= sndbuf.int
|
|
142
168
|
send_nonblock(ch, 1)
|
|
@@ -146,18 +172,65 @@ end
|
|
|
146
172
|
# Blocked - free send buffer
|
|
147
173
|
```
|
|
148
174
|
|
|
175
|
+
### Lock
|
|
176
|
+
|
|
177
|
+
#### File
|
|
178
|
+
|
|
179
|
+
The default lock for a channel is a file lock. The locking mechanism is
|
|
180
|
+
implemented with the
|
|
181
|
+
[lockf](https://man.freebsd.org/cgi/man.cgi?query=lockf&apropos=0&sektion=3&manpath=FreeBSD+14.2-RELEASE+and+Ports&arch=default&format=html)
|
|
182
|
+
function from the C standard library. Nothing special has to be done to
|
|
183
|
+
use it, and it allows a channel to be safely accessed across multiple
|
|
184
|
+
processes:
|
|
185
|
+
|
|
186
|
+
```ruby
|
|
187
|
+
#!/usr/bin/env ruby
|
|
188
|
+
require "xchan"
|
|
189
|
+
|
|
190
|
+
##
|
|
191
|
+
# 'lock: :file' is added just for the example
|
|
192
|
+
# It is the default behavior, and not necessary
|
|
193
|
+
ch = xchan(:marshal, lock: :file)
|
|
194
|
+
5.times.map do
|
|
195
|
+
fork do
|
|
196
|
+
ch.send(5)
|
|
197
|
+
end
|
|
198
|
+
end.each { Process.wait(_1) }
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### Null
|
|
202
|
+
|
|
203
|
+
The null lock is the same as using no lock at all. The null lock is
|
|
204
|
+
implemented as a collection of no-op operations. The null lock is
|
|
205
|
+
implemented in the
|
|
206
|
+
[Chan::NullLock](https://0x1eef.github.io/x/xchan.rb/Chan/NullLock.html)
|
|
207
|
+
class, and in certain situations, it can be useful and preferable
|
|
208
|
+
to using a file lock:
|
|
209
|
+
|
|
210
|
+
```ruby
|
|
211
|
+
#!/usr/bin/env ruby
|
|
212
|
+
require "xchan"
|
|
213
|
+
|
|
214
|
+
ch = xchan(:marshal, lock: :null)
|
|
215
|
+
fork do
|
|
216
|
+
ch.send(5)
|
|
217
|
+
end
|
|
218
|
+
Process.wait
|
|
219
|
+
```
|
|
220
|
+
|
|
149
221
|
### Socket
|
|
150
222
|
|
|
151
223
|
#### Options
|
|
152
224
|
|
|
153
225
|
A channel has one socket for read operations and another
|
|
154
226
|
socket for write operations.
|
|
155
|
-
[Chan::UNIXSocket#r](https://0x1eef.github
|
|
227
|
+
[Chan::UNIXSocket#r](https://0x1eef.github.io/x/xchan.rb/Chan/UNIXSocket.html#r-instance_method)
|
|
156
228
|
returns the socket used for read operations, and
|
|
157
|
-
[Chan::UNIXSocket#w](https://0x1eef.github
|
|
229
|
+
[Chan::UNIXSocket#w](https://0x1eef.github.io/x/xchan.rb/Chan/UNIXSocket.html#w-instance_method)
|
|
158
230
|
returns the socket used for write operations:
|
|
159
231
|
|
|
160
232
|
```ruby
|
|
233
|
+
#!/usr/bin/env ruby
|
|
161
234
|
require "xchan"
|
|
162
235
|
ch = xchan(:marshal)
|
|
163
236
|
|
|
@@ -189,11 +262,11 @@ xchan.rb can be installed via rubygems.org:
|
|
|
189
262
|
|
|
190
263
|
## Sources
|
|
191
264
|
|
|
192
|
-
* [
|
|
193
|
-
* [
|
|
265
|
+
* [github.com/@0x1eef](https://github.com/0x1eef/xchan.rb#readme)
|
|
266
|
+
* [gitlab.com/@0x1eef](https://gitlab.com/0x1eef/xchan.rb#about)
|
|
194
267
|
|
|
195
268
|
## License
|
|
196
269
|
|
|
197
270
|
[BSD Zero Clause](https://choosealicense.com/licenses/0bsd/)
|
|
198
271
|
<br>
|
|
199
|
-
See [LICENSE](./LICENSE)
|
|
272
|
+
See [share/xchan.rb/LICENSE](./share/xchan.rb/LICENSE)
|
data/lib/xchan/bytes.rb
CHANGED
|
@@ -7,26 +7,23 @@
|
|
|
7
7
|
# increases in size, and when an object is read from
|
|
8
8
|
# a channel, the collection decreases in size.
|
|
9
9
|
class Chan::Bytes
|
|
10
|
-
require "json"
|
|
11
10
|
require_relative "counter"
|
|
12
11
|
|
|
13
12
|
##
|
|
14
13
|
# @param [String] tmpdir
|
|
15
14
|
# Directory where temporary files are stored
|
|
16
|
-
#
|
|
17
15
|
# @return [Chan::Bytes]
|
|
18
16
|
def initialize(tmpdir)
|
|
19
|
-
@io = Chan.temporary_file(%w[bytes .
|
|
17
|
+
@io = Chan.temporary_file(%w[bytes .bin], tmpdir:)
|
|
18
|
+
@io.binmode
|
|
20
19
|
@io.sync = true
|
|
21
20
|
write(@io, [])
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
##
|
|
25
24
|
# Adds a count to the start of the collection
|
|
26
|
-
#
|
|
27
25
|
# @param [Integer] len
|
|
28
26
|
# The bytesize of an object
|
|
29
|
-
#
|
|
30
27
|
# @return [void]
|
|
31
28
|
def unshift(len)
|
|
32
29
|
return 0 if len.nil? || len.zero?
|
|
@@ -38,10 +35,8 @@ class Chan::Bytes
|
|
|
38
35
|
|
|
39
36
|
##
|
|
40
37
|
# Adds a count to the end of the collection
|
|
41
|
-
#
|
|
42
38
|
# @param [Integer] len
|
|
43
39
|
# The bytesize of an object
|
|
44
|
-
#
|
|
45
40
|
# @return [void]
|
|
46
41
|
def push(len)
|
|
47
42
|
return 0 if len.nil? || len.zero?
|
|
@@ -53,7 +48,6 @@ class Chan::Bytes
|
|
|
53
48
|
|
|
54
49
|
##
|
|
55
50
|
# Removes a count from the start of the collection
|
|
56
|
-
#
|
|
57
51
|
# @return [Integer]
|
|
58
52
|
# Returns the removed byte count
|
|
59
53
|
def shift
|
|
@@ -73,7 +67,6 @@ class Chan::Bytes
|
|
|
73
67
|
|
|
74
68
|
##
|
|
75
69
|
# Close the underlying IO
|
|
76
|
-
#
|
|
77
70
|
# @return [void]
|
|
78
71
|
def close
|
|
79
72
|
@io.close
|
|
@@ -86,15 +79,17 @@ class Chan::Bytes
|
|
|
86
79
|
end
|
|
87
80
|
|
|
88
81
|
def write(io, bytes)
|
|
82
|
+
io.rewind
|
|
89
83
|
io.truncate(0)
|
|
90
|
-
io.write(serialize(bytes))
|
|
84
|
+
io.write(serialize(bytes))
|
|
85
|
+
io.rewind
|
|
91
86
|
end
|
|
92
87
|
|
|
93
88
|
def serialize(bytes)
|
|
94
|
-
|
|
89
|
+
bytes.pack("Q>*")
|
|
95
90
|
end
|
|
96
91
|
|
|
97
92
|
def deserialize(bytes)
|
|
98
|
-
|
|
93
|
+
bytes.unpack("Q>*")
|
|
99
94
|
end
|
|
100
95
|
end
|
data/lib/xchan/counter.rb
CHANGED
|
@@ -5,58 +5,72 @@
|
|
|
5
5
|
# for the number of written and received bytes on a
|
|
6
6
|
# given channel.
|
|
7
7
|
class Chan::Counter
|
|
8
|
-
require "json"
|
|
9
|
-
|
|
10
8
|
##
|
|
11
9
|
# @param [String] tmpdir
|
|
12
10
|
# Directory where temporary files are stored
|
|
13
|
-
#
|
|
14
11
|
# @return [Chan::Counter]
|
|
15
12
|
def initialize(tmpdir)
|
|
16
|
-
@io = Chan.temporary_file(%w[counter .
|
|
17
|
-
|
|
13
|
+
@io = Chan.temporary_file(%w[counter .bin], tmpdir:)
|
|
14
|
+
@io.binmode
|
|
15
|
+
@io.sync = true
|
|
16
|
+
write(@io, 0, 0)
|
|
18
17
|
end
|
|
19
18
|
|
|
20
19
|
##
|
|
21
20
|
# @return [Integer]
|
|
22
21
|
# Returns the number of bytes written to a channel
|
|
23
22
|
def bytes_written
|
|
24
|
-
read(@io)
|
|
23
|
+
_, bytes = read(@io)
|
|
24
|
+
bytes
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
##
|
|
28
28
|
# @return [Integer]
|
|
29
29
|
# Returns the number of bytes read from a channel
|
|
30
30
|
def bytes_read
|
|
31
|
-
read(@io)
|
|
31
|
+
bytes, _ = read(@io)
|
|
32
|
+
bytes
|
|
32
33
|
end
|
|
33
34
|
|
|
34
35
|
##
|
|
35
|
-
# @param [
|
|
36
|
+
# @param [Integer] bytes_read
|
|
37
|
+
# Number of bytes read to increment the counter by
|
|
38
|
+
# @param [Integer] bytes_written
|
|
39
|
+
# Number of bytes written to increment the counter by
|
|
36
40
|
# @return [void]
|
|
37
41
|
# @private
|
|
38
|
-
def increment!(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
def increment!(bytes_read: 0, bytes_written: 0)
|
|
43
|
+
bytes_in, bytes_out = read(@io)
|
|
44
|
+
bytes_in += bytes_read
|
|
45
|
+
bytes_out += bytes_written
|
|
46
|
+
write(@io, bytes_in, bytes_out)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
##
|
|
50
|
+
# Close the counter
|
|
51
|
+
# @return [void]
|
|
52
|
+
def close
|
|
53
|
+
@io.close
|
|
42
54
|
end
|
|
43
55
|
|
|
44
56
|
private
|
|
45
57
|
|
|
46
|
-
def write(io,
|
|
58
|
+
def write(io, bytes_read, bytes_written)
|
|
59
|
+
io.rewind
|
|
47
60
|
io.truncate(0)
|
|
48
|
-
io.write(serialize(
|
|
61
|
+
io.write(serialize(bytes_read, bytes_written))
|
|
62
|
+
io.rewind
|
|
49
63
|
end
|
|
50
64
|
|
|
51
65
|
def read(io)
|
|
52
66
|
deserialize(io.read).tap { io.rewind }
|
|
53
67
|
end
|
|
54
68
|
|
|
55
|
-
def serialize(
|
|
56
|
-
|
|
69
|
+
def serialize(bytes_read, bytes_written)
|
|
70
|
+
[bytes_read, bytes_written].pack("Q>Q>")
|
|
57
71
|
end
|
|
58
72
|
|
|
59
|
-
def deserialize(
|
|
60
|
-
|
|
73
|
+
def deserialize(payload)
|
|
74
|
+
payload.unpack("Q>Q>")
|
|
61
75
|
end
|
|
62
76
|
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
##
|
|
4
|
+
# {Chan::NullLock Chan::NullLock} is a no-op lock that can be used
|
|
5
|
+
# instead of the standard file lock when a lock is not needed
|
|
6
|
+
#
|
|
7
|
+
# @example
|
|
8
|
+
# ch = xchan(:marshal, lock: Chan::NullLock)
|
|
9
|
+
# ch.send([1,2,3])
|
|
10
|
+
# # ditto
|
|
11
|
+
# ch = xchan(:marshal, lock: :null)
|
|
12
|
+
# ch.send([1,2,3])
|
|
13
|
+
class Chan::NullLock
|
|
14
|
+
##
|
|
15
|
+
# @return [void]
|
|
16
|
+
# This method is a no-op
|
|
17
|
+
def self.lock
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# @return [void]
|
|
22
|
+
# This method is a no-op
|
|
23
|
+
def self.lock_nonblock
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
##
|
|
27
|
+
# @return [void]
|
|
28
|
+
# This method is a no-op
|
|
29
|
+
def self.release
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
##
|
|
33
|
+
# @return [void]
|
|
34
|
+
# This method is a no-op
|
|
35
|
+
def self.close
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
##
|
|
39
|
+
# @return [true]
|
|
40
|
+
# Always returns true
|
|
41
|
+
def self.lockable?
|
|
42
|
+
true
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/xchan/tempfile.rb
CHANGED
data/lib/xchan/unix_socket.rb
CHANGED
|
@@ -29,24 +29,22 @@ class Chan::UNIXSocket
|
|
|
29
29
|
# ch.send([1,2,3])
|
|
30
30
|
# ch.recv.pop # => 3
|
|
31
31
|
# ch.close
|
|
32
|
-
#
|
|
33
|
-
# @param [Symbol, <#dump, #load>] s
|
|
32
|
+
# @param [Symbol, <#dump, #load>] serializer
|
|
34
33
|
# The name of a serializer
|
|
35
|
-
#
|
|
36
|
-
# @param [Integer] sock_type
|
|
34
|
+
# @param [Integer] sock
|
|
37
35
|
# Type of socket (eg `Socket::SOCK_STREAM`)
|
|
38
|
-
#
|
|
39
36
|
# @param [String] tmpdir
|
|
40
37
|
# Directory where temporary files can be stored
|
|
41
|
-
#
|
|
38
|
+
# @param [Symbol, <Lock::File, Chan::NullLock>] lock
|
|
39
|
+
# The name of a lock, or an instance of `Lock::File`, or {Chan::NullLock Chan::NullLock}
|
|
42
40
|
# @return [Chan::UNIXSocket]
|
|
43
41
|
# Returns an instance of {Chan::UNIXSocket Chan::UNIXSocket}
|
|
44
|
-
def initialize(
|
|
45
|
-
@s = Chan.serializers[
|
|
46
|
-
@r, @w = ::UNIXSocket.pair(
|
|
42
|
+
def initialize(serializer, sock: Socket::SOCK_DGRAM, tmpdir: Dir.tmpdir, lock: :file)
|
|
43
|
+
@s = Chan.serializers[serializer]&.call || serializer
|
|
44
|
+
@r, @w = ::UNIXSocket.pair(sock)
|
|
47
45
|
@bytes = Chan::Bytes.new(tmpdir)
|
|
48
46
|
@counter = Chan::Counter.new(tmpdir)
|
|
49
|
-
@
|
|
47
|
+
@lock = Chan.locks[lock]&.call(tmpdir) || lock
|
|
50
48
|
end
|
|
51
49
|
|
|
52
50
|
##
|
|
@@ -58,17 +56,15 @@ class Chan::UNIXSocket
|
|
|
58
56
|
|
|
59
57
|
##
|
|
60
58
|
# Closes the channel
|
|
61
|
-
#
|
|
62
59
|
# @raise [IOError]
|
|
63
60
|
# When the channel is closed
|
|
64
|
-
#
|
|
65
61
|
# @return [void]
|
|
66
62
|
def close
|
|
67
|
-
@
|
|
68
|
-
raise IOError, "channel
|
|
69
|
-
[@r, @w, @bytes, @
|
|
63
|
+
@lock.lock
|
|
64
|
+
raise IOError, "closed channel" if closed?
|
|
65
|
+
[@r, @w, @bytes, @counter, @lock].each(&:close)
|
|
70
66
|
rescue IOError => ex
|
|
71
|
-
@
|
|
67
|
+
@lock.release
|
|
72
68
|
raise(ex)
|
|
73
69
|
end
|
|
74
70
|
|
|
@@ -77,13 +73,10 @@ class Chan::UNIXSocket
|
|
|
77
73
|
|
|
78
74
|
##
|
|
79
75
|
# Performs a blocking write
|
|
80
|
-
#
|
|
81
76
|
# @param [Object] object
|
|
82
77
|
# An object
|
|
83
|
-
#
|
|
84
78
|
# @raise [IOError]
|
|
85
79
|
# When the channel is closed
|
|
86
|
-
#
|
|
87
80
|
# @return [Object]
|
|
88
81
|
# Returns the number of bytes written to the channel
|
|
89
82
|
def send(object)
|
|
@@ -95,30 +88,25 @@ class Chan::UNIXSocket
|
|
|
95
88
|
|
|
96
89
|
##
|
|
97
90
|
# Performs a non-blocking write
|
|
98
|
-
#
|
|
99
91
|
# @param [Object] object
|
|
100
92
|
# An object
|
|
101
|
-
#
|
|
102
93
|
# @raise [IOError]
|
|
103
94
|
# When the channel is closed
|
|
104
|
-
#
|
|
105
95
|
# @raise [Chan::WaitWritable]
|
|
106
96
|
# When a write to {#w} blocks
|
|
107
|
-
#
|
|
108
97
|
# @raise [Chan::WaitLockable]
|
|
109
98
|
# When a write blocks because of a lock held by another process
|
|
110
|
-
#
|
|
111
99
|
# @return [Integer, nil]
|
|
112
100
|
# Returns the number of bytes written to the channel
|
|
113
101
|
def send_nonblock(object)
|
|
114
|
-
@
|
|
102
|
+
@lock.lock_nonblock
|
|
115
103
|
raise IOError, "channel closed" if closed?
|
|
116
104
|
len = @w.write_nonblock(serialize(object))
|
|
117
105
|
@bytes.push(len)
|
|
118
106
|
@counter.increment!(bytes_written: len)
|
|
119
|
-
len.tap { @
|
|
107
|
+
len.tap { @lock.release }
|
|
120
108
|
rescue IOError, IO::WaitWritable, Errno::ENOBUFS => ex
|
|
121
|
-
@
|
|
109
|
+
@lock.release
|
|
122
110
|
raise Chan::WaitWritable, ex.message
|
|
123
111
|
rescue Errno::EWOULDBLOCK => ex
|
|
124
112
|
raise Chan::WaitLockable, ex.message
|
|
@@ -133,10 +121,8 @@ class Chan::UNIXSocket
|
|
|
133
121
|
|
|
134
122
|
##
|
|
135
123
|
# Performs a blocking read
|
|
136
|
-
#
|
|
137
124
|
# @raise [IOError]
|
|
138
125
|
# When the channel is closed
|
|
139
|
-
#
|
|
140
126
|
# @return [Object]
|
|
141
127
|
# Returns an object from the channel
|
|
142
128
|
def recv
|
|
@@ -151,31 +137,27 @@ class Chan::UNIXSocket
|
|
|
151
137
|
|
|
152
138
|
##
|
|
153
139
|
# Performs a non-blocking read
|
|
154
|
-
#
|
|
155
140
|
# @raise [IOError]
|
|
156
141
|
# When the channel is closed
|
|
157
|
-
#
|
|
158
142
|
# @raise [Chan::WaitReadable]
|
|
159
143
|
# When a read from {#r} blocks
|
|
160
|
-
#
|
|
161
144
|
# @raise [Chan::WaitLockable]
|
|
162
145
|
# When a read blocks because of a lock held by another process
|
|
163
|
-
#
|
|
164
146
|
# @return [Object]
|
|
165
147
|
# Returns an object from the channel
|
|
166
148
|
def recv_nonblock
|
|
167
|
-
@
|
|
149
|
+
@lock.lock_nonblock
|
|
168
150
|
raise IOError, "closed channel" if closed?
|
|
169
151
|
len = @bytes.shift
|
|
170
152
|
obj = deserialize(@r.read_nonblock(len.zero? ? 1 : len))
|
|
171
153
|
@counter.increment!(bytes_read: len)
|
|
172
|
-
obj.tap { @
|
|
154
|
+
obj.tap { @lock.release }
|
|
173
155
|
rescue IOError => ex
|
|
174
|
-
@
|
|
156
|
+
@lock.release
|
|
175
157
|
raise(ex)
|
|
176
158
|
rescue IO::WaitReadable => ex
|
|
177
159
|
@bytes.unshift(len)
|
|
178
|
-
@
|
|
160
|
+
@lock.release
|
|
179
161
|
raise Chan::WaitReadable, ex.message
|
|
180
162
|
rescue Errno::EAGAIN => ex
|
|
181
163
|
raise Chan::WaitLockable, ex.message
|
|
@@ -190,7 +172,6 @@ class Chan::UNIXSocket
|
|
|
190
172
|
# ch = xchan(:pure)
|
|
191
173
|
# 1.upto(4) { ch.send(_1) }
|
|
192
174
|
# ch.to_a.last # => "4"
|
|
193
|
-
#
|
|
194
175
|
# @return [Array<Object>]
|
|
195
176
|
# Returns the contents of the channel
|
|
196
177
|
def to_a
|
|
@@ -241,26 +222,36 @@ class Chan::UNIXSocket
|
|
|
241
222
|
|
|
242
223
|
##
|
|
243
224
|
# Waits for the channel to become readable
|
|
244
|
-
#
|
|
245
|
-
# @param [Float, Integer, nil] s
|
|
225
|
+
# @param [Float, Integer, nil] timeout
|
|
246
226
|
# The number of seconds to wait. Waits indefinitely with no arguments.
|
|
247
|
-
#
|
|
248
227
|
# @return [Chan::UNIXSocket, nil]
|
|
249
228
|
# Returns self when the channel is readable, otherwise returns nil
|
|
250
|
-
def wait_readable(
|
|
251
|
-
@r.wait_readable(
|
|
229
|
+
def wait_readable(timeout = nil)
|
|
230
|
+
@r.wait_readable(timeout) and self
|
|
252
231
|
end
|
|
253
232
|
|
|
254
233
|
##
|
|
255
234
|
# Waits for the channel to become writable
|
|
256
|
-
#
|
|
257
|
-
# @param [Float, Integer, nil] s
|
|
235
|
+
# @param [Float, Integer, nil] timeout
|
|
258
236
|
# The number of seconds to wait. Waits indefinitely with no arguments.
|
|
259
|
-
#
|
|
260
237
|
# @return [Chan::UNIXSocket, nil]
|
|
261
238
|
# Returns self when the channel is writable, otherwise returns nil
|
|
262
|
-
def wait_writable(
|
|
263
|
-
@w.wait_writable(
|
|
239
|
+
def wait_writable(timeout = nil)
|
|
240
|
+
@w.wait_writable(timeout) and self
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
##
|
|
244
|
+
# Waits for the channel to become lockable
|
|
245
|
+
# @param [Float, Integer, nil] timeout
|
|
246
|
+
# The number of seconds to wait before timeout
|
|
247
|
+
# @return [Chan::UNIXSocket, nil]
|
|
248
|
+
def wait_lockable(timeout = nil)
|
|
249
|
+
start = (timeout ? gettime : nil)
|
|
250
|
+
loop do
|
|
251
|
+
break(nil) if start && (gettime - start) >= timeout
|
|
252
|
+
break(self) if @lock.lockable?
|
|
253
|
+
sleep 0.01
|
|
254
|
+
end
|
|
264
255
|
end
|
|
265
256
|
|
|
266
257
|
##
|
|
@@ -269,10 +260,10 @@ class Chan::UNIXSocket
|
|
|
269
260
|
private
|
|
270
261
|
|
|
271
262
|
def lock
|
|
272
|
-
@
|
|
263
|
+
@lock.lock
|
|
273
264
|
yield
|
|
274
265
|
ensure
|
|
275
|
-
@
|
|
266
|
+
@lock.release
|
|
276
267
|
end
|
|
277
268
|
|
|
278
269
|
def serialize(obj)
|
|
@@ -282,4 +273,8 @@ class Chan::UNIXSocket
|
|
|
282
273
|
def deserialize(str)
|
|
283
274
|
@s.load(str)
|
|
284
275
|
end
|
|
276
|
+
|
|
277
|
+
def gettime
|
|
278
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
279
|
+
end
|
|
285
280
|
end
|
data/lib/xchan/version.rb
CHANGED
data/lib/xchan.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module Chan
|
|
4
4
|
require_relative "xchan/version"
|
|
5
5
|
require_relative "xchan/unix_socket"
|
|
6
|
+
require_relative "xchan/null_lock"
|
|
6
7
|
require_relative "xchan/tempfile"
|
|
7
8
|
|
|
8
9
|
WaitReadable = Class.new(IO::EAGAINWaitReadable)
|
|
@@ -32,10 +33,8 @@ module Chan
|
|
|
32
33
|
#
|
|
33
34
|
# @param [String] basename
|
|
34
35
|
# Basename of the temporary file
|
|
35
|
-
#
|
|
36
36
|
# @param [String] tmpdir
|
|
37
37
|
# Parent directory of the temporary file
|
|
38
|
-
#
|
|
39
38
|
# @return [Chan::Tempfile]
|
|
40
39
|
# Returns an instance of {Chan::Tempfile Chan::Tempfile}
|
|
41
40
|
def self.temporary_file(basename, tmpdir: Dir.tmpdir)
|
|
@@ -59,6 +58,16 @@ module Chan
|
|
|
59
58
|
}
|
|
60
59
|
}
|
|
61
60
|
end
|
|
61
|
+
|
|
62
|
+
##
|
|
63
|
+
# @return [Hash<Symbol, Proc>]
|
|
64
|
+
# Returns the default locks
|
|
65
|
+
def self.locks
|
|
66
|
+
{
|
|
67
|
+
null: lambda { |_tmpdir| Chan::NullLock },
|
|
68
|
+
file: lambda { |tmpdir| Lockf.new Chan.temporary_file(%w[xchan lock], tmpdir:) }
|
|
69
|
+
}
|
|
70
|
+
end
|
|
62
71
|
end
|
|
63
72
|
|
|
64
73
|
module Kernel
|
|
@@ -68,10 +77,10 @@ module Kernel
|
|
|
68
77
|
# ch.send([1,2,3])
|
|
69
78
|
# ch.recv.pop # => 3
|
|
70
79
|
# ch.close
|
|
71
|
-
#
|
|
72
|
-
# @param
|
|
73
|
-
# @param sock_type (see Chan::UNIXSocket#initialize)
|
|
80
|
+
# @param serializer (see Chan::UNIXSocket#initialize)
|
|
81
|
+
# @param sock (see Chan::UNIXSocket#initialize)
|
|
74
82
|
# @param tmpdir (see Chan::UNIXSocket#initialize)
|
|
83
|
+
# @param lock (see Chan::UNIXSocket#initialize)
|
|
75
84
|
# @return (see Chan::UNIXSocket#initialize)
|
|
76
85
|
def xchan(s, ...)
|
|
77
86
|
Chan::UNIXSocket.new(s, ...)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require_relative "../setup"
|
|
4
5
|
require "xchan"
|
|
5
6
|
|
|
6
|
-
ch = xchan(:marshal,
|
|
7
|
+
ch = xchan(:marshal, sock: Socket::SOCK_STREAM)
|
|
7
8
|
sndbuf = ch.w.getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF)
|
|
8
9
|
while ch.bytes_sent <= sndbuf.int
|
|
9
10
|
ch.send(1)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require_relative "../setup"
|
|
@@ -14,7 +15,7 @@ rescue Chan::WaitLockable
|
|
|
14
15
|
retry
|
|
15
16
|
end
|
|
16
17
|
|
|
17
|
-
ch = xchan(:marshal,
|
|
18
|
+
ch = xchan(:marshal, sock: Socket::SOCK_STREAM)
|
|
18
19
|
sndbuf = ch.w.getsockopt(Socket::SOL_SOCKET, Socket::SO_SNDBUF)
|
|
19
20
|
while ch.bytes_sent <= sndbuf.int
|
|
20
21
|
send_nonblock(ch, 1)
|
data/test/readme_test.rb
CHANGED
|
@@ -27,10 +27,10 @@ class Chan::ReadmeTest < Test::Unit::TestCase
|
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def test_socket_2_options
|
|
30
|
-
r = 'The read buffer can contain a maximum of: \d{1,
|
|
31
|
-
'The maximum size of a single message is: \d{1,
|
|
30
|
+
r = 'The read buffer can contain a maximum of: \d{1,7} bytes.\s*' \
|
|
31
|
+
'The maximum size of a single message is: \d{1,7} bytes.\s*'
|
|
32
32
|
assert_match Regexp.new(r),
|
|
33
|
-
cmd("ruby", readme_example("socket/
|
|
33
|
+
cmd("ruby", readme_example("socket/1_options.rb"))
|
|
34
34
|
.stdout
|
|
35
35
|
.tr("\n", " ")
|
|
36
36
|
end
|
data/test/xchan_test.rb
CHANGED
|
@@ -84,7 +84,7 @@ class Chan::RecvNonBlockTest < Chan::Test
|
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def test_recv_nonblock_with_a_lock
|
|
87
|
-
ch.instance_variable_get(:@
|
|
87
|
+
ch.instance_variable_get(:@lock).lock
|
|
88
88
|
pid = fork do
|
|
89
89
|
ch.recv_nonblock
|
|
90
90
|
exit(1)
|
|
@@ -223,3 +223,42 @@ class Chan::TemporaryFileTest < Chan::Test
|
|
|
223
223
|
@file ||= Chan.temporary_file %w[foobar .txt]
|
|
224
224
|
end
|
|
225
225
|
end
|
|
226
|
+
|
|
227
|
+
##
|
|
228
|
+
# Chan::UNIXSocket#wait_lockable
|
|
229
|
+
class Chan::WaitLockableTest < Chan::Test
|
|
230
|
+
def test_wait_lockable_on_lockable_channel
|
|
231
|
+
assert_instance_of Chan::UNIXSocket, ch.wait_lockable
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def test_wait_lockable_on_locked_channel
|
|
235
|
+
aux = xchan(:pure)
|
|
236
|
+
lock! do
|
|
237
|
+
Process.wait fork { aux.send ch.wait_lockable(0.1).class.to_s }
|
|
238
|
+
end
|
|
239
|
+
assert_equal "NilClass", aux.recv
|
|
240
|
+
ensure
|
|
241
|
+
aux.close
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def test_wait_lockable_on_null_lock
|
|
245
|
+
ch = xchan(:pure, lock: :null)
|
|
246
|
+
assert_instance_of Chan::UNIXSocket, ch.wait_lockable
|
|
247
|
+
ensure
|
|
248
|
+
ch.close
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
private
|
|
252
|
+
|
|
253
|
+
def lock!
|
|
254
|
+
ch.instance_variable_get(:@lock).lock
|
|
255
|
+
yield
|
|
256
|
+
ensure
|
|
257
|
+
release!
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def release!
|
|
261
|
+
ch.instance_variable_get(:@lock).release
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
|
data/xchan.rb.gemspec
CHANGED
|
@@ -8,15 +8,22 @@ Gem::Specification.new do |gem|
|
|
|
8
8
|
gem.homepage = "https://github.com/0x1eef/xchan.rb#readme"
|
|
9
9
|
gem.version = Chan::VERSION
|
|
10
10
|
gem.licenses = ["0BSD"]
|
|
11
|
-
gem.files =
|
|
11
|
+
gem.files = Dir[
|
|
12
|
+
"README.md", "LICENSE",
|
|
13
|
+
"share/xchan.rb/**/*.rb",
|
|
14
|
+
"lib/*.rb", "lib/**/*.rb",
|
|
15
|
+
"test/*.rb", "test/**/*.rb",
|
|
16
|
+
"xchan.rb.gemspec"
|
|
17
|
+
]
|
|
12
18
|
gem.require_paths = ["lib"]
|
|
13
19
|
gem.summary = "An easy to use InterProcess Communication (IPC) library"
|
|
14
20
|
gem.description = gem.summary
|
|
15
|
-
gem.add_runtime_dependency "lockf.rb", "~>
|
|
21
|
+
gem.add_runtime_dependency "lockf.rb", "~> 3.0"
|
|
16
22
|
gem.add_development_dependency "test-unit", "~> 3.5.7"
|
|
17
23
|
gem.add_development_dependency "yard", "~> 0.9"
|
|
18
|
-
gem.add_development_dependency "
|
|
24
|
+
gem.add_development_dependency "kramdown", "~> 2.5"
|
|
19
25
|
gem.add_development_dependency "standard", "~> 1.13"
|
|
20
26
|
gem.add_development_dependency "test-cmd.rb", "~> 0.12.4"
|
|
21
27
|
gem.add_development_dependency "rake", "~> 13.1"
|
|
28
|
+
gem.add_development_dependency "irb", "~> 1.14"
|
|
22
29
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: xchan.rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.20.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- '0x1eef'
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: lockf.rb
|
|
@@ -16,14 +15,14 @@ dependencies:
|
|
|
16
15
|
requirements:
|
|
17
16
|
- - "~>"
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
18
|
+
version: '3.0'
|
|
20
19
|
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
23
|
- - "~>"
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '3.0'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
27
|
name: test-unit
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -53,19 +52,19 @@ dependencies:
|
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
53
|
version: '0.9'
|
|
55
54
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
55
|
+
name: kramdown
|
|
57
56
|
requirement: !ruby/object:Gem::Requirement
|
|
58
57
|
requirements:
|
|
59
58
|
- - "~>"
|
|
60
59
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
60
|
+
version: '2.5'
|
|
62
61
|
type: :development
|
|
63
62
|
prerelease: false
|
|
64
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
64
|
requirements:
|
|
66
65
|
- - "~>"
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
67
|
+
version: '2.5'
|
|
69
68
|
- !ruby/object:Gem::Dependency
|
|
70
69
|
name: standard
|
|
71
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -108,6 +107,20 @@ dependencies:
|
|
|
108
107
|
- - "~>"
|
|
109
108
|
- !ruby/object:Gem::Version
|
|
110
109
|
version: '13.1'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: irb
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - "~>"
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '1.14'
|
|
117
|
+
type: :development
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - "~>"
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '1.14'
|
|
111
124
|
description: An easy to use InterProcess Communication (IPC) library
|
|
112
125
|
email:
|
|
113
126
|
- 0x1eef@protonmail.com
|
|
@@ -115,18 +128,11 @@ executables: []
|
|
|
115
128
|
extensions: []
|
|
116
129
|
extra_rdoc_files: []
|
|
117
130
|
files:
|
|
118
|
-
- ".github/workflows/tests.yml"
|
|
119
|
-
- ".gitignore"
|
|
120
|
-
- ".projectile"
|
|
121
|
-
- ".rubocop.yml"
|
|
122
|
-
- ".yardopts"
|
|
123
|
-
- Gemfile
|
|
124
|
-
- LICENSE
|
|
125
131
|
- README.md
|
|
126
|
-
- Rakefile.rb
|
|
127
132
|
- lib/xchan.rb
|
|
128
133
|
- lib/xchan/bytes.rb
|
|
129
134
|
- lib/xchan/counter.rb
|
|
135
|
+
- lib/xchan/null_lock.rb
|
|
130
136
|
- lib/xchan/tempfile.rb
|
|
131
137
|
- lib/xchan/unix_socket.rb
|
|
132
138
|
- lib/xchan/version.rb
|
|
@@ -134,7 +140,7 @@ files:
|
|
|
134
140
|
- share/xchan.rb/examples/read_operations/2_nonblocking_read.rb
|
|
135
141
|
- share/xchan.rb/examples/serialization/1_serializers.rb
|
|
136
142
|
- share/xchan.rb/examples/setup.rb
|
|
137
|
-
- share/xchan.rb/examples/socket/
|
|
143
|
+
- share/xchan.rb/examples/socket/1_options.rb
|
|
138
144
|
- share/xchan.rb/examples/stress_tests/1_parallel_access_stress_test.rb
|
|
139
145
|
- share/xchan.rb/examples/write_operations/1_blocking_write.rb
|
|
140
146
|
- share/xchan.rb/examples/write_operations/2_nonblocking_write.rb
|
|
@@ -146,7 +152,6 @@ homepage: https://github.com/0x1eef/xchan.rb#readme
|
|
|
146
152
|
licenses:
|
|
147
153
|
- 0BSD
|
|
148
154
|
metadata: {}
|
|
149
|
-
post_install_message:
|
|
150
155
|
rdoc_options: []
|
|
151
156
|
require_paths:
|
|
152
157
|
- lib
|
|
@@ -161,8 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
161
166
|
- !ruby/object:Gem::Version
|
|
162
167
|
version: '0'
|
|
163
168
|
requirements: []
|
|
164
|
-
rubygems_version: 3.
|
|
165
|
-
signing_key:
|
|
169
|
+
rubygems_version: 3.6.9
|
|
166
170
|
specification_version: 4
|
|
167
171
|
summary: An easy to use InterProcess Communication (IPC) library
|
|
168
172
|
test_files: []
|
data/.github/workflows/tests.yml
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
name: xchan.rb
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ main ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ main ]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
specs:
|
|
11
|
-
strategy:
|
|
12
|
-
fail-fast: false
|
|
13
|
-
matrix:
|
|
14
|
-
os: [ubuntu-latest, macos-latest]
|
|
15
|
-
ruby: [3.2, 3.3]
|
|
16
|
-
runs-on: ${{ matrix.os }}
|
|
17
|
-
steps:
|
|
18
|
-
- uses: actions/checkout@v2
|
|
19
|
-
- uses: ruby/setup-ruby@v1
|
|
20
|
-
with:
|
|
21
|
-
ruby-version: ${{ matrix.ruby }}
|
|
22
|
-
- run: bundle install
|
|
23
|
-
- run: SERIALIZER=marshal; for t in *_test.rb; do ruby test/${t}; done
|
|
24
|
-
- run: SERIALIZER=json; for t in *_test.rb; do ruby test/${t}; done
|
|
25
|
-
- run: SERIALIZER=yaml; for t in *_test.rb; do ruby test/${t}; done
|
|
26
|
-
- run: SERIALIZER=pure; for t in *_test.rb; do ruby test/${t}; done
|
data/.gitignore
DELETED
data/.projectile
DELETED
data/.rubocop.yml
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
##
|
|
2
|
-
# Plugins
|
|
3
|
-
require:
|
|
4
|
-
- standard
|
|
5
|
-
|
|
6
|
-
##
|
|
7
|
-
# Defaults: standard-rb
|
|
8
|
-
inherit_gem:
|
|
9
|
-
standard: config/base.yml
|
|
10
|
-
|
|
11
|
-
##
|
|
12
|
-
# All cops
|
|
13
|
-
AllCops:
|
|
14
|
-
TargetRubyVersion: 3.2
|
|
15
|
-
Include:
|
|
16
|
-
- lib/*.rb
|
|
17
|
-
- lib/**/*.rb
|
|
18
|
-
- test/*_test.rb
|
|
19
|
-
|
|
20
|
-
##
|
|
21
|
-
# Enabled
|
|
22
|
-
Style/FrozenStringLiteralComment:
|
|
23
|
-
Enabled: true
|
|
24
|
-
|
|
25
|
-
##
|
|
26
|
-
# Disabled
|
|
27
|
-
Layout/ArgumentAlignment:
|
|
28
|
-
Enabled: false
|
|
29
|
-
Layout/MultilineMethodCallIndentation:
|
|
30
|
-
Enabled: false
|
|
31
|
-
Layout/EmptyLineBetweenDefs:
|
|
32
|
-
Enabled: false
|
|
33
|
-
Style/TrivialAccessors:
|
|
34
|
-
Enabled: false
|
data/.yardopts
DELETED
data/Gemfile
DELETED
data/LICENSE
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
Copyright (C) 2023 by 0x1eef <0x1eef@protonmail.com>
|
|
2
|
-
|
|
3
|
-
Permission to use, copy, modify, and/or distribute this
|
|
4
|
-
software for any purpose with or without fee is hereby
|
|
5
|
-
granted.
|
|
6
|
-
|
|
7
|
-
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS
|
|
8
|
-
ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
|
9
|
-
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
|
|
10
|
-
EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
11
|
-
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
|
|
12
|
-
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
13
|
-
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
|
|
14
|
-
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
|
15
|
-
OF THIS SOFTWARE.
|