lockf.rb 0.13.0 → 2.0.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: 07acab1cbd6394d179fafd3fed888bdb56f7bc52868a8557a6b2114500a409ca
4
- data.tar.gz: '0178e4e393991e7b3ab099ba2491aa7888fb30e1f096d785d4797f6bbb30a048'
3
+ metadata.gz: 2a49042a4d79251c0a85dbe626fefaa323862ea30a45426012a1d8bab08f63fb
4
+ data.tar.gz: 57f2c700f963a299ce4502e3a7856cc75283ceb80d1c27864ea08438950047d5
5
5
  SHA512:
6
- metadata.gz: 80e87c4f223f90db7ffb518dcf969342125c546b8d3a839af8a36086caeca67a7155b90953c883dab3f598c5f17d5d827b8fe72c2e53b841b6260a789fc6deeb
7
- data.tar.gz: ad79f9b41adb8ea5fd4a891eabd0f8488bfe5a5afd80a27ccacc81f2e06eae1bd7530fd74edb985f988aad559f59176ed61392e87829fb7d9e65395d23f99e7c
6
+ metadata.gz: 7d5c94dbaa6ad0b2eff1fe114e902d7c49014f2bb0ce69b2c5512ae0d107274d7c3c8b6a2d688672faeb85c7b48510689952efd9c64dc4cc78616e3e566f2e8e
7
+ data.tar.gz: 27c55d59bbab2f8e76b5370b010b3541d65a346b88279361e7f64110b3e6a1fe3f1ddaf4677fbefcec7f2e6409d70483937298f47cda1e3d729c209122d821df
data/.clang-format ADDED
@@ -0,0 +1,11 @@
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/.rubocop.yml CHANGED
@@ -18,4 +18,8 @@ Layout/ArgumentAlignment:
18
18
  ##
19
19
  # Options for all cops.
20
20
  AllCops:
21
- TargetRubyVersion: 2.7
21
+ TargetRubyVersion: 3.2
22
+ Include:
23
+ - lib/*.rb
24
+ - lib/**/*.rb
25
+ - test/*.rb
data/Gemfile CHANGED
@@ -1,3 +1,2 @@
1
1
  source "https://rubygems.org"
2
2
  gemspec
3
- gem "test-cmd.rb", github: "0x1eef/test-cmd.rb", tag: "v0.4.0"
data/README.md CHANGED
@@ -2,48 +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
-
10
- [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3)
11
- can synchronize access to a file between multiple processes, or
12
- synchronize access to a shared resource being accessed by multiple
13
- processes at the same time. When used with a shared resource,
14
- [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3)
15
- can provide something similar to a mutex that works across multiple
16
- processes rather than multiple threads.
17
5
 
18
6
  ## Examples
19
7
 
20
- ### LockFile
21
-
22
- The
23
- [`LockFile`](https://0x1eef.github.io/x/lockf.rb/LockFile.html)
24
- class provides an abstract, Ruby-oriented interface to
25
- [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3).
8
+ ### Lock::File
26
9
 
27
- __Blocking lock__
10
+ __Blocking__
28
11
 
29
- The `LockFile#lock` method can be used to acquire a lock. The method will
30
- 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:
31
19
 
32
20
  ```ruby
33
- require "lockf"
21
+ #!/usr/bin/env ruby
22
+ require "lock/file"
34
23
 
35
- lockf = LockFile.temporary_file
24
+ lockf = Lock::File.temporary_file
36
25
  lockf.lock
37
26
  print "Lock acquired by parent process (#{Time.now.utc})", "\n"
38
- pid = fork do
27
+ fork do
39
28
  print "Child process waiting on lock (#{Time.now.utc})", "\n"
40
29
  lockf.lock
41
30
  print "Lock acquired by child process (#{Time.now.utc})", "\n"
42
31
  end
43
32
  sleep(3)
44
33
  lockf.release
45
- Process.wait(pid)
46
- lockf.file.close
34
+ Process.wait
47
35
 
48
36
  ##
49
37
  # Lock acquired by parent process (2023-02-11 16:43:15 UTC)
@@ -51,31 +39,31 @@ lockf.file.close
51
39
  # Lock acquired by child process (2023-02-11 16:43:18 UTC)
52
40
  ```
53
41
 
54
- __Non-blocking lock__
42
+ __Non-blocking__
55
43
 
56
- The `LockFile#lock_nonblock` method can be used to acquire a lock
57
- without blocking. When it is found that acquiring a lock would block
58
- the method will raise an exception (ie `Errno::EAGAIN` /`Errno::EWOULDBLOCK`)
59
- 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:
60
48
 
61
49
  ```ruby
62
- require "lockf"
50
+ #!/usr/bin/env ruby
51
+ require "lock/file"
63
52
 
64
- lockf = LockFile.temporary_file
53
+ lockf = Lock::File.temporary_file
65
54
  lockf.lock_nonblock
66
55
  print "Lock acquired by parent process (#{Time.now.utc})", "\n"
67
- pid = fork do
56
+ fork do
68
57
  lockf.lock_nonblock
69
58
  print "Lock acquired by child process (#{Time.now.utc})", "\n"
70
59
  rescue Errno::EWOULDBLOCK
71
- print "Lock would block", "\n"
72
60
  sleep 1
61
+ print "Lock would block", "\n"
73
62
  retry
74
63
  end
75
64
  sleep 3
76
65
  lockf.release
77
- Process.wait(pid)
78
- lockf.file.close
66
+ Process.wait
79
67
 
80
68
  ##
81
69
  # Lock acquired by parent process (2023-02-11 19:03:05 UTC)
@@ -85,25 +73,25 @@ lockf.file.close
85
73
  # Lock acquired by child process (2023-02-11 19:03:08 UTC)
86
74
  ```
87
75
 
88
- ### LockFile.lockf
76
+ ### Lock::File::FFI
77
+
78
+ __lockf__
89
79
 
90
- The
91
- [`LockFile.lockf`](https://0x1eef.github.io/x/lockf.rb/LockFile.html#lockf-class_method)
92
- 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
93
82
  [lockf(3)](https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3)
94
83
  that is more or less equivalent to how the function would be called
95
- from C.
96
-
97
- __Blocking lock__
84
+ from C:
98
85
 
99
86
  ```ruby
100
- require "lockf"
87
+ #!/usr/bin/env ruby
88
+ require "lock/file"
101
89
  require "tempfile"
102
90
 
103
91
  file = Tempfile.new("lockf-ffi").tap(&:unlink)
104
- LockFile.lockf(file.fileno, LockFile::F_LOCK, 0)
92
+ Lock::File::FFI.lockf(file, Lock::File::F_LOCK, 0)
105
93
  print "Lock acquired", "\n"
106
- LockFile.lockf(file.fileno, LockFile::F_ULOCK, 0)
94
+ Lock::File::FFI.lockf(file, Lock::File::F_ULOCK, 0)
107
95
  print "Lock released", "\n"
108
96
  file.close
109
97
 
@@ -112,29 +100,14 @@ file.close
112
100
  # Lock released
113
101
  ```
114
102
 
115
- __Non-blocking lock__
103
+ ## Documentation
116
104
 
117
- ```ruby
118
- require "lockf"
119
- require "tempfile"
120
-
121
- file = Tempfile.new("lockf-ffi").tap(&:unlink)
122
- LockFile.lockf(file.fileno, LockFile::F_TLOCK, 0)
123
- print "Lock acquired", "\n"
124
- LockFile.lockf(file.fileno, LockFile::F_ULOCK, 0)
125
- print "Lock released", "\n"
126
- file.close
127
-
128
- ##
129
- # Lock acquired
130
- # Lock released
131
- ```
105
+ A complete API reference is available at
106
+ [0x1eef.github.io/x/lockf.rb](https://0x1eef.github.io/x/lockf.rb)
132
107
 
133
108
  ## Install
134
109
 
135
- **Rubygems.org**
136
-
137
- lockf.rb can be installed via rubygems.org.
110
+ lockf.rb can be installed via rubygems.org:
138
111
 
139
112
  gem install lockf.rb
140
113
 
@@ -145,7 +118,7 @@ lockf.rb can be installed via rubygems.org.
145
118
 
146
119
  ## License
147
120
 
148
- [BSD Zero Clause](https://choosealicense.com/licenses/0bsd/).
121
+ [BSD Zero Clause](https://choosealicense.com/licenses/0bsd/)
149
122
  <br>
150
- See [LICENSE](./LICENSE).
123
+ See [LICENSE](./LICENSE)
151
124
 
data/Rakefile.rb CHANGED
@@ -1,25 +1,15 @@
1
1
  require "bundler/setup"
2
- require "rake/extensiontask"
3
- require "rake/testtask"
4
2
 
5
- namespace :linters do
6
- desc "Run the C linter"
7
- task :c do
8
- sh "uncrustify -c .uncrustify.cfg --no-backup --replace ext/lockf.rb/*.c"
9
- end
10
-
11
- desc "Run the Ruby linter"
3
+ namespace :format do
4
+ desc "Run rubocop"
12
5
  task :ruby do
13
- sh "bundle exec rubocop -A Rakefile.rb lib/**/*.rb spec/**/*.rb"
6
+ sh "bundle exec rubocop -A"
14
7
  end
15
8
  end
16
- task lint: ["linters:c", "linters:ruby"]
17
-
18
- Rake::ExtensionTask.new("lockf.rb")
9
+ task format: %w[format:ruby]
19
10
 
20
- Rake::TestTask.new do |t|
21
- t.test_files = FileList["test/*_test.rb"]
22
- t.verbose = true
23
- t.warning = false
11
+ desc "Run tests"
12
+ task :test do
13
+ sh "bin/test-runner"
24
14
  end
25
- task default: %w[clobber compile test]
15
+ 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,36 @@
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
+ private
31
+
32
+ def libc
33
+ @libc ||= Fiddle.dlopen Dir["/lib/libc.*"].first
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Lock::File
4
+ VERSION = "2.0.0"
5
+ end
data/lib/lock/file.rb ADDED
@@ -0,0 +1,114 @@
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 "tmpdir"
10
+ require_relative "file/version"
11
+ require_relative "file/ffi"
12
+ require_relative "file/constants"
13
+
14
+ include FFI
15
+ include Constants
16
+
17
+ ##
18
+ # @example
19
+ # lockf = Lock::File.temporary_file
20
+ # lockf.lock
21
+ # # ...
22
+ #
23
+ # @param [String] basename
24
+ # @param [String] tmpdir
25
+ # @return [Lock::File]
26
+ # Returns a {Lock::File Lock::File} for a random,
27
+ # unlinked temporary file
28
+ def self.from_temporary_file(basename: "lockf", tmpdir: Dir.tmpdir)
29
+ require "tempfile" unless defined?(Tempfile)
30
+ file = Tempfile.new(basename, tmpdir:).tap(&:unlink)
31
+ Lock::File.new(file)
32
+ end
33
+ class << self
34
+ alias_method :temporary_file, :from_temporary_file
35
+ end
36
+
37
+ ##
38
+ # @return [<#fileno>]
39
+ # Returns a file handle
40
+ attr_reader :file
41
+
42
+ ##
43
+ # @param [<#fileno>] file
44
+ # @param [Integer] size
45
+ # @return [Lock::File]
46
+ # Returns an instance of {Lock::File Lock::File}
47
+ def initialize(file, size = 0)
48
+ @file = file
49
+ @size = size
50
+ end
51
+
52
+ ##
53
+ # Acquire lock (blocking)
54
+ #
55
+ # @see https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3 lockf(3)
56
+ # @raise [SystemCallError]
57
+ # Might raise a subclass of SystemCallError
58
+ # @return [Boolean]
59
+ # Returns true when successful
60
+ def lock
61
+ tries ||= 0
62
+ lockf(@file, F_LOCK, @size)
63
+ rescue Errno::EINTR => ex
64
+ tries += 1
65
+ tries == 3 ? raise(ex) : retry
66
+ end
67
+
68
+ ##
69
+ # Acquire lock (non-blocking)
70
+ #
71
+ # @see https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3 lockf(3)
72
+ # @raise [SystemCallError]
73
+ # Might raise a subclass of SystemCallError
74
+ # @return [Boolean]
75
+ # Returns true when successful
76
+ def lock_nonblock
77
+ lockf(@file, F_TLOCK, @size)
78
+ end
79
+
80
+ ##
81
+ # Release lock
82
+ #
83
+ # @see https://man.freebsd.org/cgi/man.cgi?query=lockf&sektion=3 lockf(3)
84
+ # @raise [SystemCallError]
85
+ # Might raise a subclass of SystemCallError
86
+ # @return [Boolean]
87
+ # Returns true when successful
88
+ def release
89
+ lockf(@file, F_ULOCK, @size)
90
+ end
91
+
92
+ ##
93
+ # @return [Boolean]
94
+ # Returns true when lock is held by another process
95
+ def locked?
96
+ lockf(@file, F_TEST, @size)
97
+ false
98
+ rescue Errno::EACCES, Errno::EAGAIN
99
+ true
100
+ end
101
+
102
+ ##
103
+ # Closes {Lock::File#file Lock::File#file}
104
+ #
105
+ # @example
106
+ # # Equivalent to:
107
+ # lockf = Lock::File.temporary_file
108
+ # lockf.file.close
109
+ # @return [void]
110
+ def close
111
+ return unless @file.respond_to?(:close)
112
+ @file.close
113
+ end
114
+ end
data/lib/lockf.rb CHANGED
@@ -1,139 +1 @@
1
- ##
2
- # The
3
- # [`LockFile`](https://0x1eef.github.io/x/lockf.rb/LockFile.html)
4
- # class provides a Ruby-oriented interface to the C function
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
- # @raise [Errno::EBADF]
84
- # @raise [Errno::EDEADLK]
85
- # @raise [Errno::EINTR]
86
- # @raise [Errno::ENOLCK]
87
- # @return [Integer]
88
- def lock
89
- attempts ||= 0
90
- LockFile.lockf(@file.fileno, F_LOCK, @len)
91
- rescue Errno::EINTR => ex
92
- attempts += 1
93
- attempts == 3 ? raise(ex) : retry
94
- end
95
-
96
- ##
97
- # Acquire a lock (non-blocking)
98
- # @raise [Errno::EAGAIN]
99
- # @raise [Errno::EBADF]
100
- # @raise [Errno::ENOLCK]
101
- # @raise [Errno::EINVAL]
102
- # @return [Integer]
103
- def lock_nonblock
104
- LockFile.lockf(@file.fileno, F_TLOCK, @len)
105
- end
106
-
107
- ##
108
- # Release a lock
109
- # @raise [Errno::EBADF]
110
- # @raise [Errno::ENOLCK]
111
- # @return [Integer]
112
- def release
113
- LockFile.lockf(@file.fileno, F_ULOCK, @len)
114
- end
115
-
116
- ##
117
- # @return [Boolean]
118
- # Returns true when a lock has been acquired by another process.
119
- def locked?
120
- LockFile.lockf(@file.fileno, F_TEST, @len)
121
- false
122
- rescue Errno::EACCES, Errno::EAGAIN
123
- true
124
- end
125
-
126
- ##
127
- # Closes {LockFile#file LockFile#file}.
128
- #
129
- # @example
130
- # # Equivalent to:
131
- # lockf = LockFile.temporary_file
132
- # lockf.file.close
133
- #
134
- # @return [void]
135
- def close
136
- return unless @file.respond_to?(:close)
137
- @file.close
138
- end
139
- 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,24 +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 "redcarpet", "~> 3.5"
17
- gem.add_development_dependency "standard", "= 1.12.1"
18
- gem.add_development_dependency "rubocop", "= 1.29.1"
19
- gem.add_development_dependency "test-unit", "~> 3.5.7"
20
- gem.add_development_dependency "rake-compiler", "= 1.2.0"
21
- gem.add_development_dependency "rack", "~> 3.0"
22
- gem.add_development_dependency "rackup", "~> 2.1"
23
- gem.add_development_dependency "test-cmd.rb", "~> 0.4"
17
+ gem.add_development_dependency "standard", "~> 1.12"
18
+ gem.add_development_dependency "rubocop", "~> 1.29"
19
+ gem.add_development_dependency "test-unit", "~> 3.5"
20
+ gem.add_development_dependency "test-cmd.rb", "~> 0.12"
24
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.file.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.file.close
18
+ Process.wait
18
19
 
19
20
  ##
20
21
  # Lock acquired by parent process (2023-02-11 19:03:05 UTC)
@@ -1,10 +1,12 @@
1
- require "lockf"
2
- require "tempfile"
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
3
 
4
+ require "lock/file"
5
+ require "tempfile"
4
6
  file = Tempfile.new("lockf-ffi").tap(&:unlink)
5
- LockFile.lockf(file.fileno, LockFile::F_LOCK, 0)
7
+ Lock::File::FFI.lockf(file, Lock::File::F_LOCK, 0)
6
8
  print "Lock acquired", "\n"
7
- LockFile.lockf(file.fileno, LockFile::F_ULOCK, 0)
9
+ Lock::File::FFI.lockf(file, Lock::File::F_ULOCK, 0)
8
10
  print "Lock released", "\n"
9
11
  file.close
10
12
 
@@ -1,10 +1,12 @@
1
- require "lockf"
2
- require "tempfile"
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
3
 
4
+ require "lock/file"
5
+ require "tempfile"
4
6
  file = Tempfile.new("lockf-ffi").tap(&:unlink)
5
- LockFile.lockf(file.fileno, LockFile::F_TLOCK, 0)
7
+ Lock::File::FFI.lockf(file, Lock::File::F_TLOCK, 0)
6
8
  print "Lock acquired", "\n"
7
- LockFile.lockf(file.fileno, LockFile::F_ULOCK, 0)
9
+ Lock::File::FFI.lockf(file, Lock::File::F_ULOCK, 0)
8
10
  print "Lock released", "\n"
9
11
  file.close
10
12
 
@@ -1,11 +1,13 @@
1
+ # frozen_string_literal: true
1
2
  require_relative "setup"
2
- class LockFile::Test < Test::Unit::TestCase
3
+
4
+ class Lock::File::Test < Test::Unit::TestCase
3
5
  attr_reader :file
4
6
  attr_reader :lockf
5
7
 
6
8
  def setup
7
- @file = Tempfile.new("lockf-test").tap(&:unlink)
8
- @lockf = LockFile.new(file)
9
+ @file = Tempfile.new("lockf-test").tap(&:unlink)
10
+ @lockf = Lock::File.new(file)
9
11
  end
10
12
 
11
13
  def teardown
@@ -13,9 +15,9 @@ class LockFile::Test < Test::Unit::TestCase
13
15
  end
14
16
 
15
17
  ##
16
- # Lock::File#lock
18
+ # LockFile#lock
17
19
  def test_lock
18
- assert_equal 0, lockf.lock
20
+ assert_equal true, lockf.lock
19
21
  ensure
20
22
  lockf.release
21
23
  end
@@ -30,9 +32,9 @@ class LockFile::Test < Test::Unit::TestCase
30
32
  end
31
33
 
32
34
  ##
33
- # Lock::File#lock_nonblock
35
+ # LockFile#lock_nonblock
34
36
  def test_lock_nonblock
35
- assert_equal 0, lockf.lock_nonblock
37
+ assert_equal true, lockf.lock_nonblock
36
38
  ensure
37
39
  lockf.release
38
40
  end
@@ -47,7 +49,7 @@ class LockFile::Test < Test::Unit::TestCase
47
49
  end
48
50
 
49
51
  ##
50
- # Lock::File#locked?
52
+ # LockFile#locked?
51
53
  def test_locked?
52
54
  pid = fork_sleep { lockf.lock }
53
55
  sleep(0.1)
@@ -60,9 +62,9 @@ class LockFile::Test < Test::Unit::TestCase
60
62
  ##
61
63
  # LockFile.temporary_file
62
64
  def test_temporary_file
63
- lockf = LockFile.temporary_file
64
- assert_equal 0, lockf.lock
65
- assert_equal 0, lockf.release
65
+ lockf = Lock::File.temporary_file
66
+ assert_equal true, lockf.lock
67
+ assert_equal true, lockf.release
66
68
  ensure
67
69
  lockf.file.close
68
70
  end
data/test/readme_test.rb CHANGED
@@ -3,40 +3,40 @@
3
3
  require_relative "setup"
4
4
  require "test/cmd"
5
5
 
6
- class LockFile::ReadmeTest < Test::Unit::TestCase
7
- include Test::Cmd
8
-
6
+ class Lock::File::ReadmeTest < Test::Unit::TestCase
9
7
  def test_lockfile_blocking_variant
10
- r = 'Lock acquired by parent process \(.+\)\s*' \
11
- 'Child process waiting on lock \(.+\)\s*' \
12
- 'Lock acquired by child process \(.+\)\s*'
13
- assert_match Regexp.new(r),
14
- readme_example("1_lockfile_blocking_variant.rb").stdout
8
+ r = ruby(readme_example("1_lockfile_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 }
15
13
  end
16
14
 
17
15
  def test_lockfile_nonblocking_variant
18
- r = 'Lock acquired by parent process \(.+\)\s*' \
19
- '(Lock would block\s*){3,4}' \
20
- 'Lock acquired by child process \(.+\)\s*'
21
- assert_match Regexp.new(r),
22
- readme_example("2_lockfile_nonblocking_variant.rb").stdout
16
+ r = ruby(readme_example("2_lockfile_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 }
23
21
  end
24
22
 
25
23
  def test_ffi_lockf_blocking_variant
26
24
  assert_equal "Lock acquired\nLock released\n",
27
- readme_example("3_ffilockf_blocking_variant.rb").stdout
25
+ ruby(readme_example("3_ffilockf_blocking_variant.rb")).stdout
28
26
  end
29
27
 
30
28
  def test_ffi_lockf_nonblocking_variant
31
29
  assert_equal "Lock acquired\nLock released\n",
32
- readme_example("4_ffilockf_nonblocking_variant.rb").stdout
30
+ ruby(readme_example("4_ffilockf_nonblocking_variant.rb")).stdout
33
31
  end
34
32
 
35
33
  private
36
34
 
37
- def readme_example(path)
38
- examples_dir = File.join(Dir.getwd, "share", "lockf.rb", "examples")
39
- example = File.join(examples_dir, path)
40
- 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)
41
41
  end
42
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,150 +1,108 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lockf.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 2.0.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-16 00:00:00.000000000 Z
11
+ date: 2024-06-28 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: redcarpet
28
+ name: yard
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.5'
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: '3.5'
40
+ version: '0.9'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: standard
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - '='
46
- - !ruby/object:Gem::Version
47
- version: 1.12.1
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '='
53
- - !ruby/object:Gem::Version
54
- version: 1.12.1
55
- - !ruby/object:Gem::Dependency
56
- name: rubocop
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - '='
60
- - !ruby/object:Gem::Version
61
- version: 1.29.1
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - '='
67
- - !ruby/object:Gem::Version
68
- version: 1.29.1
69
- - !ruby/object:Gem::Dependency
70
- name: test-unit
71
43
  requirement: !ruby/object:Gem::Requirement
72
44
  requirements:
73
45
  - - "~>"
74
46
  - !ruby/object:Gem::Version
75
- version: 3.5.7
47
+ version: '1.12'
76
48
  type: :development
77
49
  prerelease: false
78
50
  version_requirements: !ruby/object:Gem::Requirement
79
51
  requirements:
80
52
  - - "~>"
81
53
  - !ruby/object:Gem::Version
82
- version: 3.5.7
54
+ version: '1.12'
83
55
  - !ruby/object:Gem::Dependency
84
- name: rake-compiler
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - '='
88
- - !ruby/object:Gem::Version
89
- version: 1.2.0
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - '='
95
- - !ruby/object:Gem::Version
96
- version: 1.2.0
97
- - !ruby/object:Gem::Dependency
98
- name: rack
56
+ name: rubocop
99
57
  requirement: !ruby/object:Gem::Requirement
100
58
  requirements:
101
59
  - - "~>"
102
60
  - !ruby/object:Gem::Version
103
- version: '3.0'
61
+ version: '1.29'
104
62
  type: :development
105
63
  prerelease: false
106
64
  version_requirements: !ruby/object:Gem::Requirement
107
65
  requirements:
108
66
  - - "~>"
109
67
  - !ruby/object:Gem::Version
110
- version: '3.0'
68
+ version: '1.29'
111
69
  - !ruby/object:Gem::Dependency
112
- name: rackup
70
+ name: test-unit
113
71
  requirement: !ruby/object:Gem::Requirement
114
72
  requirements:
115
73
  - - "~>"
116
74
  - !ruby/object:Gem::Version
117
- version: '2.1'
75
+ version: '3.5'
118
76
  type: :development
119
77
  prerelease: false
120
78
  version_requirements: !ruby/object:Gem::Requirement
121
79
  requirements:
122
80
  - - "~>"
123
81
  - !ruby/object:Gem::Version
124
- version: '2.1'
82
+ version: '3.5'
125
83
  - !ruby/object:Gem::Dependency
126
84
  name: test-cmd.rb
127
85
  requirement: !ruby/object:Gem::Requirement
128
86
  requirements:
129
87
  - - "~>"
130
88
  - !ruby/object:Gem::Version
131
- version: '0.4'
89
+ version: '0.12'
132
90
  type: :development
133
91
  prerelease: false
134
92
  version_requirements: !ruby/object:Gem::Requirement
135
93
  requirements:
136
94
  - - "~>"
137
95
  - !ruby/object:Gem::Version
138
- version: '0.4'
96
+ version: '0.12'
139
97
  description: Ruby bindings for lockf(3)
140
98
  email:
141
99
  - 0x1eef@protonmail.com
142
100
  executables: []
143
- extensions:
144
- - ext/lockf.rb/extconf.rb
101
+ extensions: []
145
102
  extra_rdoc_files: []
146
103
  files:
147
104
  - ".bundle/config"
105
+ - ".clang-format"
148
106
  - ".github/workflows/tests.yml"
149
107
  - ".gitignore"
150
108
  - ".projectile"
@@ -155,11 +113,13 @@ files:
155
113
  - LICENSE
156
114
  - README.md
157
115
  - Rakefile.rb
158
- - ext/lockf.rb/extconf.rb
159
- - ext/lockf.rb/lockf.c
160
- - ext/lockf.rb/lockf.h
116
+ - bin/test-runner
117
+ - lib/lock/file.rb
118
+ - lib/lock/file/constants.rb
119
+ - lib/lock/file/ffi.rb
120
+ - lib/lock/file/version.rb
161
121
  - lib/lockf.rb
162
- - lib/lockf/version.rb
122
+ - lib/lockfile.rb
163
123
  - lockf.rb.gemspec
164
124
  - share/lockf.rb/examples/1_lockfile_blocking_variant.rb
165
125
  - share/lockf.rb/examples/2_lockfile_nonblocking_variant.rb
@@ -187,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
187
147
  - !ruby/object:Gem::Version
188
148
  version: '0'
189
149
  requirements: []
190
- rubygems_version: 3.5.3
150
+ rubygems_version: 3.5.11
191
151
  signing_key:
192
152
  specification_version: 4
193
153
  summary: Ruby bindings for lockf(3)
@@ -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,34 +0,0 @@
1
- #include <ruby.h>
2
- #include <unistd.h>
3
- #include <errno.h>
4
- #include "lockf.h"
5
-
6
- static VALUE
7
- lockf_lock(VALUE self, VALUE fd, VALUE cmd, VALUE len)
8
- {
9
- int result;
10
-
11
- Check_Type(fd, T_FIXNUM);
12
- Check_Type(cmd, T_FIXNUM);
13
- Check_Type(len, T_FIXNUM);
14
- errno = 0;
15
- result = lockf(NUM2INT(fd), NUM2INT(cmd), NUM2INT(len));
16
- if (result == 0) {
17
- return INT2NUM(result);
18
- } else {
19
- rb_syserr_fail(errno, "lockf");
20
- }
21
- }
22
-
23
- void
24
- Init_lockf(void)
25
- {
26
- VALUE cLockf;
27
-
28
- cLockf = rb_define_class("LockFile", rb_cObject);
29
- rb_define_const(cLockf, "F_LOCK", INT2NUM(F_LOCK));
30
- rb_define_const(cLockf, "F_TLOCK", INT2NUM(F_TLOCK));
31
- rb_define_const(cLockf, "F_ULOCK", INT2NUM(F_ULOCK));
32
- rb_define_const(cLockf, "F_TEST", INT2NUM(F_TEST));
33
- rb_define_singleton_method(cLockf, "lockf", lockf_lock, 3);
34
- }
data/ext/lockf.rb/lockf.h DELETED
@@ -1 +0,0 @@
1
- void Init_lockf(void);
data/lib/lockf/version.rb DELETED
@@ -1,3 +0,0 @@
1
- class LockFile
2
- VERSION = "0.13.0"
3
- end