blob: 0fa91bb99c09aa45ae2fd102c69288e62d837e8b [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:
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000040 CriticalSection() { InitializeCriticalSection(&crit_); }
41 ~CriticalSection() { DeleteCriticalSection(&crit_); }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000042 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000043 EnterCriticalSection(&crit_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000044 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000045 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000046 return TryEnterCriticalSection(&crit_) != FALSE;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000047 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000048 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049 LeaveCriticalSection(&crit_);
50 }
51
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000052 // Used for debugging.
53 bool CurrentThreadIsOwner() const {
54 return crit_.OwningThread == reinterpret_cast<HANDLE>(GetCurrentThreadId());
55 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000056
57 private:
58 CRITICAL_SECTION crit_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059};
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000060#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000061
62#if defined(WEBRTC_POSIX)
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000063class LOCKABLE CriticalSection {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000064 public:
65 CriticalSection() {
66 pthread_mutexattr_t mutex_attribute;
67 pthread_mutexattr_init(&mutex_attribute);
68 pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
69 pthread_mutex_init(&mutex_, &mutex_attribute);
70 pthread_mutexattr_destroy(&mutex_attribute);
71 TRACK_OWNER(thread_ = 0);
72 }
73 ~CriticalSection() {
74 pthread_mutex_destroy(&mutex_);
75 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000076 void Enter() EXCLUSIVE_LOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000077 pthread_mutex_lock(&mutex_);
78 TRACK_OWNER(thread_ = pthread_self());
79 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000080 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000081 if (pthread_mutex_trylock(&mutex_) == 0) {
82 TRACK_OWNER(thread_ = pthread_self());
83 return true;
84 }
85 return false;
86 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000087 void Leave() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000088 TRACK_OWNER(thread_ = 0);
89 pthread_mutex_unlock(&mutex_);
90 }
91
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000092 // Used for debugging.
93 bool CurrentThreadIsOwner() const {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000094#if CS_TRACK_OWNER
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000095 return pthread_equal(thread_, pthread_self());
96#else
97 return true;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000098#endif // CS_TRACK_OWNER
tommi@webrtc.org04cd4662015-01-26 15:27:29 +000099 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000100
101 private:
102 pthread_mutex_t mutex_;
103 TRACK_OWNER(pthread_t thread_);
104};
105#endif // WEBRTC_POSIX
106
107// CritScope, for serializing execution through a scope.
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000108class SCOPED_LOCKABLE CritScope {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000109 public:
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000110 explicit CritScope(CriticalSection *pcrit) EXCLUSIVE_LOCK_FUNCTION(pcrit) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000111 pcrit_ = pcrit;
112 pcrit_->Enter();
113 }
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +0000114 ~CritScope() UNLOCK_FUNCTION() {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000115 pcrit_->Leave();
116 }
117 private:
118 CriticalSection *pcrit_;
119 DISALLOW_COPY_AND_ASSIGN(CritScope);
120};
121
122// Tries to lock a critical section on construction via
123// CriticalSection::TryEnter, and unlocks on destruction if the
124// lock was taken. Never blocks.
125//
126// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
127// subsequent code. Users *must* check locked() to determine if the
128// lock was taken. If you're not calling locked(), you're doing it wrong!
129class TryCritScope {
130 public:
131 explicit TryCritScope(CriticalSection *pcrit) {
132 pcrit_ = pcrit;
133 locked_ = pcrit_->TryEnter();
134 }
135 ~TryCritScope() {
136 if (locked_) {
137 pcrit_->Leave();
138 }
139 }
140 bool locked() const {
141 return locked_;
142 }
143 private:
144 CriticalSection *pcrit_;
145 bool locked_;
146 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
147};
148
149// TODO: Move this to atomicops.h, which can't be done easily because of
150// complex compile rules.
151class AtomicOps {
152 public:
153#if defined(WEBRTC_WIN)
154 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000155 static int Increment(volatile int* i) {
156 return ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(i));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000157 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000158 static int Decrement(volatile int* i) {
159 return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
160 }
161 static int Load(volatile const int* i) {
162 return *i;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000163 }
164#else
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000165 static int Increment(volatile int* i) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000166 return __sync_add_and_fetch(i, 1);
167 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000168 static int Decrement(volatile int* i) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000169 return __sync_sub_and_fetch(i, 1);
170 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000171 static int Load(volatile const int* i) {
172 // Adding 0 is a no-op, so const_cast is fine.
173 return __sync_add_and_fetch(const_cast<volatile int*>(i), 0);
174 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000175#endif
176};
177
178} // namespace rtc
179
180#endif // WEBRTC_BASE_CRITICALSECTION_H__