lockf.rb 1.0.0 → 2.1.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: 05e204191db7552902307b79f09636be97f36fba053a89c5ab849c6dd0205830
4
- data.tar.gz: 82167b478eae279325094a0ba29b8d75500dc6d0a53ea32fd24ed0ef200fa643
3
+ metadata.gz: b0f68d54d3ad30fc3c9c6316910adebcd74645876546aec01c86402261275ff6
4
+ data.tar.gz: ed9cbe6b94840dd3987d16825737b3e98c42efb4904f15fd2ef206ebd0ab431a
5
5
  SHA512:
6
- metadata.gz: 31b69f15f99e3a4b6f522de3b708130ee67ab3a3c5498df989e034bf281f0c02463f360d948150ca9cd562e85a9fd4a8d802d27dad6fa014e289abaa33c6f5d6
7
- data.tar.gz: 8b9d9b5979cf813a0234054531e0fe4e6d7c7be83221f49540aeaec97d94347db851756fece830b4f711da42683d4195589f7d3578264a232d6aedd37d7d0377
6
+ metadata.gz: 663fb2919e2560b75307ce6ea01291582e61fca0fa14f9c86f54dfd7ab598a2301b361be09952800a93089a5010f53dcd8ee76870ba1cc44ff7470ef1295abb0
7
+ data.tar.gz: a249a8c95037378796bbc8cb4fd3224da60137117902ac189546860791bfa9b1256a26636895762ffbcd3a74037e4bb38c26d6aefe57721ca6d603a0022f1128
@@ -11,8 +11,8 @@ jobs:
11
11
  strategy:
12
12
  fail-fast: false
13
13
  matrix:
14
- os: [ubuntu-latest]
15
- ruby: [3.2]
14
+ os: [ubuntu-latest, macos-latest]
15
+ ruby: [3.2, 3.3]
16
16
  runs-on: ${{ matrix.os }}
17
17
  steps:
18
18
  - uses: actions/checkout@v2
@@ -20,4 +20,4 @@ jobs:
20
20
  with:
21
21
  ruby-version: ${{ matrix.ruby }}
22
22
  - run: bundle install
23
- - run: bundle exec rake
23
+ - run: ruby -S rake ci
data/.gitignore CHANGED
@@ -1,10 +1,4 @@
1
- *.so
2
- *.o
3
- *.lock
4
- Makefile
5
- tmp/
6
- pkg/
7
- *~
8
- .yardoc/
9
- .gems/
10
- doc/
1
+ /*.lock
2
+ /.yardoc/
3
+ /.gems/
4
+ /doc/
data/.rubocop.yml CHANGED
@@ -14,6 +14,14 @@ Layout/MultilineMethodCallIndentation:
14
14
  Enabled: false
15
15
  Layout/ArgumentAlignment:
16
16
  Enabled: false
17
+ Layout/MultilineArrayBraceLayout:
18
+ Enabled: false
19
+ Layout/ExtraSpacing:
20
+ Enabled: false
21
+ Style/MultilineIfModifier:
22
+ Enabled: false
23
+ Layout/ArrayAlignment:
24
+ Enabled: false
17
25
 
18
26
  ##
19
27
  # Options for all cops.
@@ -23,3 +31,4 @@ AllCops:
23
31
  - lib/*.rb
24
32
  - lib/**/*.rb
25
33
  - test/*.rb
34
+ - share/lockf.rb/examples/*.rb
data/README.md CHANGED
@@ -2,40 +2,36 @@
2
2
 
3
3
  lockf.rb provides Ruby bindings for
4
4
  [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3).
5
- The
6
- [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3)
7
- function implements an advisory-mode lock that can be placed on select
8
- regions of a file, or on the entire contents of a file.
9
5
 
10
6
  ## Examples
11
7
 
12
- ### LockFile
13
-
14
- The
15
- [`LockFile`](https://0x1eef.github.io/x/lockf.rb/LockFile.html)
16
- class provides an abstract, Ruby-oriented interface to
17
- [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3).
8
+ ### Lock::File
18
9
 
19
- __Blocking lock__
10
+ __Blocking__
20
11
 
21
- The `LockFile#lock` method can be used to acquire a lock. The method will
22
- block when another process has acquired a lock beforehand:
12
+ [Lock::File#lock](http://0x1eef.github.io/x/lockf.rb/Lock/File.html#lock-instance_method)
13
+ can be used to acquire a lock.
14
+ [Lock::File.temporary_file](http://0x1eef.github.io/x/lockf.rb/Lock/File.html#temporary_file-class_method)
15
+ returns a lock for an unlinked temporary file.
16
+ [Lock::File#lock](http://0x1eef.github.io/x/lockf.rb/Lock/File.html#lock-instance_method)
17
+ will block when another
18
+ process has acquired a lock beforehand:
23
19
 
24
20
  ```ruby
25
- require "lockf"
21
+ #!/usr/bin/env ruby
22
+ require "lock/file"
26
23
 
27
- lockf = LockFile.temporary_file
24
+ lockf = Lock::File.temporary_file
28
25
  lockf.lock
29
26
  print "Lock acquired by parent process (#{Time.now.utc})", "\n"
30
- pid = fork do
27
+ fork do
31
28
  print "Child process waiting on lock (#{Time.now.utc})", "\n"
32
29
  lockf.lock
33
30
  print "Lock acquired by child process (#{Time.now.utc})", "\n"
34
31
  end
35
32
  sleep(3)
36
33
  lockf.release
37
- Process.wait(pid)
38
- lockf.close
34
+ Process.wait
39
35
 
40
36
  ##
41
37
  # Lock acquired by parent process (2023-02-11 16:43:15 UTC)
@@ -43,31 +39,31 @@ lockf.close
43
39
  # Lock acquired by child process (2023-02-11 16:43:18 UTC)
44
40
  ```
45
41
 
46
- __Non-blocking lock__
42
+ __Non-blocking__
47
43
 
48
- The `LockFile#lock_nonblock` method can be used to acquire a lock
49
- without blocking. When it is found that acquiring a lock would block
50
- the method will raise an exception (ie `Errno::EAGAIN` /`Errno::EWOULDBLOCK`)
51
- instead:
44
+ [Lock::File#lock_nonblock](http://0x1eef.github.io/x/lockf.rb/Lock/File.html#lock_nonblock-instance_method)
45
+ can be used to acquire a lock without blocking. When it is found
46
+ that acquiring a lock would block the method will raise an
47
+ exception (`Errno::EAGAIN` / `Errno::EWOULDBLOCK`) instead:
52
48
 
53
49
  ```ruby
54
- require "lockf"
50
+ #!/usr/bin/env ruby
51
+ require "lock/file"
55
52
 
56
- lockf = LockFile.temporary_file
53
+ lockf = Lock::File.temporary_file
57
54
  lockf.lock_nonblock
58
55
  print "Lock acquired by parent process (#{Time.now.utc})", "\n"
59
- pid = fork do
56
+ fork do
60
57
  lockf.lock_nonblock
61
58
  print "Lock acquired by child process (#{Time.now.utc})", "\n"
62
59
  rescue Errno::EWOULDBLOCK
63
- print "Lock would block", "\n"
64
60
  sleep 1
61
+ print "Lock would block", "\n"
65
62
  retry
66
63
  end
67
64
  sleep 3
68
65
  lockf.release
69
- Process.wait(pid)
70
- lockf.close
66
+ Process.wait
71
67
 
72
68
  ##
73
69
  # Lock acquired by parent process (2023-02-11 19:03:05 UTC)
@@ -77,43 +73,25 @@ lockf.close
77
73
  # Lock acquired by child process (2023-02-11 19:03:08 UTC)
78
74
  ```
79
75
 
80
- ### LockFile.lockf
76
+ ### Lock::File::FFI
77
+
78
+ __lockf__
81
79
 
82
- The
83
- [`LockFile.lockf`](https://0x1eef.github.io/x/lockf.rb/LockFile.html#lockf-class_method)
84
- method provides a direct interface to
80
+ [Lock::File::FFI.lockf](http://0x1eef.freebsd.home.network/x/lockf.rb/Lock/File/FFI.html#lockf-instance_method)
81
+ provides a direct interface to
85
82
  [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3)
86
83
  that is more or less equivalent to how the function would be called
87
- from C.
88
-
89
- __Blocking lock__
90
-
91
- ```ruby
92
- require "lockf"
93
- require "tempfile"
94
-
95
- file = Tempfile.new("lockf-ffi").tap(&:unlink)
96
- LockFile.lockf(file.fileno, LockFile::F_LOCK, 0)
97
- print "Lock acquired", "\n"
98
- LockFile.lockf(file.fileno, LockFile::F_ULOCK, 0)
99
- print "Lock released", "\n"
100
- file.close
101
-
102
- ##
103
- # Lock acquired
104
- # Lock released
105
- ```
106
-
107
- __Non-blocking lock__
84
+ from C:
108
85
 
109
86
  ```ruby
110
- require "lockf"
87
+ #!/usr/bin/env ruby
88
+ require "lock/file"
111
89
  require "tempfile"
112
90
 
113
91
  file = Tempfile.new("lockf-ffi").tap(&:unlink)
114
- LockFile.lockf(file.fileno, LockFile::F_TLOCK, 0)
92
+ Lock::File::FFI.lockf(file, Lock::File::F_LOCK, 0)
115
93
  print "Lock acquired", "\n"
116
- LockFile.lockf(file.fileno, LockFile::F_ULOCK, 0)
94
+ Lock::File::FFI.lockf(file, Lock::File::F_ULOCK, 0)
117
95
  print "Lock released", "\n"
118
96
  file.close
119
97
 
@@ -124,14 +102,12 @@ file.close
124
102
 
125
103
  ## Documentation
126
104
 
127
- A complete API reference is available at
128
- [0x1eef.github.io/x/lockf.rb](https://0x1eef.github.io/x/lockf.rb).
105
+ A complete API reference is available at
106
+ [0x1eef.github.io/x/lockf.rb](https://0x1eef.github.io/x/lockf.rb)
129
107
 
130
108
  ## Install
131
109
 
132
- **Rubygems.org**
133
-
134
- lockf.rb can be installed via rubygems.org.
110
+ lockf.rb can be installed via rubygems.org:
135
111
 
136
112
  gem install lockf.rb
137
113
 
@@ -142,7 +118,7 @@ lockf.rb can be installed via rubygems.org.
142
118
 
143
119
  ## License
144
120
 
145
- [BSD Zero Clause](https://choosealicense.com/licenses/0bsd/).
121
+ [BSD Zero Clause](https://choosealicense.com/licenses/0bsd/)
146
122
  <br>
147
- See [LICENSE](./LICENSE).
123
+ See [LICENSE](./LICENSE)
148
124
 
data/Rakefile.rb CHANGED
@@ -1,26 +1,23 @@
1
1
  require "bundler/setup"
2
- require "rake/extensiontask"
3
- require "rake/testtask"
4
2
 
5
- namespace :clang do
6
- desc "Run clang-format"
7
- task :format do
8
- sh "clang-format -style=file:.clang-format -i ext/lockf.rb/*.c"
3
+ namespace :format do
4
+ desc "Apply rubocop fixes"
5
+ task :apply do
6
+ sh "bundle exec rubocop -A"
9
7
  end
10
- end
11
8
 
12
- namespace :ruby do
13
9
  desc "Run rubocop"
14
- task :format do
15
- sh "bundle exec rubocop -A"
10
+ task :check do
11
+ sh "bundle exec rubocop"
16
12
  end
17
13
  end
18
- task format: %w[clang:format ruby:format]
14
+ task format: %w[format:apply]
15
+
16
+ desc "Run CI tasks"
17
+ task ci: %i[format:check test]
19
18
 
20
- Rake::ExtensionTask.new("lockf.rb")
21
- Rake::TestTask.new do |t|
22
- t.test_files = FileList["test/*_test.rb"]
23
- t.verbose = true
24
- t.warning = false
19
+ desc "Run tests"
20
+ task :test do
21
+ sh "bin/test-runner"
25
22
  end
26
- task default: %w[clobber compile test]
23
+ task default: %w[test]
data/bin/test-runner ADDED
@@ -0,0 +1,6 @@
1
+ #!/bin/sh
2
+ set -e
3
+
4
+ for t in test/*_test.rb; do
5
+ ruby -Itest "${t}"
6
+ done
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Lock::File
4
+ # The constants found in this module are defined
5
+ # by unistd.h. Their documentation can be found in
6
+ # the
7
+ # [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3)
8
+ # man page
9
+ module Constants
10
+ F_ULOCK = 0x0
11
+ F_LOCK = 0x1
12
+ F_TLOCK = 0x2
13
+ F_TEST = 0x3
14
+ end
15
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Lock::File
4
+ module FFI
5
+ require "fiddle"
6
+ include Fiddle::Types
7
+ extend self
8
+
9
+ ##
10
+ # Provides a Ruby interface for lockf(3)
11
+ #
12
+ # @see https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3 lockf(3)
13
+ # @param [Integer, #fileno] fd
14
+ # @param [Integer] function
15
+ # @param [Integer] size
16
+ # @raise [SystemCallError]
17
+ # Might raise a subclass of SystemCallError
18
+ # @return [Boolean]
19
+ # Returns true when successful
20
+ def lockf(fd, function, size = 0)
21
+ fileno = fd.respond_to?(:fileno) ? fd.fileno : fd
22
+ Fiddle::Function.new(
23
+ libc["lockf"],
24
+ [INT, INT, INT],
25
+ INT
26
+ ).call(fileno, function, size)
27
+ .zero? || raise(SystemCallError.new("lockf", Fiddle.last_error))
28
+ end
29
+
30
+ ##
31
+ # @return [Fiddle::Handle]
32
+ def libc
33
+ @libc ||= begin
34
+ globs = %w[
35
+ /lib/libc.so.*
36
+ /usr/lib/libc.so.*
37
+ /lib/x86_64-linux-gnu/libc.so.*
38
+ /lib/i386-linux-gnu/libc.so.*
39
+ ]
40
+ Fiddle.dlopen(Dir[*globs].first)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Lock::File
4
+ VERSION = "2.1.0"
5
+ end
data/lib/lock/file.rb ADDED
@@ -0,0 +1,109 @@
1
+ module Lock
2
+ end unless defined?(Lock)
3
+
4
+ ##
5
+ # {Lock::File Lock::File} provides an object-oriented
6
+ # [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3)
7
+ # interface
8
+ class Lock::File
9
+ require_relative "file/version"
10
+ require_relative "file/ffi"
11
+ require_relative "file/constants"
12
+
13
+ include FFI
14
+ include Constants
15
+
16
+ ##
17
+ # Accepts the same parameters as Tempfile.new
18
+ #
19
+ # @example
20
+ # lockf = Lock::File.temporary_file
21
+ # lockf.lock
22
+ # # ...
23
+ #
24
+ # @return [Lock::File]
25
+ # Returns a {Lock::File Lock::File} for a random,
26
+ # unlinked temporary file
27
+ def self.temporary_file(...)
28
+ require "tempfile" unless defined?(Tempfile)
29
+ Lock::File.new Tempfile.new(...).tap(&:unlink)
30
+ end
31
+
32
+ ##
33
+ # @return [<#fileno>]
34
+ # Returns a file handle
35
+ attr_reader :file
36
+
37
+ ##
38
+ # @param [<#fileno>] file
39
+ # @param [Integer] size
40
+ # @return [Lock::File]
41
+ # Returns an instance of {Lock::File Lock::File}
42
+ def initialize(file, size = 0)
43
+ @file = file
44
+ @size = size
45
+ end
46
+
47
+ ##
48
+ # Acquire lock (blocking)
49
+ #
50
+ # @see https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3 lockf(3)
51
+ # @raise [SystemCallError]
52
+ # Might raise a subclass of SystemCallError
53
+ # @return [Boolean]
54
+ # Returns true when successful
55
+ def lock
56
+ tries ||= 0
57
+ lockf(@file, F_LOCK, @size)
58
+ rescue Errno::EINTR => ex
59
+ tries += 1
60
+ (tries == 3) ? raise(ex) : retry
61
+ end
62
+
63
+ ##
64
+ # Acquire lock (non-blocking)
65
+ #
66
+ # @see https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3 lockf(3)
67
+ # @raise [SystemCallError]
68
+ # Might raise a subclass of SystemCallError
69
+ # @return [Boolean]
70
+ # Returns true when successful
71
+ def lock_nonblock
72
+ lockf(@file, F_TLOCK, @size)
73
+ end
74
+
75
+ ##
76
+ # Release lock
77
+ #
78
+ # @see https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3 lockf(3)
79
+ # @raise [SystemCallError]
80
+ # Might raise a subclass of SystemCallError
81
+ # @return [Boolean]
82
+ # Returns true when successful
83
+ def release
84
+ lockf(@file, F_ULOCK, @size)
85
+ end
86
+
87
+ ##
88
+ # @return [Boolean]
89
+ # Returns true when lock is held by another process
90
+ def locked?
91
+ lockf(@file, F_TEST, @size)
92
+ false
93
+ rescue Errno::EACCES, Errno::EAGAIN
94
+ true
95
+ end
96
+
97
+ ##
98
+ # Closes {Lock::File#file Lock::File#file}
99
+ #
100
+ # @example
101
+ # # Equivalent to:
102
+ # lockf = Lock::File.temporary_file
103
+ # lockf.file.close
104
+ # @return [void]
105
+ def close
106
+ return unless @file.respond_to?(:close)
107
+ @file.close
108
+ end
109
+ end
data/lib/lockf.rb CHANGED
@@ -1,142 +1 @@
1
- ##
2
- # The
3
- # [LockFile](https://0x1eef.github.io/x/lockf.rb/LockFile.html)
4
- # class provides a Ruby interface to
5
- # [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3).
6
- class LockFile
7
- require "tmpdir"
8
- require_relative "lockf.rb.so"
9
-
10
- ##
11
- # @!method self.lockf(fd, cmd, len)
12
- # @example
13
- # LockFile.lockf(5, LockFile::F_LOCK, 0)
14
- #
15
- # @param [Integer] fd
16
- # A number that represents a file descriptor.
17
- #
18
- # @param [Integer] cmd
19
- # {LockFile::F_LOCK}, {LockFile::F_TLOCK}, {LockFile::F_ULOCK}, or
20
- # {LockFile::F_TEST}.
21
- #
22
- # @param [Integer] len
23
- # The number of bytes to place a lock on.
24
- # A value of "0" covers the entire file.
25
- #
26
- # @raise [SystemCallError]
27
- # Might raise a number of Errno exception classes.
28
- #
29
- # @return [Integer]
30
- # Returns 0 on success.
31
- #
32
- # @see (https://man7.org/linux/man-pages/man3/lockf.3.html) lockf man page (Linux)
33
- # @see (https://man.openbsd.org/lockf.3) lockf man page (OpenBSD)
34
- # @see (https://www.freebsd.org/cgi/man.cgi?query=lockf) lockf man page (FreeBSD)
35
-
36
- ##
37
- # @example
38
- # lockf = LockFile.temporary_file
39
- # lockf.lock
40
- # lockf.release
41
- # lockf.file.close
42
- #
43
- # @param [String] basename
44
- # The basename of the temporary file.
45
- #
46
- # @param [String] tmpdir
47
- # The path to the parent directory of the temporary file.
48
- #
49
- # @return [LockFile]
50
- # Returns an instance of {LockFile LockFile} backed by an
51
- # unlinked instance of Tempfile.
52
- def self.from_temporary_file(basename: "lockf", tmpdir: Dir.tmpdir)
53
- require "tempfile" unless defined?(Tempfile)
54
- file = Tempfile.new(basename, tmpdir:).tap(&:unlink)
55
- LockFile.new(file)
56
- end
57
- class << self
58
- alias_method :temporary_file, :from_temporary_file
59
- end
60
-
61
- ##
62
- # @return [<File, Tempfile, #fileno>]
63
- # Returns a file object.
64
- attr_reader :file
65
-
66
- ##
67
- # @param [<File, TempFile, String, #fileno>] file
68
- # The file to place a lock on.
69
- #
70
- # @param [Integer] len
71
- # The number of bytes to place a lock on.
72
- # A value of "0" covers the entire file.
73
- #
74
- # @return [LockFile]
75
- # Returns an instance of {LockFile LockFile}.
76
- def initialize(file, len = 0)
77
- @file = String === file ? File.open(file, "r+") : file
78
- @len = len
79
- end
80
-
81
- ##
82
- # Acquire a lock (blocking).
83
- #
84
- # @raise [Errno::EBADF]
85
- # @raise [Errno::EDEADLK]
86
- # @raise [Errno::EINTR]
87
- # @raise [Errno::ENOLCK]
88
- # @return [Integer]
89
- def lock
90
- attempts ||= 0
91
- LockFile.lockf(@file.fileno, F_LOCK, @len)
92
- rescue Errno::EINTR => ex
93
- attempts += 1
94
- attempts == 3 ? raise(ex) : retry
95
- end
96
-
97
- ##
98
- # Acquire a lock (non-blocking).
99
- #
100
- # @raise [Errno::EAGAIN]
101
- # @raise [Errno::EBADF]
102
- # @raise [Errno::ENOLCK]
103
- # @raise [Errno::EINVAL]
104
- # @return [Integer]
105
- def lock_nonblock
106
- LockFile.lockf(@file.fileno, F_TLOCK, @len)
107
- end
108
-
109
- ##
110
- # Release a lock.
111
- #
112
- # @raise [Errno::EBADF]
113
- # @raise [Errno::ENOLCK]
114
- # @return [Integer]
115
- def release
116
- LockFile.lockf(@file.fileno, F_ULOCK, @len)
117
- end
118
-
119
- ##
120
- # @return [Boolean]
121
- # Returns true when a lock has been acquired by another process.
122
- def locked?
123
- LockFile.lockf(@file.fileno, F_TEST, @len)
124
- false
125
- rescue Errno::EACCES, Errno::EAGAIN
126
- true
127
- end
128
-
129
- ##
130
- # Closes {LockFile#file LockFile#file}.
131
- #
132
- # @example
133
- # # Equivalent to:
134
- # lockf = LockFile.temporary_file
135
- # lockf.file.close
136
- #
137
- # @return [void]
138
- def close
139
- return unless @file.respond_to?(:close)
140
- @file.close
141
- end
142
- end
1
+ require_relative "lock/file"
data/lib/lockfile.rb ADDED
@@ -0,0 +1 @@
1
+ require_relative "lock/file"
data/lockf.rb.gemspec CHANGED
@@ -1,21 +1,21 @@
1
- require "./lib/lockf/version"
1
+ require_relative "lib/lockfile"
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = "lockf.rb"
5
5
  gem.authors = ["0x1eef"]
6
6
  gem.email = ["0x1eef@protonmail.com"]
7
7
  gem.homepage = "https://github.com/0x1eef/lockf.rb#readme"
8
- gem.version = LockFile::VERSION
8
+ gem.version = Lock::File::VERSION
9
9
  gem.licenses = ["0BSD"]
10
10
  gem.files = `git ls-files`.split($/)
11
11
  gem.require_paths = ["lib"]
12
- gem.extensions = %w[ext/lockf.rb/extconf.rb]
13
12
  gem.summary = "Ruby bindings for lockf(3)"
14
13
  gem.description = gem.summary
14
+
15
+ gem.add_runtime_dependency "fiddle", "~> 1.1"
15
16
  gem.add_development_dependency "yard", "~> 0.9"
16
- gem.add_development_dependency "standard", "~> 1.12"
17
+ gem.add_development_dependency "standard", "~> 1.39"
17
18
  gem.add_development_dependency "rubocop", "~> 1.29"
18
19
  gem.add_development_dependency "test-unit", "~> 3.5"
19
- gem.add_development_dependency "rake-compiler", "~> 1.2"
20
- gem.add_development_dependency "test-cmd.rb", "~> 0.6"
20
+ gem.add_development_dependency "test-cmd.rb", "~> 0.12"
21
21
  end
@@ -1,17 +1,18 @@
1
- require "lockf"
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- lockf = LockFile.from_temporary_file
4
+ require "lock/file"
5
+ lockf = Lock::File.temporary_file
4
6
  lockf.lock
5
7
  print "Lock acquired by parent process (#{Time.now.utc})", "\n"
6
- pid = fork do
8
+ fork do
7
9
  print "Child process waiting on lock (#{Time.now.utc})", "\n"
8
10
  lockf.lock
9
11
  print "Lock acquired by child process (#{Time.now.utc})", "\n"
10
12
  end
11
13
  sleep(3)
12
14
  lockf.release
13
- Process.wait(pid)
14
- lockf.close
15
+ Process.wait
15
16
 
16
17
  ##
17
18
  # Lock acquired by parent process (2023-02-11 16:43:15 UTC)
@@ -1,9 +1,11 @@
1
- require "lockf"
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
2
3
 
3
- lockf = LockFile.from_temporary_file
4
+ require "lock/file"
5
+ lockf = Lock::File.temporary_file
4
6
  lockf.lock_nonblock
5
7
  print "Lock acquired by parent process (#{Time.now.utc})", "\n"
6
- pid = fork do
8
+ fork do
7
9
  lockf.lock_nonblock
8
10
  print "Lock acquired by child process (#{Time.now.utc})", "\n"
9
11
  rescue Errno::EWOULDBLOCK
@@ -13,8 +15,7 @@ rescue Errno::EWOULDBLOCK
13
15
  end
14
16
  sleep 3
15
17
  lockf.release
16
- Process.wait(pid)
17
- lockf.close
18
+ Process.wait
18
19
 
19
20
  ##
20
21
  # Lock acquired by parent process (2023-02-11 19:03:05 UTC)
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "lock/file"
5
+ require "tempfile"
6
+ file = Tempfile.new("lockf-ffi").tap(&:unlink)
7
+ Lock::File::FFI.lockf(file, Lock::File::F_LOCK, 0)
8
+ print "Lock acquired", "\n"
9
+ Lock::File::FFI.lockf(file, Lock::File::F_ULOCK, 0)
10
+ print "Lock released", "\n"
11
+ file.close
12
+
13
+ ##
14
+ # Lock acquired
15
+ # Lock released
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "lock/file"
5
+ require "tempfile"
6
+ file = Tempfile.new("lockf-ffi").tap(&:unlink)
7
+ Lock::File::FFI.lockf(file, Lock::File::F_TLOCK, 0)
8
+ print "Lock acquired", "\n"
9
+ Lock::File::FFI.lockf(file, Lock::File::F_ULOCK, 0)
10
+ print "Lock released", "\n"
11
+ file.close
12
+
13
+ ##
14
+ # Lock acquired
15
+ # Lock released
@@ -1,11 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_relative "setup"
2
- class LockFile::Test < Test::Unit::TestCase
4
+
5
+ class Lock::File::Test < Test::Unit::TestCase
3
6
  attr_reader :file
4
7
  attr_reader :lockf
5
8
 
6
9
  def setup
7
10
  @file = Tempfile.new("lockf-test").tap(&:unlink)
8
- @lockf = LockFile.new(file)
11
+ @lockf = Lock::File.new(file)
9
12
  end
10
13
 
11
14
  def teardown
@@ -15,7 +18,7 @@ class LockFile::Test < Test::Unit::TestCase
15
18
  ##
16
19
  # LockFile#lock
17
20
  def test_lock
18
- assert_equal 0, lockf.lock
21
+ assert_equal true, lockf.lock
19
22
  ensure
20
23
  lockf.release
21
24
  end
@@ -32,7 +35,7 @@ class LockFile::Test < Test::Unit::TestCase
32
35
  ##
33
36
  # LockFile#lock_nonblock
34
37
  def test_lock_nonblock
35
- assert_equal 0, lockf.lock_nonblock
38
+ assert_equal true, lockf.lock_nonblock
36
39
  ensure
37
40
  lockf.release
38
41
  end
@@ -60,9 +63,9 @@ class LockFile::Test < Test::Unit::TestCase
60
63
  ##
61
64
  # LockFile.temporary_file
62
65
  def test_temporary_file
63
- lockf = LockFile.temporary_file
64
- assert_equal 0, lockf.lock
65
- assert_equal 0, lockf.release
66
+ lockf = Lock::File.temporary_file
67
+ assert_equal true, lockf.lock
68
+ assert_equal true, lockf.release
66
69
  ensure
67
70
  lockf.file.close
68
71
  end
data/test/readme_test.rb CHANGED
@@ -3,38 +3,40 @@
3
3
  require_relative "setup"
4
4
  require "test/cmd"
5
5
 
6
- class LockFile::ReadmeTest < Test::Unit::TestCase
6
+ class Lock::File::ReadmeTest < Test::Unit::TestCase
7
7
  def test_lockfile_blocking_variant
8
- r = 'Lock acquired by parent process \(.+\)\s*' \
9
- 'Child process waiting on lock \(.+\)\s*' \
10
- 'Lock acquired by child process \(.+\)\s*'
11
- assert_match Regexp.new(r),
12
- readme_example("1_lockfile_blocking_variant.rb").stdout
8
+ r = ruby(readme_example("1_lock_file_blocking_variant.rb"))
9
+ ["Lock acquired by parent process (.+)\n",
10
+ "Child process waiting on lock (.+)\n",
11
+ "Lock acquired by child process (.+)\n"
12
+ ].each { assert_match Regexp.new(_1), r.stdout }
13
13
  end
14
14
 
15
15
  def test_lockfile_nonblocking_variant
16
- r = 'Lock acquired by parent process \(.+\)\s*' \
17
- '(Lock would block\s*){3,4}' \
18
- 'Lock acquired by child process \(.+\)\s*'
19
- assert_match Regexp.new(r),
20
- readme_example("2_lockfile_nonblocking_variant.rb").stdout
16
+ r = ruby(readme_example("2_lock_file_nonblocking_variant.rb"))
17
+ ["Lock acquired by parent process (.+)\n",
18
+ "(Lock would block\n){3,4}",
19
+ "Lock acquired by child process (.+)\n"
20
+ ].each { assert_match Regexp.new(_1), r.stdout }
21
21
  end
22
22
 
23
23
  def test_ffi_lockf_blocking_variant
24
24
  assert_equal "Lock acquired\nLock released\n",
25
- readme_example("3_ffilockf_blocking_variant.rb").stdout
25
+ ruby(readme_example("3_ffi_lockf_blocking_variant.rb")).stdout
26
26
  end
27
27
 
28
28
  def test_ffi_lockf_nonblocking_variant
29
29
  assert_equal "Lock acquired\nLock released\n",
30
- readme_example("4_ffilockf_nonblocking_variant.rb").stdout
30
+ ruby(readme_example("4_ffi_lockf_nonblocking_variant.rb")).stdout
31
31
  end
32
32
 
33
33
  private
34
34
 
35
- def readme_example(path)
36
- examples_dir = File.join(Dir.getwd, "share", "lockf.rb", "examples")
37
- example = File.join(examples_dir, path)
38
- cmd "bundle exec ruby #{example}"
35
+ def ruby(*argv)
36
+ cmd("ruby", *argv)
37
+ end
38
+
39
+ def readme_example(example_name)
40
+ File.join(__dir__, "..", "share", "lockf.rb", "examples", example_name)
39
41
  end
40
42
  end
data/test/setup.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  require "bundler/setup"
2
2
  require "test/unit"
3
- require "lockf"
3
+ require "lock/file"
4
4
  require "tempfile"
metadata CHANGED
@@ -1,128 +1,128 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lockf.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - '0x1eef'
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-03-30 00:00:00.000000000 Z
11
+ date: 2024-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: yard
14
+ name: fiddle
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.9'
20
- type: :development
19
+ version: '1.1'
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.9'
26
+ version: '1.1'
27
27
  - !ruby/object:Gem::Dependency
28
- name: standard
28
+ name: yard
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.12'
33
+ version: '0.9'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '1.12'
40
+ version: '0.9'
41
41
  - !ruby/object:Gem::Dependency
42
- name: rubocop
42
+ name: standard
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.29'
47
+ version: '1.39'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.29'
54
+ version: '1.39'
55
55
  - !ruby/object:Gem::Dependency
56
- name: test-unit
56
+ name: rubocop
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.5'
61
+ version: '1.29'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.5'
68
+ version: '1.29'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rake-compiler
70
+ name: test-unit
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '1.2'
75
+ version: '3.5'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '1.2'
82
+ version: '3.5'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: test-cmd.rb
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.6'
89
+ version: '0.12'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.6'
96
+ version: '0.12'
97
97
  description: Ruby bindings for lockf(3)
98
98
  email:
99
99
  - 0x1eef@protonmail.com
100
100
  executables: []
101
- extensions:
102
- - ext/lockf.rb/extconf.rb
101
+ extensions: []
103
102
  extra_rdoc_files: []
104
103
  files:
105
104
  - ".bundle/config"
106
- - ".clang-format"
107
105
  - ".github/workflows/tests.yml"
108
106
  - ".gitignore"
109
107
  - ".projectile"
110
108
  - ".rubocop.yml"
111
- - ".uncrustify.cfg"
112
109
  - ".yardopts"
113
110
  - Gemfile
114
111
  - LICENSE
115
112
  - README.md
116
113
  - Rakefile.rb
117
- - ext/lockf.rb/extconf.rb
118
- - ext/lockf.rb/lockf.c
114
+ - bin/test-runner
115
+ - lib/lock/file.rb
116
+ - lib/lock/file/constants.rb
117
+ - lib/lock/file/ffi.rb
118
+ - lib/lock/file/version.rb
119
119
  - lib/lockf.rb
120
- - lib/lockf/version.rb
120
+ - lib/lockfile.rb
121
121
  - lockf.rb.gemspec
122
- - share/lockf.rb/examples/1_lockfile_blocking_variant.rb
123
- - share/lockf.rb/examples/2_lockfile_nonblocking_variant.rb
124
- - share/lockf.rb/examples/3_ffilockf_blocking_variant.rb
125
- - share/lockf.rb/examples/4_ffilockf_nonblocking_variant.rb
122
+ - share/lockf.rb/examples/1_lock_file_blocking_variant.rb
123
+ - share/lockf.rb/examples/2_lock_file_nonblocking_variant.rb
124
+ - share/lockf.rb/examples/3_ffi_lockf_blocking_variant.rb
125
+ - share/lockf.rb/examples/4_ffi_lockf_nonblocking_variant.rb
126
126
  - test/lock_file_test.rb
127
127
  - test/readme_test.rb
128
128
  - test/setup.rb
@@ -145,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
145
  - !ruby/object:Gem::Version
146
146
  version: '0'
147
147
  requirements: []
148
- rubygems_version: 3.5.3
148
+ rubygems_version: 3.5.11
149
149
  signing_key:
150
150
  specification_version: 4
151
151
  summary: Ruby bindings for lockf(3)
data/.clang-format DELETED
@@ -1,11 +0,0 @@
1
- BasedOnStyle: LLVM
2
- IndentWidth: 2
3
- SortIncludes: false
4
- UseTab: Never
5
- BreakBeforeBraces: Allman
6
- AllowShortFunctionsOnASingleLine: Inline
7
- AlwaysBreakAfterDefinitionReturnType: TopLevel
8
- BreakBeforeBinaryOperators: All
9
- BinPackArguments: false
10
- AlignConsecutiveAssignments: true
11
- AlwaysBreakAfterReturnType: None
data/.uncrustify.cfg DELETED
@@ -1,2 +0,0 @@
1
- indent_with_tabs = 0
2
- indent_columns = 4
@@ -1,12 +0,0 @@
1
- require "mkmf"
2
-
3
- [
4
- "INSTALL_DATA", "INSTALL_SCRIPT",
5
- "INSTALL_PROGRAM", "INSTALL_DATA",
6
- "INSTALL"
7
- ].each do
8
- CONFIG[_1].sub!(/-o [a-zA-Z0-9]+/, "")
9
- CONFIG[_1].sub!(/-g [a-zA-Z0-9]+/, "")
10
- end
11
-
12
- create_makefile "lockf.rb"
data/ext/lockf.rb/lockf.c DELETED
@@ -1,36 +0,0 @@
1
- #include <ruby.h>
2
- #include <unistd.h>
3
- #include <errno.h>
4
-
5
- static VALUE
6
- lockf_lock(VALUE self, VALUE fd, VALUE cmd, VALUE len)
7
- {
8
- int result;
9
-
10
- Check_Type(fd, T_FIXNUM);
11
- Check_Type(cmd, T_FIXNUM);
12
- Check_Type(len, T_FIXNUM);
13
- errno = 0;
14
- result = lockf(NUM2INT(fd), NUM2INT(cmd), NUM2INT(len));
15
- if (result == 0)
16
- {
17
- return INT2NUM(result);
18
- }
19
- else
20
- {
21
- rb_syserr_fail(errno, "lockf");
22
- }
23
- }
24
-
25
- void
26
- Init_lockf(void)
27
- {
28
- VALUE cLockf;
29
-
30
- cLockf = rb_define_class("LockFile", rb_cObject);
31
- rb_define_const(cLockf, "F_LOCK", INT2NUM(F_LOCK));
32
- rb_define_const(cLockf, "F_TLOCK", INT2NUM(F_TLOCK));
33
- rb_define_const(cLockf, "F_ULOCK", INT2NUM(F_ULOCK));
34
- rb_define_const(cLockf, "F_TEST", INT2NUM(F_TEST));
35
- rb_define_singleton_method(cLockf, "lockf", lockf_lock, 3);
36
- }
data/lib/lockf/version.rb DELETED
@@ -1,3 +0,0 @@
1
- class LockFile
2
- VERSION = "1.0.0"
3
- end
@@ -1,13 +0,0 @@
1
- require "lockf"
2
- require "tempfile"
3
-
4
- file = Tempfile.new("lockf-ffi").tap(&:unlink)
5
- LockFile.lockf(file.fileno, LockFile::F_LOCK, 0)
6
- print "Lock acquired", "\n"
7
- LockFile.lockf(file.fileno, LockFile::F_ULOCK, 0)
8
- print "Lock released", "\n"
9
- file.close
10
-
11
- ##
12
- # Lock acquired
13
- # Lock released
@@ -1,13 +0,0 @@
1
- require "lockf"
2
- require "tempfile"
3
-
4
- file = Tempfile.new("lockf-ffi").tap(&:unlink)
5
- LockFile.lockf(file.fileno, LockFile::F_TLOCK, 0)
6
- print "Lock acquired", "\n"
7
- LockFile.lockf(file.fileno, LockFile::F_ULOCK, 0)
8
- print "Lock released", "\n"
9
- file.close
10
-
11
- ##
12
- # Lock acquired
13
- # Lock released