blob: c78e818f93a9aebec7adb387fa7324d9f4881eae [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)
tommi@webrtc.org4a4e6882015-03-04 20:09:37 +000018// Include winsock2.h before including <windows.h> to maintain consistency with
19// win32.h. We can't include win32.h directly here since it pulls in
20// headers such as basictypes.h which causes problems in Chromium where webrtc
21// exists as two separate projects, webrtc and libjingle.
22#include <winsock2.h>
23#include <windows.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000024#endif
25
26#if defined(WEBRTC_POSIX)
27#include <pthread.h>
28#endif
29
tommi@webrtc.orgd3125052015-02-28 00:01:11 +000030#if defined(WEBRTC_MAC)
31// TODO(tommi): This is a temporary test to see if critical section objects are
32// somehow causing pointer co-member variables that follow a critical section
33// variable, are somehow throwing off the alignment and causing crash on
34// the Mac 10.9 debug bot:
35// http://build.chromium.org/p/chromium.mac/builders/Mac10.9%20Tests%20(dbg)
36#define _MUTEX_ALIGNMENT __attribute__((__aligned__(8)))
37#define _STATIC_ASSERT_CRITICAL_SECTION_SIZE() \
38 static_assert(sizeof(CriticalSection) % 8 == 0, \
39 "Bad size of CriticalSection")
40
41#else
42#define _MUTEX_ALIGNMENT
43#define _STATIC_ASSERT_CRITICAL_SECTION_SIZE()
44#endif
45
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000046#ifdef _DEBUG
tommi@webrtc.org679d2f12015-03-07 20:14:50 +000047#if defined(WEBRTC_MAC)
48// TODO(tommi): This is related to the comment above. It looks like the
49// pthread_t member might be throwing off the mac debug bots (10.9).
50#define CS_TRACK_OWNER 0
51#else
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000052#define CS_TRACK_OWNER 1
tommi@webrtc.org679d2f12015-03-07 20:14:50 +000053#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000054#endif // _DEBUG
55
56#if CS_TRACK_OWNER
57#define TRACK_OWNER(x) x
58#else // !CS_TRACK_OWNER
59#define TRACK_OWNER(x)
60#endif // !CS_TRACK_OWNER
61
62namespace rtc {
63
64#if defined(WEBRTC_WIN)
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000065class LOCKABLE CriticalSection {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000066 public:
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000067 CriticalSection() { InitializeCriticalSection(&crit_); }
68 ~CriticalSection() { DeleteCriticalSection(&crit_); }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000069 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000070 EnterCriticalSection(&crit_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000071 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000072 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000073 return TryEnterCriticalSection(&crit_) != FALSE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000074 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000075 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000076 LeaveCriticalSection(&crit_);
77 }
78
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000079 // Used for debugging.
80 bool CurrentThreadIsOwner() const {
81 return crit_.OwningThread == reinterpret_cast<HANDLE>(GetCurrentThreadId());
82 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083
84 private:
85 CRITICAL_SECTION crit_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000086};
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000087#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088
89#if defined(WEBRTC_POSIX)
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000090class LOCKABLE CriticalSection {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091 public:
92 CriticalSection() {
tommi@webrtc.orgd3125052015-02-28 00:01:11 +000093 _STATIC_ASSERT_CRITICAL_SECTION_SIZE();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000094 pthread_mutexattr_t mutex_attribute;
95 pthread_mutexattr_init(&mutex_attribute);
96 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
97 pthread_mutex_init(&mutex_, &mutex_attribute);
98 pthread_mutexattr_destroy(&mutex_attribute);
99 TRACK_OWNER(thread_ = 0);
100 }
101 ~CriticalSection() {
102 pthread_mutex_destroy(&mutex_);
103 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000104 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000105 pthread_mutex_lock(&mutex_);
106 TRACK_OWNER(thread_ = pthread_self());
107 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000108 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000109 if (pthread_mutex_trylock(&mutex_) == 0) {
110 TRACK_OWNER(thread_ = pthread_self());
111 return true;
112 }
113 return false;
114 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000115 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000116 TRACK_OWNER(thread_ = 0);
117 pthread_mutex_unlock(&mutex_);
118 }
119
tommi@webrtc.org04cd4662015-01-26 15:27:29 +0000120 // Used for debugging.
121 bool CurrentThreadIsOwner() const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000122#if CS_TRACK_OWNER
tommi@webrtc.org04cd4662015-01-26 15:27:29 +0000123 return pthread_equal(thread_, pthread_self());
124#else
125 return true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000126#endif // CS_TRACK_OWNER
tommi@webrtc.org04cd4662015-01-26 15:27:29 +0000127 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000128
129 private:
tommi@webrtc.orgd3125052015-02-28 00:01:11 +0000130 _MUTEX_ALIGNMENT pthread_mutex_t mutex_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000131 TRACK_OWNER(pthread_t thread_);
132};
133#endif // WEBRTC_POSIX
134
135// CritScope, for serializing execution through a scope.
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000136class SCOPED_LOCKABLE CritScope {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000137 public:
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000138 explicit CritScope(CriticalSection *pcrit) EXCLUSIVE_LOCK_FUNCTION(pcrit) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000139 pcrit_ = pcrit;
140 pcrit_->Enter();
141 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000142 ~CritScope() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000143 pcrit_->Leave();
144 }
145 private:
146 CriticalSection *pcrit_;
147 DISALLOW_COPY_AND_ASSIGN(CritScope);
148};
149
150// Tries to lock a critical section on construction via
151// CriticalSection::TryEnter, and unlocks on destruction if the
152// lock was taken. Never blocks.
153//
154// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
155// subsequent code. Users *must* check locked() to determine if the
156// lock was taken. If you're not calling locked(), you're doing it wrong!
157class TryCritScope {
158 public:
159 explicit TryCritScope(CriticalSection *pcrit) {
160 pcrit_ = pcrit;
161 locked_ = pcrit_->TryEnter();
162 }
163 ~TryCritScope() {
164 if (locked_) {
165 pcrit_->Leave();
166 }
167 }
168 bool locked() const {
169 return locked_;
170 }
171 private:
172 CriticalSection *pcrit_;
173 bool locked_;
174 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
175};
176
177// TODO: Move this to atomicops.h, which can't be done easily because of
178// complex compile rules.
179class AtomicOps {
180 public:
181#if defined(WEBRTC_WIN)
182 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000183 static int Increment(volatile int* i) {
184 return ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(i));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000185 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000186 static int Decrement(volatile int* i) {
187 return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
188 }
189 static int Load(volatile const int* i) {
190 return *i;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000191 }
192#else
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000193 static int Increment(volatile int* i) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000194 return __sync_add_and_fetch(i, 1);
195 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000196 static int Decrement(volatile int* i) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000197 return __sync_sub_and_fetch(i, 1);
198 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000199 static int Load(volatile const int* i) {
200 // Adding 0 is a no-op, so const_cast is fine.
201 return __sync_add_and_fetch(const_cast<volatile int*>(i), 0);
202 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000203#endif
204};
205
206} // namespace rtc
207
208#endif // WEBRTC_BASE_CRITICALSECTION_H__