3 * Copyright 2004, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 #ifndef TALK_BASE_CRITICALSECTION_H__
29 #define TALK_BASE_CRITICALSECTION_H__
31 #include "talk/base/constructormagic.h"
34 #include "talk/base/win32.h"
42 #define CS_TRACK_OWNER 1
46 #define TRACK_OWNER(x) x
47 #else // !CS_TRACK_OWNER
48 #define TRACK_OWNER(x)
49 #endif // !CS_TRACK_OWNER
54 class CriticalSection {
57 InitializeCriticalSection(&crit_);
58 // Windows docs say 0 is not a valid thread id
59 TRACK_OWNER(thread_ = 0);
62 DeleteCriticalSection(&crit_);
65 EnterCriticalSection(&crit_);
66 TRACK_OWNER(thread_ = GetCurrentThreadId());
69 if (TryEnterCriticalSection(&crit_) != FALSE) {
70 TRACK_OWNER(thread_ = GetCurrentThreadId());
76 TRACK_OWNER(thread_ = 0);
77 LeaveCriticalSection(&crit_);
81 bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
82 #endif // CS_TRACK_OWNER
85 CRITICAL_SECTION crit_;
86 TRACK_OWNER(DWORD thread_); // The section's owning thread id
91 class 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);
102 pthread_mutex_destroy(&mutex_);
105 pthread_mutex_lock(&mutex_);
106 TRACK_OWNER(thread_ = pthread_self());
109 if (pthread_mutex_trylock(&mutex_) == 0) {
110 TRACK_OWNER(thread_ = pthread_self());
116 TRACK_OWNER(thread_ = 0);
117 pthread_mutex_unlock(&mutex_);
121 bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); }
122 #endif // CS_TRACK_OWNER
125 pthread_mutex_t mutex_;
126 TRACK_OWNER(pthread_t thread_);
130 // CritScope, for serializing execution through a scope.
133 explicit CritScope(CriticalSection *pcrit) {
141 CriticalSection *pcrit_;
142 DISALLOW_COPY_AND_ASSIGN(CritScope);
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.
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!
154 explicit TryCritScope(CriticalSection *pcrit) {
156 locked_ = pcrit_->TryEnter();
163 bool locked() const {
167 CriticalSection *pcrit_;
169 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
172 // TODO: Move this to atomicops.h, which can't be done easily because of
173 // complex compile rules.
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));
181 static int Decrement(int* i) {
182 return ::InterlockedDecrement(reinterpret_cast<LONG*>(i));
185 static int Increment(int* i) {
186 return __sync_add_and_fetch(i, 1);
188 static int Decrement(int* i) {
189 return __sync_sub_and_fetch(i, 1);
194 } // namespace talk_base
196 #endif // TALK_BASE_CRITICALSECTION_H__