blob: 3a1f6a4ec7d2a094d746fa6c08c5f26136f990c7 [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
47#define CS_TRACK_OWNER 1
48#endif // _DEBUG
49
50#if CS_TRACK_OWNER
51#define TRACK_OWNER(x) x
52#else // !CS_TRACK_OWNER
53#define TRACK_OWNER(x)
54#endif // !CS_TRACK_OWNER
55
56namespace rtc {
57
58#if defined(WEBRTC_WIN)
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000059class LOCKABLE CriticalSection {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000060 public:
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000061 CriticalSection() { InitializeCriticalSection(&crit_); }
62 ~CriticalSection() { DeleteCriticalSection(&crit_); }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000063 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000064 EnterCriticalSection(&crit_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000065 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000066 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000067 return TryEnterCriticalSection(&crit_) != FALSE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000068 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000069 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000070 LeaveCriticalSection(&crit_);
71 }
72
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000073 // Used for debugging.
74 bool CurrentThreadIsOwner() const {
75 return crit_.OwningThread == reinterpret_cast<HANDLE>(GetCurrentThreadId());
76 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000077
78 private:
79 CRITICAL_SECTION crit_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000080};
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000081#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000082
83#if defined(WEBRTC_POSIX)
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000084class LOCKABLE CriticalSection {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000085 public:
86 CriticalSection() {
tommi@webrtc.orgd3125052015-02-28 00:01:11 +000087 _STATIC_ASSERT_CRITICAL_SECTION_SIZE();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088 pthread_mutexattr_t mutex_attribute;
89 pthread_mutexattr_init(&mutex_attribute);
90 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
91 pthread_mutex_init(&mutex_, &mutex_attribute);
92 pthread_mutexattr_destroy(&mutex_attribute);
93 TRACK_OWNER(thread_ = 0);
94 }
95 ~CriticalSection() {
96 pthread_mutex_destroy(&mutex_);
97 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000098 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099 pthread_mutex_lock(&mutex_);
100 TRACK_OWNER(thread_ = pthread_self());
101 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000102 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000103 if (pthread_mutex_trylock(&mutex_) == 0) {
104 TRACK_OWNER(thread_ = pthread_self());
105 return true;
106 }
107 return false;
108 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000109 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000110 TRACK_OWNER(thread_ = 0);
111 pthread_mutex_unlock(&mutex_);
112 }
113
tommi@webrtc.org04cd4662015-01-26 15:27:29 +0000114 // Used for debugging.
115 bool CurrentThreadIsOwner() const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000116#if CS_TRACK_OWNER
tommi@webrtc.org04cd4662015-01-26 15:27:29 +0000117 return pthread_equal(thread_, pthread_self());
118#else
119 return true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000120#endif // CS_TRACK_OWNER
tommi@webrtc.org04cd4662015-01-26 15:27:29 +0000121 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000122
123 private:
tommi@webrtc.orgd3125052015-02-28 00:01:11 +0000124 _MUTEX_ALIGNMENT pthread_mutex_t mutex_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000125 TRACK_OWNER(pthread_t thread_);
126};
127#endif // WEBRTC_POSIX
128
129// CritScope, for serializing execution through a scope.
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000130class SCOPED_LOCKABLE CritScope {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000131 public:
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000132 explicit CritScope(CriticalSection *pcrit) EXCLUSIVE_LOCK_FUNCTION(pcrit) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000133 pcrit_ = pcrit;
134 pcrit_->Enter();
135 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000136 ~CritScope() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000137 pcrit_->Leave();
138 }
139 private:
140 CriticalSection *pcrit_;
141 DISALLOW_COPY_AND_ASSIGN(CritScope);
142};
143
144// Tries to lock a critical section on construction via
145// CriticalSection::TryEnter, and unlocks on destruction if the
146// lock was taken. Never blocks.
147//
148// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
149// subsequent code. Users *must* check locked() to determine if the
150// lock was taken. If you're not calling locked(), you're doing it wrong!
151class TryCritScope {
152 public:
153 explicit TryCritScope(CriticalSection *pcrit) {
154 pcrit_ = pcrit;
155 locked_ = pcrit_->TryEnter();
156 }
157 ~TryCritScope() {
158 if (locked_) {
159 pcrit_->Leave();
160 }
161 }
162 bool locked() const {
163 return locked_;
164 }
165 private:
166 CriticalSection *pcrit_;
167 bool locked_;
168 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
169};
170
171// TODO: Move this to atomicops.h, which can't be done easily because of
172// complex compile rules.
173class AtomicOps {
174 public:
175#if defined(WEBRTC_WIN)
176 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000177 static int Increment(volatile int* i) {
178 return ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(i));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000179 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000180 static int Decrement(volatile int* i) {
181 return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
182 }
183 static int Load(volatile const int* i) {
184 return *i;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000185 }
186#else
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000187 static int Increment(volatile int* i) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000188 return __sync_add_and_fetch(i, 1);
189 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000190 static int Decrement(volatile int* i) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000191 return __sync_sub_and_fetch(i, 1);
192 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000193 static int Load(volatile const int* i) {
194 // Adding 0 is a no-op, so const_cast is fine.
195 return __sync_add_and_fetch(const_cast<volatile int*>(i), 0);
196 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000197#endif
198};
199
200} // namespace rtc
201
202#endif // WEBRTC_BASE_CRITICALSECTION_H__