sync 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []