lockf.rb 0.13.0 → 2.0.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: 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