OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2009-2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2009-2010 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 21 matching lines...) Expand all Loading... |
32 #define CrossThreadTask_h | 32 #define CrossThreadTask_h |
33 | 33 |
34 #include "core/dom/ExecutionContext.h" | 34 #include "core/dom/ExecutionContext.h" |
35 #include "core/dom/ExecutionContextTask.h" | 35 #include "core/dom/ExecutionContextTask.h" |
36 #include "platform/ThreadSafeFunctional.h" | 36 #include "platform/ThreadSafeFunctional.h" |
37 #include "wtf/PassOwnPtr.h" | 37 #include "wtf/PassOwnPtr.h" |
38 #include <type_traits> | 38 #include <type_traits> |
39 | 39 |
40 namespace blink { | 40 namespace blink { |
41 | 41 |
42 // createCrossThreadTask(...) is ExecutionContextTask version of | 42 // createCrossThreadTask(...) is similar to but safer than |
43 // threadSafeBind(). | 43 // CallClosureTask::create(bind(...)) for cross-thread task posting. |
44 // Using WTF::bind() directly is not thread-safe due to temporary objects, see | 44 // postTask(CallClosureTask::create(bind(...))) is not thread-safe |
45 // https://crbug.com/390851 for details. | 45 // due to temporary objects, see http://crbug.com/390851 for details. |
46 // | 46 // |
47 // Example: | 47 // Example: |
48 // void func1(int, const String&); | 48 // void func1(int, const String&); |
49 // createCrossThreadTask(func1, 42, str); | 49 // createCrossThreadTask(func1, 42, str); |
50 // func1(42, str2) will be called, where |str2| is a deep copy of | 50 // func1(42, str2) will be called, where |str2| is a deep copy of |
51 // |str| (created by str.isolatedCopy()). | 51 // |str| (created by str.isolatedCopy()). |
52 // | 52 // |
53 // Don't (if you pass the task across threads): | 53 // Don't (if you pass the task across threads): |
54 // bind(func1, 42, str); | 54 // bind(func1, 42, str); |
55 // bind(func1, 42, str.isolatedCopy()); | 55 // bind(func1, 42, str.isolatedCopy()); |
56 // | 56 // |
57 // For functions: | 57 // Usage: |
58 // void functionEC(MP1, ..., MPn, ExecutionContext*); | 58 // For functions: |
59 // void function(MP1, ..., MPn); | 59 // void functionEC(MP1, ..., MPn, ExecutionContext*); |
60 // class C { | 60 // void function(MP1, ..., MPn); |
61 // void memberEC(MP1, ..., MPn, ExecutionContext*); | 61 // class C { |
62 // void member(MP1, ..., MPn); | 62 // void memberEC(MP1, ..., MPn, ExecutionContext*); |
63 // }; | 63 // void member(MP1, ..., MPn); |
64 // We create tasks represented by std::unique_ptr<ExecutionContextTask>: | 64 // }; |
65 // createCrossThreadTask(functionEC, const P1& p1, ..., const Pn& pn); | 65 // We create tasks represented by PassOwnPtr<ExecutionContextTask>: |
66 // createCrossThreadTask(memberEC, C* ptr, const P1& p1, ..., const Pn& pn); | 66 // [1] createCrossThreadTask(functionEC, const P1& p1, ..., const Pn& pn
); |
67 // createCrossThreadTask(function, const P1& p1, ..., const Pn& pn); | 67 // [2] createCrossThreadTask(memberEC, C* ptr, const P1& p1, ..., const
Pn& pn); |
68 // createCrossThreadTask(member, C* ptr, const P1& p1, ..., const Pn& pn); | 68 // [3] createCrossThreadTask(function, const P1& p1, ..., const Pn& pn); |
69 // (|ptr| can also be WeakPtr<C> or other pointer-like types) | 69 // [4] createCrossThreadTask(member, C* ptr, const P1& p1, ..., const Pn
& pn); |
70 // and then the following are called on the target thread: | 70 // [5] createCrossThreadTask(member, const WeakPtr<C>& ptr, const P1& p1
, ..., const Pn& pn); |
71 // functionEC(p1, ..., pn, context); | 71 // [6] createCrossThreadTask(member, C* p0, const P1& p1, ..., const Pn&
pn); |
72 // ptr->memberEC(p1, ..., pn, context); | 72 // and then the following are called on the target thread: |
73 // function(p1, ..., pn); | 73 // [1] functionEC(p1, ..., pn, context); |
74 // ptr->member(p1, ..., pn); | 74 // [2] ptr->memberEC(p1, ..., pn, context); |
| 75 // [3] function(p1, ..., pn); |
| 76 // [4,5] ptr->member(p1, ..., pn); |
| 77 // [6] p0->member(p1, ..., pn); |
75 // | 78 // |
76 // ExecutionContext: | 79 // ExecutionContext: |
77 // |context| is supplied by the target thread. | 80 // |context| is supplied by the target thread. |
78 // | 81 // |
79 // Deep copies by threadSafeBind(): | 82 // Deep copies by threadSafeBind(): |
80 // |ptr|, |p1|, ..., |pn| are processed by threadSafeBind() and thus | 83 // |p0|, |p1|, ..., |pn| are processed by threadSafeBind() and thus |
81 // CrossThreadCopier. | 84 // CrossThreadCopier. |
82 // You don't have to call manually e.g. isolatedCopy(). | 85 // You don't have to call manually e.g. isolatedCopy(). |
83 // To pass things that cannot be copied by CrossThreadCopier | 86 // To pass things that cannot be copied by CrossThreadCopier |
84 // (e.g. pointers), use AllowCrossThreadAccess() explicitly. | 87 // (e.g. pointers), use AllowCrossThreadAccess() explicitly. |
| 88 // |ptr| is assumed safe to be passed across threads, and |
| 89 // AllowCrossThreadAccess() is applied automatically. |
85 | 90 |
86 // RETTYPE, PS, and MPS are added as template parameters to circumvent MSVC 18.0
0.21005.1 (VS 2013) issues. | 91 // RETTYPE, PS, and MPS are added as template parameters to circumvent MSVC 18.0
0.21005.1 (VS 2013) issues. |
87 | 92 |
| 93 // [1] createCrossThreadTask() for non-member functions (with ExecutionContext*
argument). |
| 94 // (P = <P1, ..., Pn>, MP = <MP1, ..., MPn, ExecutionContext*>) |
88 template<typename... P, typename... MP, | 95 template<typename... P, typename... MP, |
89 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> | 96 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> |
90 typename std::enable_if<PS + 1 == MPS, RETTYPE>::type createCrossThreadTask(void
(*function)(MP...), P&&... parameters) | 97 typename std::enable_if<PS + 1 == MPS, RETTYPE>::type createCrossThreadTask(void
(*function)(MP...), P&&... parameters) |
91 { | 98 { |
92 return internal::CallClosureWithExecutionContextTask<WTF::CrossThreadAffinit
y>::create(threadSafeBind<ExecutionContext*>(function, std::forward<P>(parameter
s)...)); | 99 return internal::CallClosureWithExecutionContextTask<WTF::CrossThreadAffinit
y>::create(threadSafeBind<ExecutionContext*>(function, std::forward<P>(parameter
s)...)); |
93 } | 100 } |
94 | 101 |
| 102 // [2] createCrossThreadTask() for member functions of class C (with ExecutionCo
ntext* argument) + raw pointer (C*). |
| 103 // (P = <P1, ..., Pn>, MP = <MP1, ..., MPn, ExecutionContext*>) |
| 104 template<typename C, typename... P, typename... MP, |
| 105 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> |
| 106 typename std::enable_if<PS + 1 == MPS, RETTYPE>::type createCrossThreadTask(void
(C::*function)(MP...), C* p, P&&... parameters) |
| 107 { |
| 108 return internal::CallClosureWithExecutionContextTask<WTF::CrossThreadAffinit
y>::create(threadSafeBind<ExecutionContext*>(function, AllowCrossThreadAccess(p)
, std::forward<P>(parameters)...)); |
| 109 } |
| 110 |
| 111 // [3] createCrossThreadTask() for non-member functions |
| 112 // (P = <P1, ..., Pn>, MP = <MP1, ..., MPn>) |
95 template<typename... P, typename... MP, | 113 template<typename... P, typename... MP, |
96 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> | 114 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> |
97 typename std::enable_if<PS == MPS, RETTYPE>::type createCrossThreadTask(void (*f
unction)(MP...), P&&... parameters) | 115 typename std::enable_if<PS == MPS, RETTYPE>::type createCrossThreadTask(void (*f
unction)(MP...), P&&... parameters) |
98 { | 116 { |
99 return internal::CallClosureTask<WTF::CrossThreadAffinity>::create(threadSaf
eBind(function, std::forward<P>(parameters)...)); | 117 return internal::CallClosureTask<WTF::CrossThreadAffinity>::create(threadSaf
eBind(function, std::forward<P>(parameters)...)); |
100 } | 118 } |
101 | 119 |
| 120 // [4] createCrossThreadTask() for member functions of class C + raw pointer (C*
) |
| 121 // [5] createCrossThreadTask() for member functions of class C + weak pointer (c
onst WeakPtr<C>&) |
| 122 // (P = <P1, ..., Pn>, MP = <MP1, ..., MPn>) |
| 123 template<typename C, typename... P, typename... MP, |
| 124 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> |
| 125 typename std::enable_if<PS == MPS, RETTYPE>::type createCrossThreadTask(void (C:
:*function)(MP...), C* p, P&&... parameters) |
| 126 { |
| 127 return internal::CallClosureTask<WTF::CrossThreadAffinity>::create(threadSaf
eBind(function, AllowCrossThreadAccess(p), std::forward<P>(parameters)...)); |
| 128 } |
| 129 |
102 template<typename C, typename... P, typename... MP, | 130 template<typename C, typename... P, typename... MP, |
103 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> | 131 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> |
104 typename std::enable_if<PS == MPS, RETTYPE>::type createCrossThreadTask(void (C:
:*function)(MP...), P&&... parameters) | 132 typename std::enable_if<PS == MPS, RETTYPE>::type createCrossThreadTask(void (C:
:*function)(MP...), const WeakPtr<C>& p, P&&... parameters) |
105 { | 133 { |
106 return internal::CallClosureWithExecutionContextTask<WTF::CrossThreadAffinit
y>::create(threadSafeBind<ExecutionContext*>(function, std::forward<P>(parameter
s)...)); | 134 return internal::CallClosureTask<WTF::CrossThreadAffinity>::create(threadSaf
eBind(function, AllowCrossThreadAccess(p), std::forward<P>(parameters)...)); |
107 } | 135 } |
108 | 136 |
109 template<typename C, typename... P, typename... MP, | 137 // [6] createCrossThreadTask() for member functions + pointers to class C other
than C* or const WeakPtr<C>& |
| 138 // (P = <P0, P1, ..., Pn>, MP = <MP1, ..., MPn>) |
| 139 template<typename C, typename P0, typename... P, typename... MP, |
110 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> | 140 typename RETTYPE = std::unique_ptr<ExecutionContextTask>, size_t PS = sizeof
...(P), size_t MPS = sizeof...(MP)> |
111 typename std::enable_if<PS == MPS + 1, RETTYPE>::type createCrossThreadTask(void
(C::*function)(MP...), P&&... parameters) | 141 typename std::enable_if<PS == MPS && !WTF::IsSubclassOfTemplate<typename std::de
cay<P0>::type, WeakPtr>::value && !std::is_pointer<typename std::decay<P0>::type
>::value, RETTYPE>::type |
| 142 createCrossThreadTask(void (C::*function)(MP...), P0&& parameter0, P&&... parame
ters) |
112 { | 143 { |
113 return internal::CallClosureTask<WTF::CrossThreadAffinity>::create(threadSaf
eBind(function, std::forward<P>(parameters)...)); | 144 return internal::CallClosureTask<WTF::CrossThreadAffinity>::create(threadSaf
eBind(function, std::forward<P0>(parameter0), std::forward<P>(parameters)...)); |
114 } | 145 } |
115 | 146 |
116 } // namespace blink | 147 } // namespace blink |
117 | 148 |
118 #endif // CrossThreadTask_h | 149 #endif // CrossThreadTask_h |
OLD | NEW |