lockf.rb 1.0.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: 05e204191db7552902307b79f09636be97f36fba053a89c5ab849c6dd0205830
4
- data.tar.gz: 82167b478eae279325094a0ba29b8d75500dc6d0a53ea32fd24ed0ef200fa643
3
+ metadata.gz: 2a49042a4d79251c0a85dbe626fefaa323862ea30a45426012a1d8bab08f63fb
4
+ data.tar.gz: 57f2c700f963a299ce4502e3a7856cc75283ceb80d1c27864ea08438950047d5
5
5
  SHA512:
6
- metadata.gz: 31b69f15f99e3a4b6f522de3b708130ee67ab3a3c5498df989e034bf281f0c02463f360d948150ca9cd562e85a9fd4a8d802d27dad6fa014e289abaa33c6f5d6
7
- data.tar.gz: 8b9d9b5979cf813a0234054531e0fe4e6d7c7be83221f49540aeaec97d94347db851756fece830b4f711da42683d4195589f7d3578264a232d6aedd37d7d0377
6
+ metadata.gz: 7d5c94dbaa6ad0b2eff1fe114e902d7c49014f2bb0ce69b2c5512ae0d107274d7c3c8b6a2d688672faeb85c7b48510689952efd9c64dc4cc78616e3e566f2e8e
7
+ data.tar.gz: 27c55d59bbab2f8e76b5370b010b3541d65a346b88279361e7f64110b3e6a1fe3f1ddaf4677fbefcec7f2e6409d70483937298f47cda1e3d729c209122d821df
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,15 @@
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"
9
- end
10
- end
11
-
12
- namespace :ruby do
3
+ namespace :format do
13
4
  desc "Run rubocop"
14
- task :format do
5
+ task :ruby do
15
6
  sh "bundle exec rubocop -A"
16
7
  end
17
8
  end
18
- task format: %w[clang:format ruby:format]
9
+ task format: %w[format:ruby]
19
10
 
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
11
+ desc "Run tests"
12
+ task :test do
13
+ sh "bin/test-runner"
25
14
  end
26
- 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,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
17
  gem.add_development_dependency "standard", "~> 1.12"
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)
@@ -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
9
  @file = Tempfile.new("lockf-test").tap(&:unlink)
8
- @lockf = LockFile.new(file)
10
+ @lockf = Lock::File.new(file)
9
11
  end
10
12
 
11
13
  def teardown
@@ -15,7 +17,7 @@ class LockFile::Test < Test::Unit::TestCase
15
17
  ##
16
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
@@ -32,7 +34,7 @@ class LockFile::Test < Test::Unit::TestCase
32
34
  ##
33
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
@@ -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,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_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 }
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_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 }
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_ffilockf_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_ffilockf_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,15 +1,29 @@
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.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-30 00:00:00.000000000 Z
11
+ date: 2024-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: fiddle
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: yard
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -66,40 +80,25 @@ dependencies:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
82
  version: '3.5'
69
- - !ruby/object:Gem::Dependency
70
- name: rake-compiler
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '1.2'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '1.2'
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"
@@ -114,10 +113,13 @@ files:
114
113
  - LICENSE
115
114
  - README.md
116
115
  - Rakefile.rb
117
- - ext/lockf.rb/extconf.rb
118
- - ext/lockf.rb/lockf.c
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
119
121
  - lib/lockf.rb
120
- - lib/lockf/version.rb
122
+ - lib/lockfile.rb
121
123
  - lockf.rb.gemspec
122
124
  - share/lockf.rb/examples/1_lockfile_blocking_variant.rb
123
125
  - share/lockf.rb/examples/2_lockfile_nonblocking_variant.rb
@@ -145,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
147
  - !ruby/object:Gem::Version
146
148
  version: '0'
147
149
  requirements: []
148
- rubygems_version: 3.5.3
150
+ rubygems_version: 3.5.11
149
151
  signing_key:
150
152
  specification_version: 4
151
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,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