sync 0.5.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 13600706b4c699e1cf55a80d5174a08031e315d1a3ab85173e5abb2a3b89509c
4
+ data.tar.gz: 07ff82e89aed6824cab4c1a152bab3c5ccfaf28ac6d944ef5414e65165f09a94
5
+ SHA512:
6
+ metadata.gz: 1db1886f07e25ec4f2f79c2083303552a856386e1e79bf282fee9d0d7adeb9b155614bcc208fb179d5cc87b4d14f16589f9341b08b2e0f88282bf8c0ab399626
7
+ data.tar.gz: 24f07556ac43c9dc3626019f5bdab0ceed03add58eb7e911d907abcef8f19f9408bea92181b9c61afea0a369d7ba0cdce61279c081cb2c3bc44e2fcaa8d14b3f
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.6.0
5
+ before_install: gem install bundler -v 1.16.2
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
2
+
3
+ Redistribution and use in source and binary forms, with or without
4
+ modification, are permitted provided that the following conditions
5
+ are met:
6
+ 1. Redistributions of source code must retain the above copyright
7
+ notice, this list of conditions and the following disclaimer.
8
+ 2. Redistributions in binary form must reproduce the above copyright
9
+ notice, this list of conditions and the following disclaimer in the
10
+ documentation and/or other materials provided with the distribution.
11
+
12
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
13
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
14
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
15
+ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
16
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
17
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
18
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
19
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
20
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
21
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
22
+ SUCH DAMAGE.
@@ -0,0 +1,77 @@
1
+ # Sync
2
+
3
+ A module that provides a two-phase lock with a counter.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'sync'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install sync
20
+
21
+ ## Usage
22
+
23
+ ### Sync_m, Synchronizer_m
24
+
25
+ ```
26
+ obj.extend(Sync_m)
27
+ ```
28
+
29
+ or
30
+
31
+ ```
32
+ class Foo
33
+ include Sync_m
34
+ :
35
+ end
36
+ ```
37
+
38
+ ```
39
+ Sync_m#sync_mode
40
+ Sync_m#sync_locked?, locked?
41
+ Sync_m#sync_shared?, shared?
42
+ Sync_m#sync_exclusive?, sync_exclusive?
43
+ Sync_m#sync_try_lock, try_lock
44
+ Sync_m#sync_lock, lock
45
+ Sync_m#sync_unlock, unlock
46
+ ```
47
+
48
+ ### Sync, Synchronizer:
49
+
50
+ ```
51
+ sync = Sync.new
52
+ ```
53
+
54
+ ```
55
+ Sync#mode
56
+ Sync#locked?
57
+ Sync#shared?
58
+ Sync#exclusive?
59
+ Sync#try_lock(mode) -- mode = :EX, :SH, :UN
60
+ Sync#lock(mode) -- mode = :EX, :SH, :UN
61
+ Sync#unlock
62
+ Sync#synchronize(mode) {...}
63
+ ```
64
+
65
+ ## Development
66
+
67
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
68
+
69
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
70
+
71
+ ## Contributing
72
+
73
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ruby/sync.
74
+
75
+ ## License
76
+
77
+ The gem is available as open source under the terms of the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/test_*.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require_relative "../lib/sync"
5
+
6
+ require "irb"
7
+ IRB.start(__FILE__)
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
@@ -0,0 +1,328 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # sync.rb - 2 phase lock with counter
4
+ # $Release Version: 1.0$
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ishitsuka.com)
7
+ #
8
+ # --
9
+ # Sync_m, Synchronizer_m
10
+ # Usage:
11
+ # obj.extend(Sync_m)
12
+ # or
13
+ # class Foo
14
+ # include Sync_m
15
+ # :
16
+ # end
17
+ #
18
+ # Sync_m#sync_mode
19
+ # Sync_m#sync_locked?, locked?
20
+ # Sync_m#sync_shared?, shared?
21
+ # Sync_m#sync_exclusive?, sync_exclusive?
22
+ # Sync_m#sync_try_lock, try_lock
23
+ # Sync_m#sync_lock, lock
24
+ # Sync_m#sync_unlock, unlock
25
+ #
26
+ # Sync, Synchronizer:
27
+ # Usage:
28
+ # sync = Sync.new
29
+ #
30
+ # Sync#mode
31
+ # Sync#locked?
32
+ # Sync#shared?
33
+ # Sync#exclusive?
34
+ # Sync#try_lock(mode) -- mode = :EX, :SH, :UN
35
+ # Sync#lock(mode) -- mode = :EX, :SH, :UN
36
+ # Sync#unlock
37
+ # Sync#synchronize(mode) {...}
38
+ #
39
+ #
40
+
41
+ ##
42
+ # A module that provides a two-phase lock with a counter.
43
+
44
+ module Sync_m
45
+ # lock mode
46
+ UN = :UN
47
+ SH = :SH
48
+ EX = :EX
49
+
50
+ # exceptions
51
+ class Err < StandardError
52
+ def Err.Fail(*opt)
53
+ fail self, sprintf(self::Message, *opt)
54
+ end
55
+
56
+ class UnknownLocker < Err
57
+ Message = "Thread(%s) not locked."
58
+ def UnknownLocker.Fail(th)
59
+ super(th.inspect)
60
+ end
61
+ end
62
+
63
+ class LockModeFailer < Err
64
+ Message = "Unknown lock mode(%s)"
65
+ def LockModeFailer.Fail(mode)
66
+ if mode.id2name
67
+ mode = mode.id2name
68
+ end
69
+ super(mode)
70
+ end
71
+ end
72
+ end
73
+
74
+ def Sync_m.define_aliases(cl)
75
+ cl.module_eval %q{
76
+ alias locked? sync_locked?
77
+ alias shared? sync_shared?
78
+ alias exclusive? sync_exclusive?
79
+ alias lock sync_lock
80
+ alias unlock sync_unlock
81
+ alias try_lock sync_try_lock
82
+ alias synchronize sync_synchronize
83
+ }
84
+ end
85
+
86
+ def Sync_m.append_features(cl)
87
+ super
88
+ # do nothing for Modules
89
+ # make aliases for Classes.
90
+ define_aliases(cl) unless cl.instance_of?(Module)
91
+ self
92
+ end
93
+
94
+ def Sync_m.extend_object(obj)
95
+ super
96
+ obj.sync_extend
97
+ end
98
+
99
+ def sync_extend
100
+ unless (defined? locked? and
101
+ defined? shared? and
102
+ defined? exclusive? and
103
+ defined? lock and
104
+ defined? unlock and
105
+ defined? try_lock and
106
+ defined? synchronize)
107
+ Sync_m.define_aliases(singleton_class)
108
+ end
109
+ sync_initialize
110
+ end
111
+
112
+ # accessing
113
+ def sync_locked?
114
+ sync_mode != UN
115
+ end
116
+
117
+ def sync_shared?
118
+ sync_mode == SH
119
+ end
120
+
121
+ def sync_exclusive?
122
+ sync_mode == EX
123
+ end
124
+
125
+ # locking methods.
126
+ def sync_try_lock(mode = EX)
127
+ return unlock if mode == UN
128
+ @sync_mutex.synchronize do
129
+ sync_try_lock_sub(mode)
130
+ end
131
+ end
132
+
133
+ def sync_lock(m = EX)
134
+ return unlock if m == UN
135
+ Thread.handle_interrupt(StandardError => :on_blocking) do
136
+ while true
137
+ @sync_mutex.synchronize do
138
+ begin
139
+ if sync_try_lock_sub(m)
140
+ return self
141
+ else
142
+ if sync_sh_locker[Thread.current]
143
+ sync_upgrade_waiting.push [Thread.current, sync_sh_locker[Thread.current]]
144
+ sync_sh_locker.delete(Thread.current)
145
+ else
146
+ unless sync_waiting.include?(Thread.current) || sync_upgrade_waiting.reverse_each.any?{|w| w.first == Thread.current }
147
+ sync_waiting.push Thread.current
148
+ end
149
+ end
150
+ @sync_mutex.sleep
151
+ end
152
+ ensure
153
+ sync_waiting.delete(Thread.current)
154
+ end
155
+ end
156
+ end
157
+ end
158
+ self
159
+ end
160
+
161
+ def sync_unlock(m = EX)
162
+ wakeup_threads = []
163
+ @sync_mutex.synchronize do
164
+ if sync_mode == UN
165
+ Err::UnknownLocker.Fail(Thread.current)
166
+ end
167
+
168
+ m = sync_mode if m == EX and sync_mode == SH
169
+
170
+ runnable = false
171
+ case m
172
+ when UN
173
+ Err::UnknownLocker.Fail(Thread.current)
174
+
175
+ when EX
176
+ if sync_ex_locker == Thread.current
177
+ if (self.sync_ex_count = sync_ex_count - 1) == 0
178
+ self.sync_ex_locker = nil
179
+ if sync_sh_locker.include?(Thread.current)
180
+ self.sync_mode = SH
181
+ else
182
+ self.sync_mode = UN
183
+ end
184
+ runnable = true
185
+ end
186
+ else
187
+ Err::UnknownLocker.Fail(Thread.current)
188
+ end
189
+
190
+ when SH
191
+ if (count = sync_sh_locker[Thread.current]).nil?
192
+ Err::UnknownLocker.Fail(Thread.current)
193
+ else
194
+ if (sync_sh_locker[Thread.current] = count - 1) == 0
195
+ sync_sh_locker.delete(Thread.current)
196
+ if sync_sh_locker.empty? and sync_ex_count == 0
197
+ self.sync_mode = UN
198
+ runnable = true
199
+ end
200
+ end
201
+ end
202
+ end
203
+
204
+ if runnable
205
+ if sync_upgrade_waiting.size > 0
206
+ th, count = sync_upgrade_waiting.shift
207
+ sync_sh_locker[th] = count
208
+ th.wakeup
209
+ wakeup_threads.push th
210
+ else
211
+ wait = sync_waiting
212
+ self.sync_waiting = []
213
+ for th in wait
214
+ th.wakeup
215
+ wakeup_threads.push th
216
+ end
217
+ end
218
+ end
219
+ end
220
+ for th in wakeup_threads
221
+ th.run
222
+ end
223
+ self
224
+ end
225
+
226
+ def sync_synchronize(mode = EX)
227
+ Thread.handle_interrupt(StandardError => :on_blocking) do
228
+ sync_lock(mode)
229
+ begin
230
+ yield
231
+ ensure
232
+ sync_unlock
233
+ end
234
+ end
235
+ end
236
+
237
+ attr_accessor :sync_mode
238
+
239
+ attr_accessor :sync_waiting
240
+ attr_accessor :sync_upgrade_waiting
241
+ attr_accessor :sync_sh_locker
242
+ attr_accessor :sync_ex_locker
243
+ attr_accessor :sync_ex_count
244
+
245
+ def sync_inspect
246
+ sync_iv = instance_variables.select{|iv| /^@sync_/ =~ iv.id2name}.collect{|iv| iv.id2name + '=' + instance_eval(iv.id2name).inspect}.join(",")
247
+ print "<#{self.class}.extend Sync_m: #{inspect}, <Sync_m: #{sync_iv}>"
248
+ end
249
+
250
+ private
251
+
252
+ def sync_initialize
253
+ @sync_mode = UN
254
+ @sync_waiting = []
255
+ @sync_upgrade_waiting = []
256
+ @sync_sh_locker = Hash.new
257
+ @sync_ex_locker = nil
258
+ @sync_ex_count = 0
259
+
260
+ @sync_mutex = Thread::Mutex.new
261
+ end
262
+
263
+ def initialize(*args)
264
+ super
265
+ sync_initialize
266
+ end
267
+
268
+ def sync_try_lock_sub(m)
269
+ case m
270
+ when SH
271
+ case sync_mode
272
+ when UN
273
+ self.sync_mode = m
274
+ sync_sh_locker[Thread.current] = 1
275
+ ret = true
276
+ when SH
277
+ count = 0 unless count = sync_sh_locker[Thread.current]
278
+ sync_sh_locker[Thread.current] = count + 1
279
+ ret = true
280
+ when EX
281
+ # in EX mode, lock will upgrade to EX lock
282
+ if sync_ex_locker == Thread.current
283
+ self.sync_ex_count = sync_ex_count + 1
284
+ ret = true
285
+ else
286
+ ret = false
287
+ end
288
+ end
289
+ when EX
290
+ if sync_mode == UN or
291
+ sync_mode == SH && sync_sh_locker.size == 1 && sync_sh_locker.include?(Thread.current)
292
+ self.sync_mode = m
293
+ self.sync_ex_locker = Thread.current
294
+ self.sync_ex_count = 1
295
+ ret = true
296
+ elsif sync_mode == EX && sync_ex_locker == Thread.current
297
+ self.sync_ex_count = sync_ex_count + 1
298
+ ret = true
299
+ else
300
+ ret = false
301
+ end
302
+ else
303
+ Err::LockModeFailer.Fail m
304
+ end
305
+ return ret
306
+ end
307
+ end
308
+
309
+ ##
310
+ # An alias for Sync_m from sync.rb
311
+
312
+ Synchronizer_m = Sync_m
313
+
314
+ ##
315
+ # A class that provides two-phase lock with a counter. See Sync_m for
316
+ # details.
317
+
318
+ class Sync
319
+
320
+ VERSION = "0.5.0"
321
+
322
+ include Sync_m
323
+ end
324
+
325
+ ##
326
+ # An alias for Sync from sync.rb. See Sync_m for details.
327
+
328
+ Synchronizer = Sync
@@ -0,0 +1,27 @@
1
+ begin
2
+ require_relative "lib/sync"
3
+ rescue LoadError
4
+ # for Ruby core repository
5
+ require_relative "sync"
6
+ end
7
+
8
+ Gem::Specification.new do |spec|
9
+ spec.name = "sync"
10
+ spec.version = Sync::VERSION
11
+ spec.authors = ["Keiju ISHITSUKA"]
12
+ spec.email = ["keiju@ruby-lang.org"]
13
+
14
+ spec.summary = %q{A module that provides a two-phase lock with a counter.}
15
+ spec.description = %q{A module that provides a two-phase lock with a counter.}
16
+ spec.homepage = "https://github.com/ruby/sync"
17
+ spec.license = "BSD-2-Clause"
18
+
19
+ spec.files = [".gitignore", ".travis.yml", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "bin/console", "bin/setup", "lib/sync.rb", "sync.gemspec"]
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "test-unit"
27
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sync
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Keiju ISHITSUKA
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-12-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: test-unit
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A module that provides a two-phase lock with a counter.
56
+ email:
57
+ - keiju@ruby-lang.org
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".travis.yml"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - bin/console
69
+ - bin/setup
70
+ - lib/sync.rb
71
+ - sync.gemspec
72
+ homepage: https://github.com/ruby/sync
73
+ licenses:
74
+ - BSD-2-Clause
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project:
92
+ rubygems_version: 2.7.6
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: A module that provides a two-phase lock with a counter.
96
+ test_files: []