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