blob: 92745ce77b6418abdcae1a5720515eb4fedc6122 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef TALK_BASE_CRITICALSECTION_H__
29#define TALK_BASE_CRITICALSECTION_H__
30
31#include "talk/base/constructormagic.h"
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +000032#include "webrtc/system_wrappers/interface/thread_annotations.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000033
34#ifdef WIN32
35#include "talk/base/win32.h"
36#endif
37
38#ifdef POSIX
39#include <pthread.h>
40#endif
41
42#ifdef _DEBUG
43#define CS_TRACK_OWNER 1
44#endif // _DEBUG
45
46#if CS_TRACK_OWNER
47#define TRACK_OWNER(x) x
48#else // !CS_TRACK_OWNER
49#define TRACK_OWNER(x)
50#endif // !CS_TRACK_OWNER
51
52namespace talk_base {
53
54#ifdef WIN32
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +000055class LOCKABLE CriticalSection {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000056 public:
57 CriticalSection() {
58 InitializeCriticalSection(&crit_);
59 // Windows docs say 0 is not a valid thread id
60 TRACK_OWNER(thread_ = 0);
61 }
62 ~CriticalSection() {
63 DeleteCriticalSection(&crit_);
64 }
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +000065 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000066 EnterCriticalSection(&crit_);
67 TRACK_OWNER(thread_ = GetCurrentThreadId());
68 }
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +000069 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000070 if (TryEnterCriticalSection(&crit_) != FALSE) {
71 TRACK_OWNER(thread_ = GetCurrentThreadId());
72 return true;
73 }
74 return false;
75 }
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +000076 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000077 TRACK_OWNER(thread_ = 0);
78 LeaveCriticalSection(&crit_);
79 }
80
81#if CS_TRACK_OWNER
82 bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
83#endif // CS_TRACK_OWNER
84
85 private:
86 CRITICAL_SECTION crit_;
87 TRACK_OWNER(DWORD thread_); // The section's owning thread id
88};
89#endif // WIN32
90
91#ifdef POSIX
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +000092class LOCKABLE CriticalSection {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000093 public:
94 CriticalSection() {
95 pthread_mutexattr_t mutex_attribute;
96 pthread_mutexattr_init(&mutex_attribute);
97 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
98 pthread_mutex_init(&mutex_, &mutex_attribute);
99 pthread_mutexattr_destroy(&mutex_attribute);
100 TRACK_OWNER(thread_ = 0);
101 }
102 ~CriticalSection() {
103 pthread_mutex_destroy(&mutex_);
104 }
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +0000105 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000106 pthread_mutex_lock(&mutex_);
107 TRACK_OWNER(thread_ = pthread_self());
108 }
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +0000109 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000110 if (pthread_mutex_trylock(&mutex_) == 0) {
111 TRACK_OWNER(thread_ = pthread_self());
112 return true;
113 }
114 return false;
115 }
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +0000116 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117 TRACK_OWNER(thread_ = 0);
118 pthread_mutex_unlock(&mutex_);
119 }
120
121#if CS_TRACK_OWNER
122 bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); }
123#endif // CS_TRACK_OWNER
124
125 private:
126 pthread_mutex_t mutex_;
127 TRACK_OWNER(pthread_t thread_);
128};
129#endif // POSIX
130
131// CritScope, for serializing execution through a scope.
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +0000132class SCOPED_LOCKABLE CritScope {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000133 public:
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +0000134 explicit CritScope(CriticalSection *pcrit) EXCLUSIVE_LOCK_FUNCTION(pcrit) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000135 pcrit_ = pcrit;
136 pcrit_->Enter();
137 }
pbos@webrtc.org0a7085f2014-02-10 13:58:37 +0000138 ~CritScope() UNLOCK_FUNCTION() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000139 pcrit_->Leave();
140 }
141 private:
142 CriticalSection *pcrit_;
143 DISALLOW_COPY_AND_ASSIGN(CritScope);
144};
145
146// Tries to lock a critical section on construction via
147// CriticalSection::TryEnter, and unlocks on destruction if the
148// lock was taken. Never blocks.
149//
150// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
151// subsequent code. Users *must* check locked() to determine if the
152// lock was taken. If you're not calling locked(), you're doing it wrong!
153class TryCritScope {
154 public:
155 explicit TryCritScope(CriticalSection *pcrit) {
156 pcrit_ = pcrit;
157 locked_ = pcrit_->TryEnter();
158 }
159 ~TryCritScope() {
160 if (locked_) {
161 pcrit_->Leave();
162 }
163 }
164 bool locked() const {
165 return locked_;
166 }
167 private:
168 CriticalSection *pcrit_;
169 bool locked_;
170 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
171};
172
173// TODO: Move this to atomicops.h, which can't be done easily because of
174// complex compile rules.
175class AtomicOps {
176 public:
177#ifdef WIN32
178 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
179 static int Increment(int* i) {
180 return ::InterlockedIncrement(reinterpret_cast<LONG*>(i));
181 }
182 static int Decrement(int* i) {
183 return ::InterlockedDecrement(reinterpret_cast<LONG*>(i));
184 }
185#else
186 static int Increment(int* i) {
187 return __sync_add_and_fetch(i, 1);
188 }
189 static int Decrement(int* i) {
190 return __sync_sub_and_fetch(i, 1);
191 }
192#endif
193};
194
195} // namespace talk_base
196
197#endif // TALK_BASE_CRITICALSECTION_H__