aboutsummaryrefslogtreecommitdiffhomepage
path: root/tensorflow/core/platform
diff options
context:
space:
mode:
authorGravatar Justin Lebar <jlebar@google.com>2018-08-06 14:41:01 -0700
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2018-08-06 14:45:30 -0700
commite8def0cec8cf2399e333dbe804f29ae26e8997c9 (patch)
tree1d43d93dca7aef6940b5dfb4a7e73d88db87b9f9 /tensorflow/core/platform
parent2c6ae175591a687aae4d3ab69b5719d0b656ea13 (diff)
Add missing annotation to mutex_lock's move constructor.
Because ~mutex_lock() is marked as an UNLOCK_FUNCTION, we have to mark the move constructor as locking ml.mu_. Otherwise if you try to move a mutex_lock, clang sees the destructor call and thinks that the mutex has been unlocked for good. Same for tf_shared_lock. Also make tf_shared_lock's move constructor non-explicit. This is just a performance optimization; tf_shared_lock was already copyable. PiperOrigin-RevId: 207610922
Diffstat (limited to 'tensorflow/core/platform')
-rw-r--r--tensorflow/core/platform/default/mutex.h8
-rw-r--r--tensorflow/core/platform/mutex_test.cc39
2 files changed, 45 insertions, 2 deletions
diff --git a/tensorflow/core/platform/default/mutex.h b/tensorflow/core/platform/default/mutex.h
index 89e57d58a0..48d90779e1 100644
--- a/tensorflow/core/platform/default/mutex.h
+++ b/tensorflow/core/platform/default/mutex.h
@@ -77,7 +77,10 @@ class SCOPED_LOCKABLE mutex_lock {
// Manually nulls out the source to prevent double-free.
// (std::move does not null the source pointer by default.)
- mutex_lock(mutex_lock&& ml) noexcept : mu_(ml.mu_) { ml.mu_ = nullptr; }
+ mutex_lock(mutex_lock&& ml) noexcept EXCLUSIVE_LOCK_FUNCTION(ml.mu_)
+ : mu_(ml.mu_) {
+ ml.mu_ = nullptr;
+ }
~mutex_lock() UNLOCK_FUNCTION() {
if (mu_ != nullptr) {
mu_->unlock();
@@ -113,7 +116,8 @@ class SCOPED_LOCKABLE tf_shared_lock {
// Manually nulls out the source to prevent double-free.
// (std::move does not null the source pointer by default.)
- explicit tf_shared_lock(tf_shared_lock&& ml) noexcept : mu_(ml.mu_) {
+ tf_shared_lock(tf_shared_lock&& ml) noexcept SHARED_LOCK_FUNCTION(ml.mu_)
+ : mu_(ml.mu_) {
ml.mu_ = nullptr;
}
~tf_shared_lock() UNLOCK_FUNCTION() {
diff --git a/tensorflow/core/platform/mutex_test.cc b/tensorflow/core/platform/mutex_test.cc
new file mode 100644
index 0000000000..7ba57775dd
--- /dev/null
+++ b/tensorflow/core/platform/mutex_test.cc
@@ -0,0 +1,39 @@
+/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+==============================================================================*/
+
+#include "tensorflow/core/platform/mutex.h"
+#include "tensorflow/core/platform/test.h"
+
+namespace tensorflow {
+namespace {
+
+// Check that mutex_lock and shared_mutex_lock are movable and that their
+// thread-safety annotations are correct enough that we don't get an error when
+// we use a moved-from lock. (For instance, we might incorrectly get an error
+// at the end of Test() when we destruct the mutex_lock, if the compiler isn't
+// aware that the mutex is in fact locked at this point.)
+struct MovableMutexLockTest {
+ mutex_lock GetLock() { return mutex_lock{mu}; }
+ void Test() { mutex_lock lock = GetLock(); }
+ mutex mu;
+};
+struct SharedMutexLockTest {
+ tf_shared_lock GetLock() { return tf_shared_lock{mu}; }
+ void Test() { tf_shared_lock lock = GetLock(); }
+ mutex mu;
+};
+
+} // namespace
+} // namespace tensorflow