1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_ 6#define PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_ 7 8#include "ppapi/cpp/logging.h" 9#include "ppapi/cpp/module.h" 10#include "ppapi/utility/threading/lock.h" 11 12/// @file 13/// Defines the traits structures for thread-safety of a completion callback 14/// factory. We provide thread-safe and non-thread-safe version. The thread-safe 15/// version is always correct (if you follow the thread usage rules of the 16/// callback factory), but if you know your object will only be used on one 17/// thread, you can uses the non-thread-safe version. 18/// 19/// The traits defines three nested classes to perform reference counting, 20/// locks, and scoped locking. 21 22namespace pp { 23 24/// The thread-safe version of thread traits. Using this class as the "traits" 25/// template argument to a completion callback factory will make it "somewhat 26/// thread-friendly." It will allow you to create completion callbacks from 27/// background threads and post them to another thread to run. 28/// 29/// Care still must be taken to ensure that the completion callbacks are 30/// executed on the same thread that the factory is destroyed on to avoid a 31/// race on destruction. 32/// 33/// Implementation note: this uses a lock instead of atomic add instructions. 34/// The number of platforms we need to support right now makes atomic 35/// operations unwieldy for this case that we don't actually use that often. 36/// As a further optimization, we can add support for this later. 37class ThreadSafeThreadTraits { 38 public: 39 class RefCount { 40 public: 41 /// Default constructor. In debug mode, this checks that the object is being 42 /// created on the main thread. 43 RefCount() : ref_(0) { 44 } 45 46 /// AddRef() increments the reference counter. 47 /// 48 /// @return An int32_t with the incremented reference counter. 49 int32_t AddRef() { 50 AutoLock lock(lock_); 51 return ++ref_; 52 } 53 54 /// Release() decrements the reference counter. 55 /// 56 /// @return An int32_t with the decremeneted reference counter. 57 int32_t Release() { 58 AutoLock lock(lock_); 59 PP_DCHECK(ref_ > 0); 60 return --ref_; 61 } 62 63 private: 64 Lock lock_; 65 int32_t ref_; 66 }; 67 68 typedef pp::Lock Lock; 69 typedef pp::AutoLock AutoLock; 70}; 71 72/// The non-thread-safe version of thread traits. Using this class as the 73/// "traits" template argument to a completion callback factory will make it 74/// not thread-safe but with potential extra performance. 75class NonThreadSafeThreadTraits { 76 public: 77 /// A simple reference counter that is not thread-safe. 78 /// 79 /// <strong>Note:</strong> in Debug mode, it checks that it is either called 80 /// on the main thread, or always called on another thread. 81 class RefCount { 82 public: 83 /// Default constructor. In debug mode, this checks that the object is being 84 /// created on the main thread. 85 RefCount() : ref_(0) { 86#ifndef NDEBUG 87 is_main_thread_ = Module::Get()->core()->IsMainThread(); 88#endif 89 } 90 91 /// Destructor. 92 ~RefCount() { 93 PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); 94 } 95 96 /// AddRef() increments the reference counter. 97 /// 98 /// @return An int32_t with the incremented reference counter. 99 int32_t AddRef() { 100 PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); 101 return ++ref_; 102 } 103 104 /// Release() decrements the reference counter. 105 /// 106 /// @return An int32_t with the decremeneted reference counter. 107 int32_t Release() { 108 PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); 109 return --ref_; 110 } 111 112 private: 113 int32_t ref_; 114#ifndef NDEBUG 115 bool is_main_thread_; 116#endif 117 }; 118 119 /// A simple object that acts like a lock but does nothing. 120 /// 121 /// <strong>Note:</strong> in Debug mode, it checks that it is either 122 /// called on the main thread, or always called on another thread. It also 123 /// asserts that the caller does not recursively lock. 124 class Lock { 125 public: 126 Lock() { 127#ifndef NDEBUG 128 is_main_thread_ = Module::Get()->core()->IsMainThread(); 129 lock_held_ = false; 130#endif 131 } 132 133 ~Lock() { 134 PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); 135 } 136 137 /// Acquires the fake "lock". This does nothing except perform checks in 138 /// debug mode. 139 void Acquire() { 140#ifndef NDEBUG 141 PP_DCHECK(!lock_held_); 142 lock_held_ = true; 143#endif 144 } 145 146 /// Releases the fake "lock". This does nothing except perform checks in 147 /// debug mode. 148 void Release() { 149#ifndef NDEBUG 150 PP_DCHECK(lock_held_); 151 lock_held_ = false; 152#endif 153 } 154 155 private: 156#ifndef NDEBUG 157 bool is_main_thread_; 158 bool lock_held_; 159#endif 160 }; 161 162 class AutoLock { 163 public: 164 explicit AutoLock(Lock& lock) : lock_(lock) { 165 lock_.Acquire(); 166 } 167 ~AutoLock() { 168 lock_.Release(); 169 } 170 171 private: 172 Lock& lock_; 173 }; 174}; 175 176} // namespace pp 177 178#endif // PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_ 179