blob: c6ffbc0d93f1b46dbc8661ecf9844cd0b9b1b76d [file] [log] [blame]
henrike@webrtc.org0e118e72013-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"
32
33#ifdef WIN32
34#include "talk/base/win32.h"
35#endif
36
37#ifdef POSIX
38#include <pthread.h>
39#endif
40
41#ifdef _DEBUG
42#define CS_TRACK_OWNER 1
43#endif // _DEBUG
44
45#if CS_TRACK_OWNER
46#define TRACK_OWNER(x) x
47#else // !CS_TRACK_OWNER
48#define TRACK_OWNER(x)
49#endif // !CS_TRACK_OWNER
50
51namespace talk_base {
52
53#ifdef WIN32
wjia@webrtc.orgee78a382014-02-10 23:20:15 +000054class CriticalSection {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000055 public:
56 CriticalSection() {
57 InitializeCriticalSection(&crit_);
58 // Windows docs say 0 is not a valid thread id
59 TRACK_OWNER(thread_ = 0);
60 }
61 ~CriticalSection() {
62 DeleteCriticalSection(&crit_);
63 }
wjia@webrtc.orgee78a382014-02-10 23:20:15 +000064 void Enter() {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000065 EnterCriticalSection(&crit_);
66 TRACK_OWNER(thread_ = GetCurrentThreadId());
67 }
wjia@webrtc.orgee78a382014-02-10 23:20:15 +000068 bool TryEnter() {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000069 if (TryEnterCriticalSection(&crit_) != FALSE) {
70 TRACK_OWNER(thread_ = GetCurrentThreadId());
71 return true;
72 }
73 return false;
74 }
wjia@webrtc.orgee78a382014-02-10 23:20:15 +000075 void Leave() {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000076 TRACK_OWNER(thread_ = 0);
77 LeaveCriticalSection(&crit_);
78 }
79
80#if CS_TRACK_OWNER
81 bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
82#endif // CS_TRACK_OWNER
83
84 private:
85 CRITICAL_SECTION crit_;
86 TRACK_OWNER(DWORD thread_); // The section's owning thread id
87};
88#endif // WIN32
89
90#ifdef POSIX
wjia@webrtc.orgee78a382014-02-10 23:20:15 +000091class CriticalSection {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000092 public:
93 CriticalSection() {
94 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 }
wjia@webrtc.orgee78a382014-02-10 23:20:15 +0000104 void Enter() {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000105 pthread_mutex_lock(&mutex_);
106 TRACK_OWNER(thread_ = pthread_self());
107 }
wjia@webrtc.orgee78a382014-02-10 23:20:15 +0000108 bool TryEnter() {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000109 if (pthread_mutex_trylock(&mutex_) == 0) {
110 TRACK_OWNER(thread_ = pthread_self());
111 return true;
112 }
113 return false;
114 }
wjia@webrtc.orgee78a382014-02-10 23:20:15 +0000115 void Leave() {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000116 TRACK_OWNER(thread_ = 0);
117 pthread_mutex_unlock(&mutex_);
118 }
119
120#if CS_TRACK_OWNER
121 bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); }
122#endif // CS_TRACK_OWNER
123
124 private:
125 pthread_mutex_t mutex_;
126 TRACK_OWNER(pthread_t thread_);
127};
128#endif // POSIX
129
130// CritScope, for serializing execution through a scope.
wjia@webrtc.orgee78a382014-02-10 23:20:15 +0000131class CritScope {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000132 public:
wjia@webrtc.orgee78a382014-02-10 23:20:15 +0000133 explicit CritScope(CriticalSection *pcrit) {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000134 pcrit_ = pcrit;
135 pcrit_->Enter();
136 }
wjia@webrtc.orgee78a382014-02-10 23:20:15 +0000137 ~CritScope() {
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000138 pcrit_->Leave();
139 }
140 private:
141 CriticalSection *pcrit_;
142 DISALLOW_COPY_AND_ASSIGN(CritScope);
143};
144
145// Tries to lock a critical section on construction via
146// CriticalSection::TryEnter, and unlocks on destruction if the
147// lock was taken. Never blocks.
148//
149// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
150// subsequent code. Users *must* check locked() to determine if the
151// lock was taken. If you're not calling locked(), you're doing it wrong!
152class TryCritScope {
153 public:
154 explicit TryCritScope(CriticalSection *pcrit) {
155 pcrit_ = pcrit;
156 locked_ = pcrit_->TryEnter();
157 }
158 ~TryCritScope() {
159 if (locked_) {
160 pcrit_->Leave();
161 }
162 }
163 bool locked() const {
164 return locked_;
165 }
166 private:
167 CriticalSection *pcrit_;
168 bool locked_;
169 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
170};
171
172// TODO: Move this to atomicops.h, which can't be done easily because of
173// complex compile rules.
174class AtomicOps {
175 public:
176#ifdef WIN32
177 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
178 static int Increment(int* i) {
179 return ::InterlockedIncrement(reinterpret_cast<LONG*>(i));
180 }
181 static int Decrement(int* i) {
182 return ::InterlockedDecrement(reinterpret_cast<LONG*>(i));
183 }
184#else
185 static int Increment(int* i) {
186 return __sync_add_and_fetch(i, 1);
187 }
188 static int Decrement(int* i) {
189 return __sync_sub_and_fetch(i, 1);
190 }
191#endif
192};
193
194} // namespace talk_base
195
196#endif // TALK_BASE_CRITICALSECTION_H__