lockf.rb 1.0.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: 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