1*d9f75844SAndroid Build Coastguard Worker /* 2*d9f75844SAndroid Build Coastguard Worker * Copyright 2020 The WebRTC Project Authors. All rights reserved. 3*d9f75844SAndroid Build Coastguard Worker * 4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license 5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source 6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found 7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may 8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree. 9*d9f75844SAndroid Build Coastguard Worker */ 10*d9f75844SAndroid Build Coastguard Worker 11*d9f75844SAndroid Build Coastguard Worker #ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ 12*d9f75844SAndroid Build Coastguard Worker #define RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ 13*d9f75844SAndroid Build Coastguard Worker 14*d9f75844SAndroid Build Coastguard Worker #if defined(WEBRTC_POSIX) 15*d9f75844SAndroid Build Coastguard Worker 16*d9f75844SAndroid Build Coastguard Worker #include <pthread.h> 17*d9f75844SAndroid Build Coastguard Worker #if defined(WEBRTC_MAC) 18*d9f75844SAndroid Build Coastguard Worker #include <pthread_spis.h> 19*d9f75844SAndroid Build Coastguard Worker #endif 20*d9f75844SAndroid Build Coastguard Worker 21*d9f75844SAndroid Build Coastguard Worker #include "absl/base/attributes.h" 22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/system/no_unique_address.h" 23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/thread_annotations.h" 24*d9f75844SAndroid Build Coastguard Worker 25*d9f75844SAndroid Build Coastguard Worker namespace webrtc { 26*d9f75844SAndroid Build Coastguard Worker 27*d9f75844SAndroid Build Coastguard Worker class RTC_LOCKABLE MutexImpl final { 28*d9f75844SAndroid Build Coastguard Worker public: MutexImpl()29*d9f75844SAndroid Build Coastguard Worker MutexImpl() { 30*d9f75844SAndroid Build Coastguard Worker pthread_mutexattr_t mutex_attribute; 31*d9f75844SAndroid Build Coastguard Worker pthread_mutexattr_init(&mutex_attribute); 32*d9f75844SAndroid Build Coastguard Worker #if defined(WEBRTC_MAC) 33*d9f75844SAndroid Build Coastguard Worker pthread_mutexattr_setpolicy_np(&mutex_attribute, 34*d9f75844SAndroid Build Coastguard Worker _PTHREAD_MUTEX_POLICY_FIRSTFIT); 35*d9f75844SAndroid Build Coastguard Worker #endif 36*d9f75844SAndroid Build Coastguard Worker pthread_mutex_init(&mutex_, &mutex_attribute); 37*d9f75844SAndroid Build Coastguard Worker pthread_mutexattr_destroy(&mutex_attribute); 38*d9f75844SAndroid Build Coastguard Worker } 39*d9f75844SAndroid Build Coastguard Worker MutexImpl(const MutexImpl&) = delete; 40*d9f75844SAndroid Build Coastguard Worker MutexImpl& operator=(const MutexImpl&) = delete; ~MutexImpl()41*d9f75844SAndroid Build Coastguard Worker ~MutexImpl() { pthread_mutex_destroy(&mutex_); } 42*d9f75844SAndroid Build Coastguard Worker Lock()43*d9f75844SAndroid Build Coastguard Worker void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() { 44*d9f75844SAndroid Build Coastguard Worker pthread_mutex_lock(&mutex_); 45*d9f75844SAndroid Build Coastguard Worker owner_.SetOwner(); 46*d9f75844SAndroid Build Coastguard Worker } TryLock()47*d9f75844SAndroid Build Coastguard Worker ABSL_MUST_USE_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) { 48*d9f75844SAndroid Build Coastguard Worker if (pthread_mutex_trylock(&mutex_) != 0) { 49*d9f75844SAndroid Build Coastguard Worker return false; 50*d9f75844SAndroid Build Coastguard Worker } 51*d9f75844SAndroid Build Coastguard Worker owner_.SetOwner(); 52*d9f75844SAndroid Build Coastguard Worker return true; 53*d9f75844SAndroid Build Coastguard Worker } AssertHeld()54*d9f75844SAndroid Build Coastguard Worker void AssertHeld() const RTC_ASSERT_EXCLUSIVE_LOCK() { owner_.AssertOwned(); } Unlock()55*d9f75844SAndroid Build Coastguard Worker void Unlock() RTC_UNLOCK_FUNCTION() { 56*d9f75844SAndroid Build Coastguard Worker owner_.ClearOwner(); 57*d9f75844SAndroid Build Coastguard Worker pthread_mutex_unlock(&mutex_); 58*d9f75844SAndroid Build Coastguard Worker } 59*d9f75844SAndroid Build Coastguard Worker 60*d9f75844SAndroid Build Coastguard Worker private: 61*d9f75844SAndroid Build Coastguard Worker class OwnerRecord { 62*d9f75844SAndroid Build Coastguard Worker public: 63*d9f75844SAndroid Build Coastguard Worker #if !RTC_DCHECK_IS_ON SetOwner()64*d9f75844SAndroid Build Coastguard Worker void SetOwner() {} ClearOwner()65*d9f75844SAndroid Build Coastguard Worker void ClearOwner() {} AssertOwned()66*d9f75844SAndroid Build Coastguard Worker void AssertOwned() const {} 67*d9f75844SAndroid Build Coastguard Worker #else 68*d9f75844SAndroid Build Coastguard Worker void SetOwner() { 69*d9f75844SAndroid Build Coastguard Worker latest_owner_ = pthread_self(); 70*d9f75844SAndroid Build Coastguard Worker is_owned_ = true; 71*d9f75844SAndroid Build Coastguard Worker } 72*d9f75844SAndroid Build Coastguard Worker void ClearOwner() { is_owned_ = false; } 73*d9f75844SAndroid Build Coastguard Worker void AssertOwned() const { 74*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(is_owned_); 75*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(pthread_equal(latest_owner_, pthread_self())); 76*d9f75844SAndroid Build Coastguard Worker } 77*d9f75844SAndroid Build Coastguard Worker 78*d9f75844SAndroid Build Coastguard Worker private: 79*d9f75844SAndroid Build Coastguard Worker // Use two separate primitive types, rather than absl::optional, since the 80*d9f75844SAndroid Build Coastguard Worker // data race described below might invalidate absl::optional invariants. 81*d9f75844SAndroid Build Coastguard Worker bool is_owned_ = false; 82*d9f75844SAndroid Build Coastguard Worker pthread_t latest_owner_ = pthread_self(); 83*d9f75844SAndroid Build Coastguard Worker #endif 84*d9f75844SAndroid Build Coastguard Worker }; 85*d9f75844SAndroid Build Coastguard Worker 86*d9f75844SAndroid Build Coastguard Worker pthread_mutex_t mutex_; 87*d9f75844SAndroid Build Coastguard Worker // This record is modified only with the mutex held, and hence, calls to 88*d9f75844SAndroid Build Coastguard Worker // AssertHeld where mutex is held are race-free and will always succeed. 89*d9f75844SAndroid Build Coastguard Worker // 90*d9f75844SAndroid Build Coastguard Worker // The failure case is more subtle: If AssertHeld is called from some thread 91*d9f75844SAndroid Build Coastguard Worker // not holding the mutex, and RTC_DCHECK_IS_ON==1, we have a data race. It is 92*d9f75844SAndroid Build Coastguard Worker // highly likely that the calling thread will see `is_owned_` false or 93*d9f75844SAndroid Build Coastguard Worker // `latest_owner_` different from itself, and crash. But it may fail to crash, 94*d9f75844SAndroid Build Coastguard Worker // and invoke some other undefined behavior (still, this race can happen only 95*d9f75844SAndroid Build Coastguard Worker // when RTC_DCHECK_IS_ON==1). 96*d9f75844SAndroid Build Coastguard Worker RTC_NO_UNIQUE_ADDRESS OwnerRecord owner_; 97*d9f75844SAndroid Build Coastguard Worker }; 98*d9f75844SAndroid Build Coastguard Worker 99*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc 100*d9f75844SAndroid Build Coastguard Worker #endif // #if defined(WEBRTC_POSIX) 101*d9f75844SAndroid Build Coastguard Worker #endif // RTC_BASE_SYNCHRONIZATION_MUTEX_PTHREAD_H_ 102