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