blob: cada6292b5fef180f8241b21cbc8d69c9dac8957 [file] [log] [blame]
/*
* Copyright 2020 The WebRTC Project Authors. All rights reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_RACE_CHECK_H_
#define RTC_BASE_SYNCHRONIZATION_MUTEX_RACE_CHECK_H_
#include <atomic>
#include "absl/base/attributes.h"
#include "rtc_base/checks.h"
#include "rtc_base/system/unused.h"
#include "rtc_base/thread_annotations.h"
namespace webrtc {
// This implementation class is useful when a consuming project can guarantee
// that all WebRTC invocation is happening serially. Additionally, the consuming
// project cannot use WebRTC code that spawn threads or task queues.
//
// The class internally check fails on Lock() if it finds the consumer actually
// invokes WebRTC concurrently.
//
// To use the race check mutex, define WEBRTC_RACE_CHECK_MUTEX globally. This
// also adds a dependency to absl::Mutex from logging.cc because even though
// objects are invoked serially, the logging is static and invoked concurrently
// and hence needs protection.
class RTC_LOCKABLE MutexImpl final {
public:
MutexImpl() = default;
MutexImpl(const MutexImpl&) = delete;
MutexImpl& operator=(const MutexImpl&) = delete;
void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() {
bool was_free = free_.exchange(false, std::memory_order_acquire);
RTC_CHECK(was_free)
<< "WEBRTC_RACE_CHECK_MUTEX: mutex locked concurrently.";
}
ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
bool was_free = free_.exchange(false, std::memory_order_acquire);
return was_free;
}
void Unlock() RTC_UNLOCK_FUNCTION() {
free_.store(true, std::memory_order_release);
}
private:
// Release-acquire ordering is used.
// - In the Lock methods we're guaranteeing that reads and writes happening
// after the (Try)Lock don't appear to have happened before the Lock (acquire
// ordering).
// - In the Unlock method we're guaranteeing that reads and writes happening
// before the Unlock don't appear to happen after it (release ordering).
std::atomic<bool> free_{true};
};
} // namespace webrtc
#endif // RTC_BASE_SYNCHRONIZATION_MUTEX_RACE_CHECK_H_