blob: 84c488ba822dfa603a01182304192310d98fdb9a [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 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 WEBRTC_BASE_CRITICALSECTION_H__
12#define WEBRTC_BASE_CRITICALSECTION_H__
13
14#include "webrtc/base/constructormagic.h"
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000015#include "webrtc/base/thread_annotations.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016
17#if defined(WEBRTC_WIN)
18#include "webrtc/base/win32.h"
19#endif
20
21#if defined(WEBRTC_POSIX)
22#include <pthread.h>
23#endif
24
tommi@webrtc.orgd3125052015-02-28 00:01:11 +000025#if defined(WEBRTC_MAC)
26// TODO(tommi): This is a temporary test to see if critical section objects are
27// somehow causing pointer co-member variables that follow a critical section
28// variable, are somehow throwing off the alignment and causing crash on
29// the Mac 10.9 debug bot:
30// http://build.chromium.org/p/chromium.mac/builders/Mac10.9%20Tests%20(dbg)
31#define _MUTEX_ALIGNMENT __attribute__((__aligned__(8)))
32#define _STATIC_ASSERT_CRITICAL_SECTION_SIZE() \
33 static_assert(sizeof(CriticalSection) % 8 == 0, \
34 "Bad size of CriticalSection")
35
36#else
37#define _MUTEX_ALIGNMENT
38#define _STATIC_ASSERT_CRITICAL_SECTION_SIZE()
39#endif
40
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000041#ifdef _DEBUG
42#define CS_TRACK_OWNER 1
43#endif // _DEBUG
44
45#if CS_TRACK_OWNER
46#define TRACK_OWNER(x) x
47#else // !CS_TRACK_OWNER
48#define TRACK_OWNER(x)
49#endif // !CS_TRACK_OWNER
50
51namespace rtc {
52
53#if defined(WEBRTC_WIN)
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000054class LOCKABLE CriticalSection {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000055 public:
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000056 CriticalSection() { InitializeCriticalSection(&crit_); }
57 ~CriticalSection() { DeleteCriticalSection(&crit_); }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000058 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059 EnterCriticalSection(&crit_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000060 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000061 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000062 return TryEnterCriticalSection(&crit_) != FALSE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000063 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000064 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000065 LeaveCriticalSection(&crit_);
66 }
67
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000068 // Used for debugging.
69 bool CurrentThreadIsOwner() const {
70 return crit_.OwningThread == reinterpret_cast<HANDLE>(GetCurrentThreadId());
71 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000072
73 private:
74 CRITICAL_SECTION crit_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000075};
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000076#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000077
78#if defined(WEBRTC_POSIX)
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000079class LOCKABLE CriticalSection {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000080 public:
81 CriticalSection() {
tommi@webrtc.orgd3125052015-02-28 00:01:11 +000082 _STATIC_ASSERT_CRITICAL_SECTION_SIZE();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083 pthread_mutexattr_t mutex_attribute;
84 pthread_mutexattr_init(&mutex_attribute);
85 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
86 pthread_mutex_init(&mutex_, &mutex_attribute);
87 pthread_mutexattr_destroy(&mutex_attribute);
88 TRACK_OWNER(thread_ = 0);
89 }
90 ~CriticalSection() {
91 pthread_mutex_destroy(&mutex_);
92 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000093 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000094 pthread_mutex_lock(&mutex_);
95 TRACK_OWNER(thread_ = pthread_self());
96 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000097 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000098 if (pthread_mutex_trylock(&mutex_) == 0) {
99 TRACK_OWNER(thread_ = pthread_self());
100 return true;
101 }
102 return false;
103 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000104 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000105 TRACK_OWNER(thread_ = 0);
106 pthread_mutex_unlock(&mutex_);
107 }
108
tommi@webrtc.org04cd4662015-01-26 15:27:29 +0000109 // Used for debugging.
110 bool CurrentThreadIsOwner() const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111#if CS_TRACK_OWNER
tommi@webrtc.org04cd4662015-01-26 15:27:29 +0000112 return pthread_equal(thread_, pthread_self());
113#else
114 return true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000115#endif // CS_TRACK_OWNER
tommi@webrtc.org04cd4662015-01-26 15:27:29 +0000116 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117
118 private:
tommi@webrtc.orgd3125052015-02-28 00:01:11 +0000119 _MUTEX_ALIGNMENT pthread_mutex_t mutex_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000120 TRACK_OWNER(pthread_t thread_);
121};
122#endif // WEBRTC_POSIX
123
124// CritScope, for serializing execution through a scope.
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000125class SCOPED_LOCKABLE CritScope {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000126 public:
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000127 explicit CritScope(CriticalSection *pcrit) EXCLUSIVE_LOCK_FUNCTION(pcrit) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000128 pcrit_ = pcrit;
129 pcrit_->Enter();
130 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000131 ~CritScope() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000132 pcrit_->Leave();
133 }
134 private:
135 CriticalSection *pcrit_;
136 DISALLOW_COPY_AND_ASSIGN(CritScope);
137};
138
139// Tries to lock a critical section on construction via
140// CriticalSection::TryEnter, and unlocks on destruction if the
141// lock was taken. Never blocks.
142//
143// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
144// subsequent code. Users *must* check locked() to determine if the
145// lock was taken. If you're not calling locked(), you're doing it wrong!
146class TryCritScope {
147 public:
148 explicit TryCritScope(CriticalSection *pcrit) {
149 pcrit_ = pcrit;
150 locked_ = pcrit_->TryEnter();
151 }
152 ~TryCritScope() {
153 if (locked_) {
154 pcrit_->Leave();
155 }
156 }
157 bool locked() const {
158 return locked_;
159 }
160 private:
161 CriticalSection *pcrit_;
162 bool locked_;
163 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
164};
165
166// TODO: Move this to atomicops.h, which can't be done easily because of
167// complex compile rules.
168class AtomicOps {
169 public:
170#if defined(WEBRTC_WIN)
171 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000172 static int Increment(volatile int* i) {
173 return ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(i));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000174 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000175 static int Decrement(volatile int* i) {
176 return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
177 }
178 static int Load(volatile const int* i) {
179 return *i;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000180 }
181#else
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000182 static int Increment(volatile int* i) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000183 return __sync_add_and_fetch(i, 1);
184 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000185 static int Decrement(volatile int* i) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000186 return __sync_sub_and_fetch(i, 1);
187 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000188 static int Load(volatile const int* i) {
189 // Adding 0 is a no-op, so const_cast is fine.
190 return __sync_add_and_fetch(const_cast<volatile int*>(i), 0);
191 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000192#endif
193};
194
195} // namespace rtc
196
197#endif // WEBRTC_BASE_CRITICALSECTION_H__