blob: a2d9bca0effd0848e67098f7fcbc78f77d2c1a8e [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
25#ifdef _DEBUG
26#define CS_TRACK_OWNER 1
27#endif // _DEBUG
28
29#if CS_TRACK_OWNER
30#define TRACK_OWNER(x) x
31#else // !CS_TRACK_OWNER
32#define TRACK_OWNER(x)
33#endif // !CS_TRACK_OWNER
34
35namespace rtc {
36
37#if defined(WEBRTC_WIN)
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000038class LOCKABLE CriticalSection {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000039 public:
40 CriticalSection() {
41 InitializeCriticalSection(&crit_);
42 // Windows docs say 0 is not a valid thread id
43 TRACK_OWNER(thread_ = 0);
44 }
45 ~CriticalSection() {
46 DeleteCriticalSection(&crit_);
47 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000048 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049 EnterCriticalSection(&crit_);
50 TRACK_OWNER(thread_ = GetCurrentThreadId());
51 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000052 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000053 if (TryEnterCriticalSection(&crit_) != FALSE) {
54 TRACK_OWNER(thread_ = GetCurrentThreadId());
55 return true;
56 }
57 return false;
58 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000059 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000060 TRACK_OWNER(thread_ = 0);
61 LeaveCriticalSection(&crit_);
62 }
63
64#if CS_TRACK_OWNER
65 bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
66#endif // CS_TRACK_OWNER
67
68 private:
69 CRITICAL_SECTION crit_;
70 TRACK_OWNER(DWORD thread_); // The section's owning thread id
71};
72#endif // WEBRTC_WIN
73
74#if defined(WEBRTC_POSIX)
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000075class LOCKABLE CriticalSection {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000076 public:
77 CriticalSection() {
78 pthread_mutexattr_t mutex_attribute;
79 pthread_mutexattr_init(&mutex_attribute);
80 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
81 pthread_mutex_init(&mutex_, &mutex_attribute);
82 pthread_mutexattr_destroy(&mutex_attribute);
83 TRACK_OWNER(thread_ = 0);
84 }
85 ~CriticalSection() {
86 pthread_mutex_destroy(&mutex_);
87 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000088 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000089 pthread_mutex_lock(&mutex_);
90 TRACK_OWNER(thread_ = pthread_self());
91 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000092 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000093 if (pthread_mutex_trylock(&mutex_) == 0) {
94 TRACK_OWNER(thread_ = pthread_self());
95 return true;
96 }
97 return false;
98 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000099 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000100 TRACK_OWNER(thread_ = 0);
101 pthread_mutex_unlock(&mutex_);
102 }
103
104#if CS_TRACK_OWNER
105 bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); }
106#endif // CS_TRACK_OWNER
107
108 private:
109 pthread_mutex_t mutex_;
110 TRACK_OWNER(pthread_t thread_);
111};
112#endif // WEBRTC_POSIX
113
114// CritScope, for serializing execution through a scope.
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000115class SCOPED_LOCKABLE CritScope {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000116 public:
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000117 explicit CritScope(CriticalSection *pcrit) EXCLUSIVE_LOCK_FUNCTION(pcrit) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000118 pcrit_ = pcrit;
119 pcrit_->Enter();
120 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000121 ~CritScope() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000122 pcrit_->Leave();
123 }
124 private:
125 CriticalSection *pcrit_;
126 DISALLOW_COPY_AND_ASSIGN(CritScope);
127};
128
129// Tries to lock a critical section on construction via
130// CriticalSection::TryEnter, and unlocks on destruction if the
131// lock was taken. Never blocks.
132//
133// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
134// subsequent code. Users *must* check locked() to determine if the
135// lock was taken. If you're not calling locked(), you're doing it wrong!
136class TryCritScope {
137 public:
138 explicit TryCritScope(CriticalSection *pcrit) {
139 pcrit_ = pcrit;
140 locked_ = pcrit_->TryEnter();
141 }
142 ~TryCritScope() {
143 if (locked_) {
144 pcrit_->Leave();
145 }
146 }
147 bool locked() const {
148 return locked_;
149 }
150 private:
151 CriticalSection *pcrit_;
152 bool locked_;
153 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
154};
155
156// TODO: Move this to atomicops.h, which can't be done easily because of
157// complex compile rules.
158class AtomicOps {
159 public:
160#if defined(WEBRTC_WIN)
161 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
162 static int Increment(int* i) {
163 return ::InterlockedIncrement(reinterpret_cast<LONG*>(i));
164 }
165 static int Decrement(int* i) {
166 return ::InterlockedDecrement(reinterpret_cast<LONG*>(i));
167 }
168#else
169 static int Increment(int* i) {
170 return __sync_add_and_fetch(i, 1);
171 }
172 static int Decrement(int* i) {
173 return __sync_sub_and_fetch(i, 1);
174 }
175#endif
176};
177
178} // namespace rtc
179
180#endif // WEBRTC_BASE_CRITICALSECTION_H__