blob: a950a47f592d1f8fef6a2a8f28c4473439e32e9f [file] [log] [blame]
henrike@webrtc.orgf7795df2014-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"
15
16#if defined(WEBRTC_WIN)
17#include "webrtc/base/win32.h"
18#endif
19
20#if defined(WEBRTC_POSIX)
21#include <pthread.h>
22#endif
23
24#ifdef _DEBUG
25#define CS_TRACK_OWNER 1
26#endif // _DEBUG
27
28#if CS_TRACK_OWNER
29#define TRACK_OWNER(x) x
30#else // !CS_TRACK_OWNER
31#define TRACK_OWNER(x)
32#endif // !CS_TRACK_OWNER
33
34namespace rtc {
35
36#if defined(WEBRTC_WIN)
37class CriticalSection {
38 public:
39 CriticalSection() {
40 InitializeCriticalSection(&crit_);
41 // Windows docs say 0 is not a valid thread id
42 TRACK_OWNER(thread_ = 0);
43 }
44 ~CriticalSection() {
45 DeleteCriticalSection(&crit_);
46 }
47 void Enter() {
48 EnterCriticalSection(&crit_);
49 TRACK_OWNER(thread_ = GetCurrentThreadId());
50 }
51 bool TryEnter() {
52 if (TryEnterCriticalSection(&crit_) != FALSE) {
53 TRACK_OWNER(thread_ = GetCurrentThreadId());
54 return true;
55 }
56 return false;
57 }
58 void Leave() {
59 TRACK_OWNER(thread_ = 0);
60 LeaveCriticalSection(&crit_);
61 }
62
63#if CS_TRACK_OWNER
64 bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
65#endif // CS_TRACK_OWNER
66
67 private:
68 CRITICAL_SECTION crit_;
69 TRACK_OWNER(DWORD thread_); // The section's owning thread id
70};
71#endif // WEBRTC_WIN
72
73#if defined(WEBRTC_POSIX)
74class CriticalSection {
75 public:
76 CriticalSection() {
77 pthread_mutexattr_t mutex_attribute;
78 pthread_mutexattr_init(&mutex_attribute);
79 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
80 pthread_mutex_init(&mutex_, &mutex_attribute);
81 pthread_mutexattr_destroy(&mutex_attribute);
82 TRACK_OWNER(thread_ = 0);
83 }
84 ~CriticalSection() {
85 pthread_mutex_destroy(&mutex_);
86 }
87 void Enter() {
88 pthread_mutex_lock(&mutex_);
89 TRACK_OWNER(thread_ = pthread_self());
90 }
91 bool TryEnter() {
92 if (pthread_mutex_trylock(&mutex_) == 0) {
93 TRACK_OWNER(thread_ = pthread_self());
94 return true;
95 }
96 return false;
97 }
98 void Leave() {
99 TRACK_OWNER(thread_ = 0);
100 pthread_mutex_unlock(&mutex_);
101 }
102
103#if CS_TRACK_OWNER
104 bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); }
105#endif // CS_TRACK_OWNER
106
107 private:
108 pthread_mutex_t mutex_;
109 TRACK_OWNER(pthread_t thread_);
110};
111#endif // WEBRTC_POSIX
112
113// CritScope, for serializing execution through a scope.
114class CritScope {
115 public:
116 explicit CritScope(CriticalSection *pcrit) {
117 pcrit_ = pcrit;
118 pcrit_->Enter();
119 }
120 ~CritScope() {
121 pcrit_->Leave();
122 }
123 private:
124 CriticalSection *pcrit_;
125 DISALLOW_COPY_AND_ASSIGN(CritScope);
126};
127
128// Tries to lock a critical section on construction via
129// CriticalSection::TryEnter, and unlocks on destruction if the
130// lock was taken. Never blocks.
131//
132// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
133// subsequent code. Users *must* check locked() to determine if the
134// lock was taken. If you're not calling locked(), you're doing it wrong!
135class TryCritScope {
136 public:
137 explicit TryCritScope(CriticalSection *pcrit) {
138 pcrit_ = pcrit;
139 locked_ = pcrit_->TryEnter();
140 }
141 ~TryCritScope() {
142 if (locked_) {
143 pcrit_->Leave();
144 }
145 }
146 bool locked() const {
147 return locked_;
148 }
149 private:
150 CriticalSection *pcrit_;
151 bool locked_;
152 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
153};
154
155// TODO: Move this to atomicops.h, which can't be done easily because of
156// complex compile rules.
157class AtomicOps {
158 public:
159#if defined(WEBRTC_WIN)
160 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
161 static int Increment(int* i) {
162 return ::InterlockedIncrement(reinterpret_cast<LONG*>(i));
163 }
164 static int Decrement(int* i) {
165 return ::InterlockedDecrement(reinterpret_cast<LONG*>(i));
166 }
167#else
168 static int Increment(int* i) {
169 return __sync_add_and_fetch(i, 1);
170 }
171 static int Decrement(int* i) {
172 return __sync_sub_and_fetch(i, 1);
173 }
174#endif
175};
176
177} // namespace rtc
178
179#endif // WEBRTC_BASE_CRITICALSECTION_H__