lockf.rb 1.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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