 Chromium Code Reviews
 Chromium Code Reviews Issue 1549143002:
  Add thread affinity and ASSERT() for same-thread restriction to WTF::Function  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@TRV_ThreadSafeBindByVariadicTemplate
    
  
    Issue 1549143002:
  Add thread affinity and ASSERT() for same-thread restriction to WTF::Function  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@TRV_ThreadSafeBindByVariadicTemplate| Index: third_party/WebKit/Source/wtf/Functional.h | 
| diff --git a/third_party/WebKit/Source/wtf/Functional.h b/third_party/WebKit/Source/wtf/Functional.h | 
| index d254fd900030641338e13a91a556b3ce19dca36a..8d25909680343619cbcd2e7e9455c24c2f93c35c 100644 | 
| --- a/third_party/WebKit/Source/wtf/Functional.h | 
| +++ b/third_party/WebKit/Source/wtf/Functional.h | 
| @@ -176,11 +176,16 @@ template<> struct ParamStorageTraits<void*> { | 
| static void* unwrap(const StorageType& value) { return value; } | 
| }; | 
| -template<typename> | 
| +enum FunctionThreadAffinity { | 
| + CrossThreadAffinity, | 
| + SameThreadAffinity | 
| +}; | 
| + | 
| +template<typename, FunctionThreadAffinity threadAffinity = SameThreadAffinity> | 
| class Function; | 
| -template<typename R, typename... Args> | 
| -class Function<R(Args...)> { | 
| +template<FunctionThreadAffinity threadAffinity, typename R, typename... Args> | 
| +class Function<R(Args...), threadAffinity> { | 
| USING_FAST_MALLOC(Function); | 
| WTF_MAKE_NONCOPYABLE(Function); | 
| public: | 
| @@ -188,13 +193,41 @@ public: | 
| virtual R operator()(Args... args) = 0; | 
| protected: | 
| Function() = default; | 
| + void checkThread() { } | 
| }; | 
| -template <typename BoundParametersTuple, typename FunctionWrapper, typename... UnboundParameters> | 
| +#if ENABLE(ASSERT) | 
| +template<typename R, typename... Args> | 
| +class Function<R(Args...), SameThreadAffinity> { | 
| + USING_FAST_MALLOC(Function); | 
| + WTF_MAKE_NONCOPYABLE(Function); | 
| +public: | 
| + virtual ~Function() | 
| + { | 
| + checkThread(); | 
| + } | 
| + virtual R operator()(Args... args) = 0; | 
| +protected: | 
| + Function() | 
| + : m_createdThread(currentThread()) | 
| + { | 
| + } | 
| + | 
| + void NEVER_INLINE checkThread() | 
| 
kinuko
2016/03/02 07:30:56
sorry, why we need this to be noinline?
 
hiroshige
2016/03/03 02:21:07
This is to make checkThread() to appear in the cra
 | 
| + { | 
| + RELEASE_ASSERT(m_createdThread == currentThread()); | 
| + } | 
| + | 
| +private: | 
| + ThreadIdentifier m_createdThread; | 
| +}; | 
| +#endif | 
| + | 
| +template <FunctionThreadAffinity threadAffinity, typename BoundParametersTuple, typename FunctionWrapper, typename... UnboundParameters> | 
| class PartBoundFunctionImpl; | 
| -template <typename... BoundParameters, typename FunctionWrapper, typename... UnboundParameters> | 
| -class PartBoundFunctionImpl<std::tuple<BoundParameters...>, FunctionWrapper, UnboundParameters...> final : public Function<typename FunctionWrapper::ResultType(UnboundParameters...)> { | 
| +template <FunctionThreadAffinity threadAffinity, typename... BoundParameters, typename FunctionWrapper, typename... UnboundParameters> | 
| +class PartBoundFunctionImpl<threadAffinity, std::tuple<BoundParameters...>, FunctionWrapper, UnboundParameters...> final : public Function<typename FunctionWrapper::ResultType(UnboundParameters...), threadAffinity> { | 
| public: | 
| // We would like to use StorageTraits<UnboundParameters>... with StorageTraits defined as below in order to obtain | 
| // storage traits of UnboundParameters, but unfortunately MSVC can't handle template using declarations correctly. | 
| @@ -221,6 +254,7 @@ private: | 
| template <std::size_t... boundIndices> | 
| typename FunctionWrapper::ResultType callInternal(UnboundParameters... unbound, const base::IndexSequence<boundIndices...>&) | 
| { | 
| + this->checkThread(); | 
| // Get each element in m_bound, unwrap them, and call the function with the desired arguments. | 
| return m_functionWrapper(ParamStorageTraits<typename std::decay<BoundParameters>::type>::unwrap(std::get<boundIndices>(m_bound))..., unbound...); | 
| } | 
| @@ -229,23 +263,31 @@ private: | 
| std::tuple<typename ParamStorageTraits<typename std::decay<BoundParameters>::type>::StorageType...> m_bound; | 
| }; | 
| -template <typename... UnboundParameters, typename FunctionType, typename... BoundParameters> | 
| -PassOwnPtr<Function<typename FunctionWrapper<FunctionType>::ResultType(UnboundParameters...)>> bind(FunctionType function, BoundParameters&&... boundParameters) | 
| +template <FunctionThreadAffinity threadAffinity, typename... UnboundParameters, typename FunctionType, typename... BoundParameters> | 
| +PassOwnPtr<Function<typename FunctionWrapper<FunctionType>::ResultType(UnboundParameters...), threadAffinity>> bindInternal(FunctionType function, BoundParameters&&... boundParameters) | 
| { | 
| // Bound parameters' types are wrapped with std::tuple so we can pass two template parameter packs (bound | 
| // parameters and unbound) to PartBoundFunctionImpl. Note that a tuple of this type isn't actually created; | 
| // std::tuple<> is just for carrying the bound parameters' types. Any other class template taking a type parameter | 
| // pack can be used instead of std::tuple. std::tuple is used just because it's most convenient for this purpose. | 
| - using BoundFunctionType = PartBoundFunctionImpl<std::tuple<BoundParameters&&...>, FunctionWrapper<FunctionType>, UnboundParameters...>; | 
| + using BoundFunctionType = PartBoundFunctionImpl<threadAffinity, std::tuple<BoundParameters&&...>, FunctionWrapper<FunctionType>, UnboundParameters...>; | 
| return adoptPtr(new BoundFunctionType(FunctionWrapper<FunctionType>(function), std::forward<BoundParameters>(boundParameters)...)); | 
| } | 
| -typedef Function<void()> Closure; | 
| +template <typename... UnboundParameters, typename FunctionType, typename... BoundParameters> | 
| +PassOwnPtr<Function<typename FunctionWrapper<FunctionType>::ResultType(UnboundParameters...), SameThreadAffinity>> bind(FunctionType function, BoundParameters&&... boundParameters) | 
| +{ | 
| + return bindInternal<SameThreadAffinity, UnboundParameters...>(function, std::forward<BoundParameters>(boundParameters)...); | 
| +} | 
| + | 
| +typedef Function<void(), SameThreadAffinity> Closure; | 
| +typedef Function<void(), CrossThreadAffinity> CrossThreadClosure; | 
| } // namespace WTF | 
| using WTF::Function; | 
| using WTF::bind; | 
| using WTF::Closure; | 
| +using WTF::CrossThreadClosure; | 
| #endif // WTF_Functional_h |