copland 0.8.0 → 1.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.
- data/doc/manual-html/chapter-1.html +227 -36
- data/doc/manual-html/chapter-10.html +155 -82
- data/doc/manual-html/chapter-11.html +90 -267
- data/doc/manual-html/chapter-12.html +289 -71
- data/doc/manual-html/chapter-13.html +430 -0
- data/doc/manual-html/chapter-2.html +45 -21
- data/doc/manual-html/chapter-3.html +45 -21
- data/doc/manual-html/chapter-4.html +45 -21
- data/doc/manual-html/chapter-5.html +45 -21
- data/doc/manual-html/chapter-6.html +49 -21
- data/doc/manual-html/chapter-7.html +45 -21
- data/doc/manual-html/chapter-8.html +66 -26
- data/doc/manual-html/chapter-9.html +48 -24
- data/doc/manual-html/index.html +54 -22
- data/doc/manual-html/manual.css +12 -0
- data/doc/manual-html/tutorial-1.html +45 -21
- data/doc/manual-html/tutorial-2.html +45 -21
- data/doc/manual-html/tutorial-3.html +45 -21
- data/doc/manual-html/tutorial-4.html +45 -21
- data/doc/manual-html/tutorial-5.html +45 -21
- data/doc/manual/manual.css +12 -0
- data/doc/manual/manual.rb +1 -1
- data/doc/manual/manual.yml +426 -20
- data/doc/packages/copland.html +41 -9
- data/doc/packages/copland.lib.html +36 -8
- data/doc/packages/copland.remote.html +46 -10
- data/doc/packages/copland.webrick.html +16 -65
- data/doc/packages/index.html +1 -1
- data/doc/presentation/copland.mgp +1083 -0
- data/doc/presentation/to_html.rb +52 -0
- data/lib/copland/configuration-point/common.rb +32 -1
- data/lib/copland/configuration/yaml/service-point.rb +10 -1
- data/lib/copland/log-factory.rb +28 -12
- data/lib/copland/logger.rb +155 -0
- data/lib/copland/models/singleton.rb +8 -2
- data/lib/copland/package.rb +32 -14
- data/lib/copland/service-point.rb +7 -0
- data/lib/copland/thread.rb +104 -0
- data/lib/copland/utils.rb +10 -3
- data/lib/copland/version.rb +2 -2
- data/test/configuration/yaml/tc_service-point-processor.rb +8 -0
- data/test/custom-logger.yml +2 -1
- data/test/impl/tc_logging-interceptor.rb +12 -12
- data/test/logger.yml +1 -1
- data/test/mock.rb +2 -0
- data/test/tc_logger.rb +19 -6
- data/test/tc_package.rb +25 -0
- data/test/tc_queryable-mutex.rb +75 -0
- data/test/tc_registry.rb +8 -4
- metadata +9 -2
@@ -88,6 +88,12 @@ module Copland
|
|
88
88
|
# passed to the factory when a new instance is required.
|
89
89
|
attr_accessor :schema
|
90
90
|
|
91
|
+
# The visibility of this service point. If <tt>:public</tt> (the default),
|
92
|
+
# the service point is accessible outside of its package. If it is
|
93
|
+
# <tt>:private</tt>, then it is only directly accessible to other services
|
94
|
+
# within its package.
|
95
|
+
attr_accessor :visibility
|
96
|
+
|
91
97
|
# Create a new service point, contained by the +owner+ package. The only
|
92
98
|
# recognized option currently is <tt>:default_service_model</tt>, which
|
93
99
|
# is used to identify the service model to use when no other service model
|
@@ -95,6 +101,7 @@ module Copland
|
|
95
101
|
def initialize( owner, name, opts={} )
|
96
102
|
@owner = owner
|
97
103
|
@name = name
|
104
|
+
@visibility = :public
|
98
105
|
|
99
106
|
use_service_model opts[ :default_service_model ] || DEFAULT_SERVICE_MODEL
|
100
107
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
#--
|
2
|
+
# =============================================================================
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# * Redistributions in binary form must reproduce the above copyright
|
13
|
+
# notice, this list of conditions and the following disclaimer in the
|
14
|
+
# documentation and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# * The names of its contributors may not be used to endorse or promote
|
17
|
+
# products derived from this software without specific prior written
|
18
|
+
# permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
# =============================================================================
|
32
|
+
#++
|
33
|
+
|
34
|
+
require 'thread'
|
35
|
+
|
36
|
+
module Copland
|
37
|
+
|
38
|
+
# A subclass of Mutex that allows clients to discover which thread has the
|
39
|
+
# mutex locked. This is necessary for (among other things) discovering
|
40
|
+
# cycles in the dependency graph of services.
|
41
|
+
class QueryableMutex < Mutex
|
42
|
+
|
43
|
+
# Checks to see if the current thread has the mutex locked, and if it
|
44
|
+
# does, raises an exception. Otherwise, locks the mutex and sets the
|
45
|
+
# locking thread to Thread.current.
|
46
|
+
def lock
|
47
|
+
if @locking_thread == Thread.current
|
48
|
+
raise ThreadError,
|
49
|
+
"an attempt was made to reacquire an existing lock " +
|
50
|
+
"(this could happen if you have a circular dependency on a service)"
|
51
|
+
end
|
52
|
+
|
53
|
+
while (Thread.critical = true; @locked)
|
54
|
+
@waiting.push Thread.current
|
55
|
+
Thread.stop
|
56
|
+
end
|
57
|
+
@locked = true
|
58
|
+
@locking_thread = Thread.current
|
59
|
+
Thread.critical = false
|
60
|
+
self
|
61
|
+
end
|
62
|
+
|
63
|
+
# Attempts to acquire the lock. Returns +true+ if the lock was acquired,
|
64
|
+
# and +false+ if the mutex was already locked.
|
65
|
+
def try_lock
|
66
|
+
result = false
|
67
|
+
Thread.critical = true
|
68
|
+
unless @locked
|
69
|
+
@locked = true
|
70
|
+
result = true
|
71
|
+
@locking_thread = Thread.current
|
72
|
+
end
|
73
|
+
Thread.critical = false
|
74
|
+
result
|
75
|
+
end
|
76
|
+
|
77
|
+
# Unlocks the mutex and sets the locking thread to +nil+.
|
78
|
+
def unlock
|
79
|
+
return unless @locked
|
80
|
+
Thread.critical = true
|
81
|
+
@locked = false
|
82
|
+
begin
|
83
|
+
t = @waiting.shift
|
84
|
+
t.wakeup if t
|
85
|
+
rescue ThreadError
|
86
|
+
retry
|
87
|
+
end
|
88
|
+
@locking_thread = nil
|
89
|
+
Thread.critical = false
|
90
|
+
begin
|
91
|
+
t.run if t
|
92
|
+
rescue ThreadError
|
93
|
+
end
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
# Return +true+ if the current thread has locked this mutex.
|
98
|
+
def self_locked?
|
99
|
+
@locking_thread == Thread.current
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
data/lib/copland/utils.rb
CHANGED
@@ -51,15 +51,19 @@ module Copland
|
|
51
51
|
# it passes the correct pkg and unqualified service name to the block and
|
52
52
|
# returns the result.
|
53
53
|
def get_possibly_local_service( registry, pkg, id )
|
54
|
+
original_package = pkg
|
55
|
+
|
54
56
|
if id =~ /^(.+)\.([^.]+)$/
|
55
57
|
pkg = registry.package( $1 )
|
56
58
|
id = $2
|
57
59
|
end
|
58
60
|
|
61
|
+
local_service = ( original_package == pkg )
|
62
|
+
|
59
63
|
if block_given?
|
60
|
-
yield pkg, id
|
64
|
+
yield pkg, id, local_service
|
61
65
|
else
|
62
|
-
pkg.service( id )
|
66
|
+
pkg.service( id, local_service )
|
63
67
|
end
|
64
68
|
end
|
65
69
|
|
@@ -121,7 +125,9 @@ module Copland
|
|
121
125
|
# real:: the value is interpreted as a floating point
|
122
126
|
# string:: the value is interpreted as a string
|
123
127
|
def translate_value( registry, pkg, point, value )
|
124
|
-
|
128
|
+
unless Thread.current[:disable_symbol_substitution]
|
129
|
+
substitute_symbols( registry, value )
|
130
|
+
end
|
125
131
|
|
126
132
|
if value.is_a?( Array )
|
127
133
|
return translate_array( registry, pkg, point, value )
|
@@ -140,6 +146,7 @@ module Copland
|
|
140
146
|
pkg.configuration_point id
|
141
147
|
end
|
142
148
|
raise ConfigurationPointNotFound, value.value unless cfg
|
149
|
+
cfg.substitute_symbols!
|
143
150
|
return cfg
|
144
151
|
when "class"
|
145
152
|
return get_class( value.value )
|
data/lib/copland/version.rb
CHANGED
@@ -81,6 +81,13 @@ class TC_ServicePointProcessor < Test::Unit::TestCase
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
def test_bad_visibility_type
|
85
|
+
assert_raise( Copland::Configuration::ParserError ) do
|
86
|
+
@processor.process "name", "implementor" => "something",
|
87
|
+
"visibility" => "blah"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
84
91
|
def test_valid
|
85
92
|
point = nil
|
86
93
|
|
@@ -91,6 +98,7 @@ class TC_ServicePointProcessor < Test::Unit::TestCase
|
|
91
98
|
"description" => "a",
|
92
99
|
"interceptors" => [],
|
93
100
|
"listen-to" => [],
|
101
|
+
"visibility" => "private",
|
94
102
|
"schema" => "mock.MockParameterProcessor"
|
95
103
|
end
|
96
104
|
|
data/test/custom-logger.yml
CHANGED
@@ -63,8 +63,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
|
|
63
63
|
|
64
64
|
assert_equal "", @device.message
|
65
65
|
service.echo 15
|
66
|
-
assert_match(
|
67
|
-
assert_match(
|
66
|
+
assert_match( /\[DEBUG\] .* -- logging.Test: echo\( 15 \)/, @device.message )
|
67
|
+
assert_match( /\[DEBUG\] .* -- logging.Test: echo => 15/, @device.message )
|
68
68
|
end
|
69
69
|
|
70
70
|
def test_exclude
|
@@ -72,8 +72,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
|
|
72
72
|
|
73
73
|
assert_equal "", @device.message
|
74
74
|
service.echo 15
|
75
|
-
assert_match(
|
76
|
-
assert_match(
|
75
|
+
assert_match( /\[DEBUG\] .* -- logging.TestExclude: echo\( 15 \)/, @device.message )
|
76
|
+
assert_match( /\[DEBUG\] .* -- logging.TestExclude: echo => 15/, @device.message )
|
77
77
|
|
78
78
|
@device.clear
|
79
79
|
assert_equal "", @device.message
|
@@ -91,8 +91,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
|
|
91
91
|
|
92
92
|
assert_equal "", @device.message
|
93
93
|
service.echo 15
|
94
|
-
assert_match(
|
95
|
-
assert_match(
|
94
|
+
assert_match( /\[DEBUG\] .* -- logging.TestInclude: echo\( 15 \)/, @device.message )
|
95
|
+
assert_match( /\[DEBUG\] .* -- logging.TestInclude: echo => 15/, @device.message )
|
96
96
|
|
97
97
|
@device.clear
|
98
98
|
assert_equal "", @device.message
|
@@ -102,8 +102,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
|
|
102
102
|
@device.clear
|
103
103
|
assert_equal "", @device.message
|
104
104
|
service.echo_notme_multiple 15, 16
|
105
|
-
assert_match(
|
106
|
-
assert_match(
|
105
|
+
assert_match( /\[DEBUG\] .* -- logging.TestInclude: echo_notme_multiple\( 15, 16 \)/, @device.message )
|
106
|
+
assert_match( /\[DEBUG\] .* -- logging.TestInclude: echo_notme_multiple => \[15, 16\]/, @device.message )
|
107
107
|
end
|
108
108
|
|
109
109
|
def test_include2
|
@@ -112,8 +112,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
|
|
112
112
|
@device.clear
|
113
113
|
assert_equal "", @device.message
|
114
114
|
service.echo_notme 15
|
115
|
-
assert_match(
|
116
|
-
assert_match(
|
115
|
+
assert_match( /\[DEBUG\] .* -- logging.TestInclude2: echo_notme\( 15 \)/, @device.message )
|
116
|
+
assert_match( /\[DEBUG\] .* -- logging.TestInclude2: echo_notme => 15/, @device.message )
|
117
117
|
|
118
118
|
@device.clear
|
119
119
|
assert_equal "", @device.message
|
@@ -126,8 +126,8 @@ class TC_LoggingInterceptor < Test::Unit::TestCase
|
|
126
126
|
|
127
127
|
assert_equal "", @device.message
|
128
128
|
service.echo 15, 16, 17
|
129
|
-
assert_match(
|
130
|
-
assert_match(
|
129
|
+
assert_match( /\[DEBUG\] .* -- logging.TestArity: echo\( 15, 16, 17 \)/, @device.message )
|
130
|
+
assert_match( /\[DEBUG\] .* -- logging.TestArity: echo => \[15, 16, 17\]/, @device.message )
|
131
131
|
|
132
132
|
@device.clear
|
133
133
|
assert_equal "", @device.message
|
data/test/logger.yml
CHANGED
data/test/mock.rb
CHANGED
@@ -91,12 +91,14 @@ class MockServicePoint
|
|
91
91
|
|
92
92
|
attr_accessor :instantiator
|
93
93
|
attr_accessor :parameter_processor
|
94
|
+
attr_accessor :visibility
|
94
95
|
|
95
96
|
def initialize( message="" )
|
96
97
|
@message = message
|
97
98
|
@pending_interceptors = []
|
98
99
|
@event_producers = []
|
99
100
|
@listeners = []
|
101
|
+
@visibility = :public
|
100
102
|
end
|
101
103
|
|
102
104
|
def instance
|
data/test/tc_logger.rb
CHANGED
@@ -62,21 +62,21 @@ class TC_Logger < Test::Unit::TestCase
|
|
62
62
|
def test_log_config
|
63
63
|
factory = Copland::LogFactory.new
|
64
64
|
assert_equal "./sample.log", factory.device.filename
|
65
|
-
assert_equal "%Y-%m-%d %H:%M:%S", factory.
|
65
|
+
assert_equal "%Y-%m-%d %H:%M:%S", factory.default_date_format
|
66
66
|
assert_equal Logger::INFO, factory.default_level
|
67
67
|
factory.close
|
68
68
|
|
69
69
|
factory = Copland::LogFactory.new :config_file => 'custom-logger.yml'
|
70
70
|
assert_equal "./custom.log", factory.device.filename
|
71
|
-
assert_equal "date %Y-%m-%d %H:%M:%S", factory.
|
71
|
+
assert_equal "date %Y-%m-%d %H:%M:%S", factory.default_date_format
|
72
72
|
assert_equal Logger::FATAL, factory.default_level
|
73
73
|
factory.close
|
74
74
|
end
|
75
75
|
|
76
76
|
def test_log_options
|
77
|
-
factory = Copland::LogFactory.new :
|
77
|
+
factory = Copland::LogFactory.new :default_date_format => "%Y",
|
78
78
|
:default_level => Logger::FATAL
|
79
|
-
assert_equal "%Y", factory.
|
79
|
+
assert_equal "%Y", factory.default_date_format
|
80
80
|
assert_equal Logger::FATAL, factory.default_level
|
81
81
|
factory.close
|
82
82
|
end
|
@@ -105,7 +105,7 @@ class TC_Logger < Test::Unit::TestCase
|
|
105
105
|
assert_equal "", io.message
|
106
106
|
|
107
107
|
log.info "test"
|
108
|
-
assert_match(
|
108
|
+
assert_match( /\[INFO \] .* -- test.log1: test/, io.message )
|
109
109
|
|
110
110
|
factory.close
|
111
111
|
assert_equal "<closed>", io.message
|
@@ -123,9 +123,22 @@ class TC_Logger < Test::Unit::TestCase
|
|
123
123
|
log = factory.get( "level.test.log1" )
|
124
124
|
|
125
125
|
log.debug "test"
|
126
|
-
assert_match(
|
126
|
+
assert_match( /\[DEBUG\] .* -- level.test.log1: test/, io.message )
|
127
127
|
|
128
128
|
factory.close
|
129
129
|
end
|
130
130
|
|
131
|
+
def test_message_format
|
132
|
+
io = MockLogIO.new
|
133
|
+
factory = Copland::LogFactory.new :device => io,
|
134
|
+
:default_message_format => "%c %C [%-5p] %F %m %M %t %% %$"
|
135
|
+
|
136
|
+
log = factory.get( "message.log1" )
|
137
|
+
log.info "test"
|
138
|
+
assert_match(
|
139
|
+
/log1 message.log1 \[INFO \] \S*tc_logger.rb test test_message_format #{Thread.current.__id__} % #{$$}\n/,
|
140
|
+
io.message
|
141
|
+
)
|
142
|
+
end
|
143
|
+
|
131
144
|
end
|
data/test/tc_package.rb
CHANGED
@@ -121,6 +121,31 @@ class TC_Package < Test::Unit::TestCase
|
|
121
121
|
end
|
122
122
|
end
|
123
123
|
|
124
|
+
def test_public_private
|
125
|
+
assert_equal 0, @package.service_points.length
|
126
|
+
|
127
|
+
point = MockServicePoint.new
|
128
|
+
point.visibility = :private
|
129
|
+
@package.add_service_point point
|
130
|
+
|
131
|
+
assert_equal 0, @package.service_point_count
|
132
|
+
assert_equal 1, @package.service_point_count(true)
|
133
|
+
|
134
|
+
assert_equal 0, @package.service_points.length
|
135
|
+
assert_equal 1, @package.service_points(true).length
|
136
|
+
|
137
|
+
assert_nil @package.service_point( "point" )
|
138
|
+
assert_not_nil @package.service_point( "point", true )
|
139
|
+
|
140
|
+
assert_raise( Copland::ServicePointNotFound ) do
|
141
|
+
@package.service( "point" )
|
142
|
+
end
|
143
|
+
|
144
|
+
assert_nothing_raised do
|
145
|
+
@package.service( "point", true )
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
124
149
|
def test_configuration_points
|
125
150
|
assert_equal 0, @package.configuration_points.length
|
126
151
|
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#--
|
2
|
+
# =============================================================================
|
3
|
+
# Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
|
4
|
+
# All rights reserved.
|
5
|
+
#
|
6
|
+
# Redistribution and use in source and binary forms, with or without
|
7
|
+
# modification, are permitted provided that the following conditions are met:
|
8
|
+
#
|
9
|
+
# * Redistributions of source code must retain the above copyright notice,
|
10
|
+
# this list of conditions and the following disclaimer.
|
11
|
+
#
|
12
|
+
# * Redistributions in binary form must reproduce the above copyright
|
13
|
+
# notice, this list of conditions and the following disclaimer in the
|
14
|
+
# documentation and/or other materials provided with the distribution.
|
15
|
+
#
|
16
|
+
# * The names of its contributors may not be used to endorse or promote
|
17
|
+
# products derived from this software without specific prior written
|
18
|
+
# permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
23
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
24
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
25
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
26
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
27
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
28
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
29
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
30
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
# =============================================================================
|
32
|
+
#++
|
33
|
+
|
34
|
+
$:.unshift "../lib"
|
35
|
+
|
36
|
+
require 'test/unit'
|
37
|
+
require 'copland/thread'
|
38
|
+
|
39
|
+
class TC_QueryableMutex < Test::Unit::TestCase
|
40
|
+
|
41
|
+
def test_lock
|
42
|
+
mutex = Copland::QueryableMutex.new
|
43
|
+
assert !mutex.self_locked?
|
44
|
+
mutex.lock
|
45
|
+
assert mutex.self_locked?
|
46
|
+
mutex.unlock
|
47
|
+
assert !mutex.self_locked?
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_reacquire_error
|
51
|
+
mutex = Copland::QueryableMutex.new
|
52
|
+
mutex.lock
|
53
|
+
assert_raise( ThreadError ) do
|
54
|
+
mutex.lock
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_safe_reacquire
|
59
|
+
mutex = Copland::QueryableMutex.new
|
60
|
+
mutex.lock
|
61
|
+
|
62
|
+
t = Thread.new do
|
63
|
+
assert mutex.locked?
|
64
|
+
assert !mutex.self_locked?
|
65
|
+
mutex.synchronize do
|
66
|
+
assert mutex.self_locked?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
assert_nil t.join(0.1)
|
71
|
+
mutex.unlock
|
72
|
+
assert_not_nil t.join
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|