garcun 0.0.2
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 +7 -0
- data/.gitattributes +17 -0
- data/.gitignore +197 -0
- data/.rspec +2 -0
- data/Gemfile +22 -0
- data/LICENSE +201 -0
- data/README.md +521 -0
- data/Rakefile +47 -0
- data/garcun.gemspec +83 -0
- data/lib/garcon.rb +290 -0
- data/lib/garcon/chef/chef_helpers.rb +343 -0
- data/lib/garcon/chef/coerce/coercer.rb +134 -0
- data/lib/garcon/chef/coerce/coercions/boolean_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/date_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/date_time_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/fixnum_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/float_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/hash_definitions.rb +29 -0
- data/lib/garcon/chef/coerce/coercions/integer_definitions.rb +31 -0
- data/lib/garcon/chef/coerce/coercions/string_definitions.rb +45 -0
- data/lib/garcon/chef/coerce/coercions/time_definitions.rb +32 -0
- data/lib/garcon/chef/handler/devreporter.rb +127 -0
- data/lib/garcon/chef/log.rb +64 -0
- data/lib/garcon/chef/node.rb +100 -0
- data/lib/garcon/chef/provider/civilize.rb +209 -0
- data/lib/garcon/chef/provider/development.rb +159 -0
- data/lib/garcon/chef/provider/download.rb +420 -0
- data/lib/garcon/chef/provider/house_keeping.rb +265 -0
- data/lib/garcon/chef/provider/node_cache.rb +31 -0
- data/lib/garcon/chef/provider/partial.rb +183 -0
- data/lib/garcon/chef/provider/recovery.rb +80 -0
- data/lib/garcon/chef/provider/zip_file.rb +271 -0
- data/lib/garcon/chef/resource/attribute.rb +52 -0
- data/lib/garcon/chef/resource/base_dsl.rb +174 -0
- data/lib/garcon/chef/resource/blender.rb +140 -0
- data/lib/garcon/chef/resource/lazy_eval.rb +66 -0
- data/lib/garcon/chef/resource/resource_name.rb +109 -0
- data/lib/garcon/chef/secret_bag.rb +204 -0
- data/lib/garcon/chef/validations.rb +76 -0
- data/lib/garcon/chef_inclusions.rb +151 -0
- data/lib/garcon/configuration.rb +138 -0
- data/lib/garcon/core_ext.rb +39 -0
- data/lib/garcon/core_ext/array.rb +27 -0
- data/lib/garcon/core_ext/binding.rb +64 -0
- data/lib/garcon/core_ext/boolean.rb +66 -0
- data/lib/garcon/core_ext/duration.rb +271 -0
- data/lib/garcon/core_ext/enumerable.rb +34 -0
- data/lib/garcon/core_ext/file.rb +127 -0
- data/lib/garcon/core_ext/filetest.rb +62 -0
- data/lib/garcon/core_ext/hash.rb +279 -0
- data/lib/garcon/core_ext/kernel.rb +159 -0
- data/lib/garcon/core_ext/lazy.rb +222 -0
- data/lib/garcon/core_ext/method_access.rb +243 -0
- data/lib/garcon/core_ext/module.rb +92 -0
- data/lib/garcon/core_ext/nil.rb +53 -0
- data/lib/garcon/core_ext/numeric.rb +44 -0
- data/lib/garcon/core_ext/object.rb +342 -0
- data/lib/garcon/core_ext/pathname.rb +152 -0
- data/lib/garcon/core_ext/process.rb +41 -0
- data/lib/garcon/core_ext/random.rb +497 -0
- data/lib/garcon/core_ext/string.rb +312 -0
- data/lib/garcon/core_ext/struct.rb +49 -0
- data/lib/garcon/core_ext/symbol.rb +170 -0
- data/lib/garcon/core_ext/time.rb +234 -0
- data/lib/garcon/exceptions.rb +101 -0
- data/lib/garcon/inflections.rb +237 -0
- data/lib/garcon/inflections/defaults.rb +79 -0
- data/lib/garcon/inflections/inflections.rb +182 -0
- data/lib/garcon/inflections/rules_collection.rb +37 -0
- data/lib/garcon/secret.rb +271 -0
- data/lib/garcon/stash/format.rb +114 -0
- data/lib/garcon/stash/journal.rb +226 -0
- data/lib/garcon/stash/queue.rb +83 -0
- data/lib/garcon/stash/serializer.rb +86 -0
- data/lib/garcon/stash/store.rb +435 -0
- data/lib/garcon/task.rb +31 -0
- data/lib/garcon/task/atomic.rb +151 -0
- data/lib/garcon/task/atomic_boolean.rb +127 -0
- data/lib/garcon/task/condition.rb +99 -0
- data/lib/garcon/task/copy_on_notify_observer_set.rb +154 -0
- data/lib/garcon/task/copy_on_write_observer_set.rb +153 -0
- data/lib/garcon/task/count_down_latch.rb +92 -0
- data/lib/garcon/task/delay.rb +196 -0
- data/lib/garcon/task/dereferenceable.rb +144 -0
- data/lib/garcon/task/event.rb +119 -0
- data/lib/garcon/task/executor.rb +275 -0
- data/lib/garcon/task/executor_options.rb +59 -0
- data/lib/garcon/task/future.rb +107 -0
- data/lib/garcon/task/immediate_executor.rb +84 -0
- data/lib/garcon/task/ivar.rb +171 -0
- data/lib/garcon/task/lazy_reference.rb +74 -0
- data/lib/garcon/task/monotonic_time.rb +69 -0
- data/lib/garcon/task/obligation.rb +256 -0
- data/lib/garcon/task/observable.rb +101 -0
- data/lib/garcon/task/priority_queue.rb +234 -0
- data/lib/garcon/task/processor_count.rb +128 -0
- data/lib/garcon/task/read_write_lock.rb +304 -0
- data/lib/garcon/task/safe_task_executor.rb +58 -0
- data/lib/garcon/task/single_thread_executor.rb +97 -0
- data/lib/garcon/task/thread_pool/cached.rb +71 -0
- data/lib/garcon/task/thread_pool/executor.rb +294 -0
- data/lib/garcon/task/thread_pool/fixed.rb +61 -0
- data/lib/garcon/task/thread_pool/worker.rb +90 -0
- data/lib/garcon/task/timer.rb +44 -0
- data/lib/garcon/task/timer_set.rb +194 -0
- data/lib/garcon/task/timer_task.rb +377 -0
- data/lib/garcon/task/waitable_list.rb +58 -0
- data/lib/garcon/utility/ansi.rb +199 -0
- data/lib/garcon/utility/at_random.rb +77 -0
- data/lib/garcon/utility/crypto.rb +292 -0
- data/lib/garcon/utility/equalizer.rb +146 -0
- data/lib/garcon/utility/faker/extensions/array.rb +22 -0
- data/lib/garcon/utility/faker/extensions/symbol.rb +9 -0
- data/lib/garcon/utility/faker/faker.rb +164 -0
- data/lib/garcon/utility/faker/faker/company.rb +17 -0
- data/lib/garcon/utility/faker/faker/hacker.rb +30 -0
- data/lib/garcon/utility/faker/faker/version.rb +3 -0
- data/lib/garcon/utility/faker/locales/en-US.yml +83 -0
- data/lib/garcon/utility/faker/locales/en.yml +21 -0
- data/lib/garcon/utility/file_helper.rb +170 -0
- data/lib/garcon/utility/hookers.rb +178 -0
- data/lib/garcon/utility/interpolation.rb +90 -0
- data/lib/garcon/utility/memstash.rb +364 -0
- data/lib/garcon/utility/misc.rb +54 -0
- data/lib/garcon/utility/msg_from_god.rb +62 -0
- data/lib/garcon/utility/retry.rb +238 -0
- data/lib/garcon/utility/timeout.rb +58 -0
- data/lib/garcon/utility/uber/builder.rb +91 -0
- data/lib/garcon/utility/uber/callable.rb +7 -0
- data/lib/garcon/utility/uber/delegates.rb +13 -0
- data/lib/garcon/utility/uber/inheritable_attr.rb +37 -0
- data/lib/garcon/utility/uber/options.rb +101 -0
- data/lib/garcon/utility/uber/uber_version.rb +3 -0
- data/lib/garcon/utility/uber/version.rb +33 -0
- data/lib/garcon/utility/url_helper.rb +100 -0
- data/lib/garcon/utils.rb +29 -0
- data/lib/garcon/version.rb +62 -0
- data/lib/garcun.rb +24 -0
- metadata +680 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
module Garcon
|
|
21
|
+
# Define update methods that use direct paths
|
|
22
|
+
module AtomicDirectUpdate
|
|
23
|
+
|
|
24
|
+
# Pass the current value to the given block, replacing it with the block's
|
|
25
|
+
# result. May retry if the value changes during the block's execution.
|
|
26
|
+
#
|
|
27
|
+
# @yield [Object]
|
|
28
|
+
# Calculate a new value for the atomic reference using given (old) value.
|
|
29
|
+
# @yieldparam [Object] old_value
|
|
30
|
+
# The starting value of the atomic reference
|
|
31
|
+
#
|
|
32
|
+
# @return [Object]
|
|
33
|
+
# The new value
|
|
34
|
+
def update
|
|
35
|
+
true until compare_and_set(old_value = get, new_value = yield(old_value))
|
|
36
|
+
new_value
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Pass the current value to the given block, replacing it with the block's
|
|
40
|
+
# result. Raise an exception if the update fails.
|
|
41
|
+
#
|
|
42
|
+
# @yield [Object]
|
|
43
|
+
# Calculate a new value for the atomic reference using given (old) value.
|
|
44
|
+
# @yieldparam [Object] old_value
|
|
45
|
+
# The starting value of the atomic reference.
|
|
46
|
+
#
|
|
47
|
+
# @raise [Garcon::ConcurrentUpdateError]
|
|
48
|
+
# If the update fails
|
|
49
|
+
#
|
|
50
|
+
# @return [Object] the new value
|
|
51
|
+
def try_update
|
|
52
|
+
old_value = get
|
|
53
|
+
new_value = yield old_value
|
|
54
|
+
unless compare_and_set(old_value, new_value)
|
|
55
|
+
raise ConcurrentUpdateError, "Update failed"
|
|
56
|
+
end
|
|
57
|
+
new_value
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# Special "compare and set" handling of numeric values.
|
|
62
|
+
module AtomicNumericCompareAndSetWrapper
|
|
63
|
+
|
|
64
|
+
def compare_and_set(old_value, new_value)
|
|
65
|
+
if old_value.kind_of? Numeric
|
|
66
|
+
while true
|
|
67
|
+
old = get
|
|
68
|
+
|
|
69
|
+
return false unless old.kind_of? Numeric
|
|
70
|
+
|
|
71
|
+
return false unless old == old_value
|
|
72
|
+
|
|
73
|
+
result = _compare_and_set(old, new_value)
|
|
74
|
+
return result if result
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
_compare_and_set(old_value, new_value)
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
alias_method :compare_and_swap, :compare_and_set
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
class AtomicMutex
|
|
84
|
+
include Garcon::AtomicDirectUpdate
|
|
85
|
+
include Garcon::AtomicNumericCompareAndSetWrapper
|
|
86
|
+
|
|
87
|
+
def initialize(value = nil)
|
|
88
|
+
@mutex = Mutex.new
|
|
89
|
+
@value = value
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Gets the current value.
|
|
93
|
+
#
|
|
94
|
+
# @return [Object]
|
|
95
|
+
# The current value.
|
|
96
|
+
def get
|
|
97
|
+
@mutex.synchronize { @value }
|
|
98
|
+
end
|
|
99
|
+
alias_method :value, :get
|
|
100
|
+
|
|
101
|
+
# Sets to the given value.
|
|
102
|
+
#
|
|
103
|
+
# @param [Object] value
|
|
104
|
+
# The new value to set.
|
|
105
|
+
#
|
|
106
|
+
# @return [Object]
|
|
107
|
+
# The new value.
|
|
108
|
+
def set(value)
|
|
109
|
+
@mutex.synchronize { @value = value }
|
|
110
|
+
end
|
|
111
|
+
alias_method :value=, :set
|
|
112
|
+
|
|
113
|
+
# Atomically sets to the given value and returns the old value.
|
|
114
|
+
#
|
|
115
|
+
# @param [Object] value
|
|
116
|
+
# The new value to set.
|
|
117
|
+
#
|
|
118
|
+
# @return [Object]
|
|
119
|
+
# The old value.
|
|
120
|
+
def get_and_set(new_value)
|
|
121
|
+
@mutex.synchronize do
|
|
122
|
+
old_value = @value
|
|
123
|
+
@value = new_value
|
|
124
|
+
old_value
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
alias_method :swap, :get_and_set
|
|
128
|
+
|
|
129
|
+
# Atomically sets the value to the given updated value if the current value
|
|
130
|
+
# is equal the expected value.
|
|
131
|
+
#
|
|
132
|
+
# @param [Object] old_value
|
|
133
|
+
# The expected value.
|
|
134
|
+
# @param [Object] new_value
|
|
135
|
+
# The new value.
|
|
136
|
+
#
|
|
137
|
+
# @return [Boolean]
|
|
138
|
+
# `true` if successful, `false` indicates that the actual value was not
|
|
139
|
+
# equal to the expected value.
|
|
140
|
+
def _compare_and_set(old_value, new_value)
|
|
141
|
+
return false unless @mutex.try_lock
|
|
142
|
+
begin
|
|
143
|
+
return false unless @value.equal? old_value
|
|
144
|
+
@value = new_value
|
|
145
|
+
ensure
|
|
146
|
+
@mutex.unlock
|
|
147
|
+
end
|
|
148
|
+
true
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
module Garcon
|
|
21
|
+
|
|
22
|
+
# A boolean value that can be updated atomically. Reads and writes to an
|
|
23
|
+
# atomic boolean and thread-safe and guaranteed to succeed. Reads and writes
|
|
24
|
+
# may block briefly but no explicit locking is required.
|
|
25
|
+
#
|
|
26
|
+
class MutexAtomicBoolean
|
|
27
|
+
|
|
28
|
+
# Creates a new `AtomicBoolean` with the given initial value.
|
|
29
|
+
#
|
|
30
|
+
# @param [Boolean] initial
|
|
31
|
+
# the initial value
|
|
32
|
+
#
|
|
33
|
+
# @api public
|
|
34
|
+
def initialize(initial = false)
|
|
35
|
+
@value = !!initial
|
|
36
|
+
@mutex = Mutex.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Retrieves the current `Boolean` value.
|
|
40
|
+
#
|
|
41
|
+
# @return [Boolean]
|
|
42
|
+
# the current value
|
|
43
|
+
#
|
|
44
|
+
# @api public
|
|
45
|
+
def value
|
|
46
|
+
@mutex.lock
|
|
47
|
+
@value
|
|
48
|
+
ensure
|
|
49
|
+
@mutex.unlock
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Explicitly sets the value.
|
|
53
|
+
#
|
|
54
|
+
# @param [Boolean] value
|
|
55
|
+
# the new value to be set
|
|
56
|
+
#
|
|
57
|
+
# @return [Boolean]
|
|
58
|
+
# the current value
|
|
59
|
+
#
|
|
60
|
+
# @api public
|
|
61
|
+
def value=(value)
|
|
62
|
+
@mutex.lock
|
|
63
|
+
@value = !!value
|
|
64
|
+
@value
|
|
65
|
+
ensure
|
|
66
|
+
@mutex.unlock
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Is the current value `true`
|
|
70
|
+
#
|
|
71
|
+
# @return [Boolean]
|
|
72
|
+
# True if the current value is `true`, else false
|
|
73
|
+
#
|
|
74
|
+
# @api public
|
|
75
|
+
def true?
|
|
76
|
+
@mutex.lock
|
|
77
|
+
@value
|
|
78
|
+
ensure
|
|
79
|
+
@mutex.unlock
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Is the current value `false`
|
|
83
|
+
#
|
|
84
|
+
# @return [Boolean]
|
|
85
|
+
# True if the current value is `false`, else false
|
|
86
|
+
#
|
|
87
|
+
# @api public
|
|
88
|
+
def false?
|
|
89
|
+
@mutex.lock
|
|
90
|
+
!@value
|
|
91
|
+
ensure
|
|
92
|
+
@mutex.unlock
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Explicitly sets the value to true.
|
|
96
|
+
#
|
|
97
|
+
# @return [Boolean]
|
|
98
|
+
# True is value has changed, otherwise false
|
|
99
|
+
#
|
|
100
|
+
# @api public
|
|
101
|
+
def make_true
|
|
102
|
+
@mutex.lock
|
|
103
|
+
old = @value
|
|
104
|
+
@value = true
|
|
105
|
+
!old
|
|
106
|
+
ensure
|
|
107
|
+
@mutex.unlock
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Explicitly sets the value to false.
|
|
111
|
+
#
|
|
112
|
+
# @return [Boolean]
|
|
113
|
+
# True is value has changed, otherwise false
|
|
114
|
+
#
|
|
115
|
+
# @api public
|
|
116
|
+
def make_false
|
|
117
|
+
@mutex.lock
|
|
118
|
+
old = @value
|
|
119
|
+
@value = false
|
|
120
|
+
old
|
|
121
|
+
ensure
|
|
122
|
+
@mutex.unlock
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class AtomicBoolean < MutexAtomicBoolean; end
|
|
127
|
+
end
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require_relative 'monotonic_time'
|
|
21
|
+
|
|
22
|
+
module Garcon
|
|
23
|
+
|
|
24
|
+
# Condition is a better implementation of standard Ruby ConditionVariable. The
|
|
25
|
+
# biggest difference is the wait return value: Condition#wait returns
|
|
26
|
+
# Condition::Result which make possible to know if waiting thread has been
|
|
27
|
+
# woken up by an another thread (using #signal or #broadcast) or due to
|
|
28
|
+
# timeout.
|
|
29
|
+
#
|
|
30
|
+
# Every #wait must be guarded by a locked Mutex or a ThreadError will be
|
|
31
|
+
# risen. Although it's not mandatory, it's recommended to call also #signal
|
|
32
|
+
# and #broadcast within the same mutex
|
|
33
|
+
class Condition
|
|
34
|
+
|
|
35
|
+
class Result
|
|
36
|
+
def initialize(remaining_time)
|
|
37
|
+
@remaining_time = remaining_time
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
attr_reader :remaining_time
|
|
41
|
+
|
|
42
|
+
# @return [Boolean]
|
|
43
|
+
# Returns true if current thread has been waken up by a #signal or a
|
|
44
|
+
# #broadcast call, otherwise false.
|
|
45
|
+
def woken_up?
|
|
46
|
+
@remaining_time.nil? || @remaining_time > 0
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @return [Boolean]
|
|
50
|
+
# Returns true if current thread has been waken up due to a timeout,
|
|
51
|
+
# otherwise false.
|
|
52
|
+
def timed_out?
|
|
53
|
+
@remaining_time != nil && @remaining_time <= 0
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
alias_method :can_wait?, :woken_up?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def initialize
|
|
60
|
+
@condition = ConditionVariable.new
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @param [Mutex] mutex
|
|
64
|
+
# The locked mutex guarding the wait.
|
|
65
|
+
#
|
|
66
|
+
# @param [Object] timeout
|
|
67
|
+
# Nil means no timeout.
|
|
68
|
+
#
|
|
69
|
+
# @return [Result]
|
|
70
|
+
#
|
|
71
|
+
# @!macro monotonic_clock_warning
|
|
72
|
+
def wait(mutex, timeout = nil)
|
|
73
|
+
start_time = Garcon.monotonic_time
|
|
74
|
+
@condition.wait(mutex, timeout)
|
|
75
|
+
|
|
76
|
+
if timeout.nil?
|
|
77
|
+
Result.new(nil)
|
|
78
|
+
else
|
|
79
|
+
Result.new(start_time + timeout - Garcon.monotonic_time)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Wakes up a waiting thread
|
|
84
|
+
#
|
|
85
|
+
# @return [true]
|
|
86
|
+
def signal
|
|
87
|
+
@condition.signal
|
|
88
|
+
true
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Wakes up all waiting threads
|
|
92
|
+
#
|
|
93
|
+
# @return [true]
|
|
94
|
+
def broadcast
|
|
95
|
+
@condition.broadcast
|
|
96
|
+
true
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
module Garcon
|
|
21
|
+
|
|
22
|
+
# A thread safe observer set implemented using copy-on-read approach:
|
|
23
|
+
# observers are added and removed from a thread safe collection; every time
|
|
24
|
+
# a notification is required the internal data structure is copied to
|
|
25
|
+
# prevent concurrency issues
|
|
26
|
+
class CopyOnNotifyObserverSet
|
|
27
|
+
|
|
28
|
+
def initialize
|
|
29
|
+
@mutex = Mutex.new
|
|
30
|
+
@observers = {}
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Adds an observer to this set. If a block is passed, the observer will be
|
|
34
|
+
# created by this method and no other params should be passed
|
|
35
|
+
#
|
|
36
|
+
# @param [Object] observer
|
|
37
|
+
# The observer to add
|
|
38
|
+
#
|
|
39
|
+
# @param [Symbol] func
|
|
40
|
+
# The function to call on the observer during notification. The default
|
|
41
|
+
# is :update
|
|
42
|
+
#
|
|
43
|
+
# @return [Object]
|
|
44
|
+
# the added observer
|
|
45
|
+
def add_observer(observer = nil, func = :update, &block)
|
|
46
|
+
if observer.nil? && block.nil?
|
|
47
|
+
raise ArgumentError, 'should pass observer as a first argument or block'
|
|
48
|
+
elsif observer && block
|
|
49
|
+
raise ArgumentError.new('cannot provide both an observer and a block')
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if block
|
|
53
|
+
observer = block
|
|
54
|
+
func = :call
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
begin
|
|
58
|
+
@mutex.lock
|
|
59
|
+
@observers[observer] = func
|
|
60
|
+
ensure
|
|
61
|
+
@mutex.unlock
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
observer
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# @param [Object] observer
|
|
68
|
+
# the observer to remove
|
|
69
|
+
# @return [Object]
|
|
70
|
+
# the deleted observer
|
|
71
|
+
def delete_observer(observer)
|
|
72
|
+
@mutex.lock
|
|
73
|
+
@observers.delete(observer)
|
|
74
|
+
@mutex.unlock
|
|
75
|
+
|
|
76
|
+
observer
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Deletes all observers
|
|
80
|
+
# @return [CopyOnWriteObserverSet] self
|
|
81
|
+
def delete_observers
|
|
82
|
+
@mutex.lock
|
|
83
|
+
@observers.clear
|
|
84
|
+
@mutex.unlock
|
|
85
|
+
|
|
86
|
+
self
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @return [Integer]
|
|
90
|
+
# the observers count
|
|
91
|
+
def count_observers
|
|
92
|
+
@mutex.lock
|
|
93
|
+
result = @observers.count
|
|
94
|
+
@mutex.unlock
|
|
95
|
+
|
|
96
|
+
result
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# Notifies all registered observers with optional args
|
|
100
|
+
#
|
|
101
|
+
# @param [Object] args
|
|
102
|
+
# arguments to be passed to each observer
|
|
103
|
+
#
|
|
104
|
+
# @return [CopyOnWriteObserverSet] self
|
|
105
|
+
def notify_observers(*args, &block)
|
|
106
|
+
observers = duplicate_observers
|
|
107
|
+
notify_to(observers, *args, &block)
|
|
108
|
+
|
|
109
|
+
self
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# Notifies all registered observers with optional args and deletes them.
|
|
113
|
+
#
|
|
114
|
+
# @param [Object] args
|
|
115
|
+
# arguments to be passed to each observer
|
|
116
|
+
#
|
|
117
|
+
# @return [CopyOnWriteObserverSet] self
|
|
118
|
+
def notify_and_delete_observers(*args, &block)
|
|
119
|
+
observers = duplicate_and_clear_observers
|
|
120
|
+
notify_to(observers, *args, &block)
|
|
121
|
+
|
|
122
|
+
self
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private # P R O P R I E T À P R I V A T A Vietato L'accesso
|
|
126
|
+
|
|
127
|
+
def duplicate_and_clear_observers
|
|
128
|
+
@mutex.lock
|
|
129
|
+
observers = @observers.dup
|
|
130
|
+
@observers.clear
|
|
131
|
+
@mutex.unlock
|
|
132
|
+
|
|
133
|
+
observers
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def duplicate_observers
|
|
137
|
+
@mutex.lock
|
|
138
|
+
observers = @observers.dup
|
|
139
|
+
@mutex.unlock
|
|
140
|
+
|
|
141
|
+
observers
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def notify_to(observers, *args)
|
|
145
|
+
if block_given? && !args.empty?
|
|
146
|
+
raise ArgumentError.new 'cannot give arguments and a block'
|
|
147
|
+
end
|
|
148
|
+
observers.each do |observer, function|
|
|
149
|
+
args = yield if block_given?
|
|
150
|
+
observer.send(function, *args)
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|