blob: d4e6bd76eb7ed9960af07f9ace7f8f7723b85a98 [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)
tommi@webrtc.org4a4e6882015-03-04 20:09:37 +000018// Include winsock2.h before including <windows.h> to maintain consistency with
19// win32.h. We can't include win32.h directly here since it pulls in
20// headers such as basictypes.h which causes problems in Chromium where webrtc
21// exists as two separate projects, webrtc and libjingle.
22#include <winsock2.h>
23#include <windows.h>
Tommi494f2092015-04-27 17:39:23 +020024#include <sal.h> // must come after windows headers.
25#endif // defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026
27#if defined(WEBRTC_POSIX)
28#include <pthread.h>
29#endif
30
Magnus Jedvert6bf10842015-04-23 11:37:55 +020031#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
Tommi494f2092015-04-27 17:39:23 +020032#define CS_DEBUG_CHECKS 1
Magnus Jedvert6bf10842015-04-23 11:37:55 +020033#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000034
Tommi494f2092015-04-27 17:39:23 +020035#if CS_DEBUG_CHECKS
36#define CS_DEBUG_CODE(x) x
37#else // !CS_DEBUG_CHECKS
38#define CS_DEBUG_CODE(x)
39#endif // !CS_DEBUG_CHECKS
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000040
41namespace rtc {
42
Tommi494f2092015-04-27 17:39:23 +020043class LOCKABLE CriticalSection {
44 public:
45 CriticalSection();
46 ~CriticalSection();
47
48 void Enter() EXCLUSIVE_LOCK_FUNCTION();
49 bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true);
50 void Leave() UNLOCK_FUNCTION();
51
52 // Use only for DCHECKing.
53 bool CurrentThreadIsOwner() const;
54 // Use only for DCHECKing.
55 bool IsLocked() const;
56
57 private:
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000058#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059 CRITICAL_SECTION crit_;
Tommi494f2092015-04-27 17:39:23 +020060#elif defined(WEBRTC_POSIX)
tommi@webrtc.orga32f0642015-03-08 07:38:31 +000061 pthread_mutex_t mutex_;
Tommi494f2092015-04-27 17:39:23 +020062 CS_DEBUG_CODE(pthread_t thread_);
63 CS_DEBUG_CODE(int recursion_count_);
64#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000065};
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000066
67// CritScope, for serializing execution through a scope.
pbos@webrtc.orgd60d79a2014-09-24 07:10:57 +000068class SCOPED_LOCKABLE CritScope {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000069 public:
Tommi494f2092015-04-27 17:39:23 +020070 explicit CritScope(CriticalSection* cs) EXCLUSIVE_LOCK_FUNCTION(cs);
71 ~CritScope() UNLOCK_FUNCTION();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000072 private:
Tommi494f2092015-04-27 17:39:23 +020073 CriticalSection* const cs_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000074 DISALLOW_COPY_AND_ASSIGN(CritScope);
75};
76
77// Tries to lock a critical section on construction via
78// CriticalSection::TryEnter, and unlocks on destruction if the
79// lock was taken. Never blocks.
80//
81// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
82// subsequent code. Users *must* check locked() to determine if the
83// lock was taken. If you're not calling locked(), you're doing it wrong!
84class TryCritScope {
85 public:
Tommi494f2092015-04-27 17:39:23 +020086 explicit TryCritScope(CriticalSection* cs);
87 ~TryCritScope();
88#if defined(WEBRTC_WIN)
89 _Check_return_ bool locked() const;
90#else
91 bool locked() const __attribute__((warn_unused_result));
92#endif
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000093 private:
Tommi494f2092015-04-27 17:39:23 +020094 CriticalSection* const cs_;
95 const bool locked_;
96 CS_DEBUG_CODE(mutable bool lock_was_called_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000097 DISALLOW_COPY_AND_ASSIGN(TryCritScope);
98};
99
100// TODO: Move this to atomicops.h, which can't be done easily because of
101// complex compile rules.
102class AtomicOps {
103 public:
104#if defined(WEBRTC_WIN)
105 // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000106 static int Increment(volatile int* i) {
107 return ::InterlockedIncrement(reinterpret_cast<volatile LONG*>(i));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000108 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000109 static int Decrement(volatile int* i) {
110 return ::InterlockedDecrement(reinterpret_cast<volatile LONG*>(i));
111 }
112 static int Load(volatile const int* i) {
113 return *i;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000114 }
tommi@webrtc.orgc7157da2015-03-19 09:30:29 +0000115 static void Store(volatile int* i, int value) {
116 *i = value;
117 }
Jiayang Liubef8d2d2015-03-26 14:38:46 -0700118 static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
119 return ::InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(i),
120 new_value,
121 old_value);
122 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000123#else
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000124 static int Increment(volatile int* i) {
tommi@webrtc.org25819b82015-03-17 15:35:11 +0000125 return __sync_add_and_fetch(i, 1);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000126 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000127 static int Decrement(volatile int* i) {
tommi@webrtc.org25819b82015-03-17 15:35:11 +0000128 return __sync_sub_and_fetch(i, 1);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000129 }
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000130 static int Load(volatile const int* i) {
131 // Adding 0 is a no-op, so const_cast is fine.
tommi@webrtc.org25819b82015-03-17 15:35:11 +0000132 return __sync_add_and_fetch(const_cast<volatile int*>(i), 0);
magjed@webrtc.orga43fce62015-02-21 13:23:27 +0000133 }
tommi@webrtc.orgc7157da2015-03-19 09:30:29 +0000134 static void Store(volatile int* i, int value) {
135 __sync_synchronize();
136 *i = value;
137 }
Jiayang Liubef8d2d2015-03-26 14:38:46 -0700138 static int CompareAndSwap(volatile int* i, int old_value, int new_value) {
139 return __sync_val_compare_and_swap(i, old_value, new_value);
140 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000141#endif
142};
143
Jiayang Liubef8d2d2015-03-26 14:38:46 -0700144
145// A POD lock used to protect global variables. Do NOT use for other purposes.
146// No custom constructor or private data member should be added.
147class LOCKABLE GlobalLockPod {
148 public:
149 void Lock() EXCLUSIVE_LOCK_FUNCTION();
150
151 void Unlock() UNLOCK_FUNCTION();
152
153 volatile int lock_acquired;
154};
155
156class GlobalLock : public GlobalLockPod {
157 public:
158 GlobalLock();
159};
160
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000161} // namespace rtc
162
163#endif // WEBRTC_BASE_CRITICALSECTION_H__