15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_ 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_ 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/logging.h" 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/cpp/module.h" 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ppapi/utility/threading/lock.h" 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// @file 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// Defines the traits structures for thread-safety of a completion callback 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// factory. We provide thread-safe and non-thread-safe version. The thread-safe 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// version is always correct (if you follow the thread usage rules of the 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// callback factory), but if you know your object will only be used on one 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// thread, you can uses the non-thread-safe version. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// The traits defines three nested classes to perform reference counting, 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// locks, and scoped locking. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace pp { 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// The thread-safe version of thread traits. Using this class as the "traits" 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// template argument to a completion callback factory will make it "somewhat 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// thread-friendly." It will allow you to create completion callbacks from 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// background threads and post them to another thread to run. 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// Care still must be taken to ensure that the completion callbacks are 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// executed on the same thread that the factory is destroyed on to avoid a 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// race on destruction. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// Implementation note: this uses a lock instead of atomic add instructions. 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// The number of platforms we need to support right now makes atomic 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// operations unwieldy for this case that we don't actually use that often. 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// As a further optimization, we can add support for this later. 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ThreadSafeThreadTraits { 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class RefCount { 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// Default constructor. In debug mode, this checks that the object is being 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// created on the main thread. 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RefCount() : ref_(0) { 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// AddRef() increments the reference counter. 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// @return An int32_t with the incremented reference counter. 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32_t AddRef() { 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(lock_); 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ++ref_; 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// Release() decrements the reference counter. 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// @return An int32_t with the decremeneted reference counter. 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32_t Release() { 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AutoLock lock(lock_); 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(ref_ > 0); 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return --ref_; 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Lock lock_; 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32_t ref_; 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef pp::Lock Lock; 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) typedef pp::AutoLock AutoLock; 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// The non-thread-safe version of thread traits. Using this class as the 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// "traits" template argument to a completion callback factory will make it 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/// not thread-safe but with potential extra performance. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NonThreadSafeThreadTraits { 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// A simple reference counter that is not thread-safe. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// <strong>Note:</strong> in Debug mode, it checks that it is either called 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// on the main thread, or always called on another thread. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class RefCount { 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// Default constructor. In debug mode, this checks that the object is being 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// created on the main thread. 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) RefCount() : ref_(0) { 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_main_thread_ = Module::Get()->core()->IsMainThread(); 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// Destructor. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~RefCount() { 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// AddRef() increments the reference counter. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// @return An int32_t with the incremented reference counter. 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32_t AddRef() { 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return ++ref_; 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// Release() decrements the reference counter. 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// @return An int32_t with the decremeneted reference counter. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32_t Release() { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return --ref_; 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int32_t ref_; 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_main_thread_; 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// A simple object that acts like a lock but does nothing. 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// <strong>Note:</strong> in Debug mode, it checks that it is either 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// called on the main thread, or always called on another thread. It also 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// asserts that the caller does not recursively lock. 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class Lock { 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Lock() { 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_main_thread_ = Module::Get()->core()->IsMainThread(); 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lock_held_ = false; 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~Lock() { 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(is_main_thread_ == Module::Get()->core()->IsMainThread()); 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// Acquires the fake "lock". This does nothing except perform checks in 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// debug mode. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Acquire() { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(!lock_held_); 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lock_held_ = true; 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// Releases the fake "lock". This does nothing except perform checks in 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) /// debug mode. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) void Release() { 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) PP_DCHECK(lock_held_); 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lock_held_ = false; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NDEBUG 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_main_thread_; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool lock_held_; 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class AutoLock { 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) explicit AutoLock(Lock& lock) : lock_(lock) { 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lock_.Acquire(); 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ~AutoLock() { 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lock_.Release(); 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Lock& lock_; 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace pp 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // PPAPI_UTILITY_THREAD_SAFE_THREAD_TRAITS_H_ 179