147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2004 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifndef WEBRTC_BASE_CRITICALSECTION_H__
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define WEBRTC_BASE_CRITICALSECTION_H__
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/constructormagic.h"
1546c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org#include "webrtc/base/thread_annotations.h"
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_WIN)
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/win32.h"
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_POSIX)
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <pthread.h>
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#ifdef _DEBUG
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define CS_TRACK_OWNER 1
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif  // _DEBUG
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if CS_TRACK_OWNER
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define TRACK_OWNER(x) x
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else  // !CS_TRACK_OWNER
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#define TRACK_OWNER(x)
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif  // !CS_TRACK_OWNER
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_WIN)
3846c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.orgclass LOCKABLE CriticalSection {
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public:
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CriticalSection() {
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    InitializeCriticalSection(&crit_);
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Windows docs say 0 is not a valid thread id
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    TRACK_OWNER(thread_ = 0);
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ~CriticalSection() {
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    DeleteCriticalSection(&crit_);
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
4846c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org  void Enter() EXCLUSIVE_LOCK_FUNCTION() {
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    EnterCriticalSection(&crit_);
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    TRACK_OWNER(thread_ = GetCurrentThreadId());
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
5246c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org  bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (TryEnterCriticalSection(&crit_) != FALSE) {
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      TRACK_OWNER(thread_ = GetCurrentThreadId());
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return true;
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
5946c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org  void Leave() UNLOCK_FUNCTION() {
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    TRACK_OWNER(thread_ = 0);
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LeaveCriticalSection(&crit_);
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if CS_TRACK_OWNER
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool CurrentThreadIsOwner() const { return thread_ == GetCurrentThreadId(); }
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif  // CS_TRACK_OWNER
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private:
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CRITICAL_SECTION crit_;
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  TRACK_OWNER(DWORD thread_);  // The section's owning thread id
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif // WEBRTC_WIN
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_POSIX)
7546c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.orgclass LOCKABLE CriticalSection {
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public:
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CriticalSection() {
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pthread_mutexattr_t mutex_attribute;
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pthread_mutexattr_init(&mutex_attribute);
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pthread_mutexattr_settype(&mutex_attribute, PTHREAD_MUTEX_RECURSIVE);
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pthread_mutex_init(&mutex_, &mutex_attribute);
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pthread_mutexattr_destroy(&mutex_attribute);
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    TRACK_OWNER(thread_ = 0);
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ~CriticalSection() {
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pthread_mutex_destroy(&mutex_);
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
8846c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org  void Enter() EXCLUSIVE_LOCK_FUNCTION() {
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pthread_mutex_lock(&mutex_);
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    TRACK_OWNER(thread_ = pthread_self());
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
9246c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org  bool TryEnter() EXCLUSIVE_TRYLOCK_FUNCTION(true) {
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (pthread_mutex_trylock(&mutex_) == 0) {
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      TRACK_OWNER(thread_ = pthread_self());
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      return true;
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
9946c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org  void Leave() UNLOCK_FUNCTION() {
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    TRACK_OWNER(thread_ = 0);
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pthread_mutex_unlock(&mutex_);
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if CS_TRACK_OWNER
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool CurrentThreadIsOwner() const { return pthread_equal(thread_, pthread_self()); }
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif  // CS_TRACK_OWNER
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private:
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  pthread_mutex_t mutex_;
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  TRACK_OWNER(pthread_t thread_);
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif // WEBRTC_POSIX
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// CritScope, for serializing execution through a scope.
11546c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.orgclass SCOPED_LOCKABLE CritScope {
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public:
11746c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org  explicit CritScope(CriticalSection *pcrit) EXCLUSIVE_LOCK_FUNCTION(pcrit) {
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pcrit_ = pcrit;
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pcrit_->Enter();
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
12146c93aa23855b429a7bd3c622842539bf5937d3dpbos@webrtc.org  ~CritScope() UNLOCK_FUNCTION() {
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pcrit_->Leave();
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private:
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CriticalSection *pcrit_;
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  DISALLOW_COPY_AND_ASSIGN(CritScope);
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Tries to lock a critical section on construction via
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// CriticalSection::TryEnter, and unlocks on destruction if the
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// lock was taken. Never blocks.
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org//
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// IMPORTANT: Unlike CritScope, the lock may not be owned by this thread in
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// subsequent code. Users *must* check locked() to determine if the
13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// lock was taken. If you're not calling locked(), you're doing it wrong!
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass TryCritScope {
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public:
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  explicit TryCritScope(CriticalSection *pcrit) {
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pcrit_ = pcrit;
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    locked_ = pcrit_->TryEnter();
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ~TryCritScope() {
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (locked_) {
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      pcrit_->Leave();
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool locked() const {
14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return locked_;
14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org private:
15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CriticalSection *pcrit_;
15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool locked_;
15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  DISALLOW_COPY_AND_ASSIGN(TryCritScope);
15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// TODO: Move this to atomicops.h, which can't be done easily because of
15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// complex compile rules.
15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgclass AtomicOps {
15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org public:
16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#if defined(WEBRTC_WIN)
16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Assumes sizeof(int) == sizeof(LONG), which it is on Win32 and Win64.
16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  static int Increment(int* i) {
16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return ::InterlockedIncrement(reinterpret_cast<LONG*>(i));
16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  static int Decrement(int* i) {
16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return ::InterlockedDecrement(reinterpret_cast<LONG*>(i));
16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#else
16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  static int Increment(int* i) {
17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return __sync_add_and_fetch(i, 1);
17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  static int Decrement(int* i) {
17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return __sync_sub_and_fetch(i, 1);
17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif
17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org};
17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org} // namespace rtc
17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#endif // WEBRTC_BASE_CRITICALSECTION_H__
181