Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: src/plugin/DetachedInitialization.h

Issue 29334397: Issue #2230, #3391 - Load filters on "download begin" event
Patch Set: Created Jan. 22, 2016, 6:02 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/plugin/PluginClass.h » ('j') | src/plugin/PluginClass.h » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 #ifndef _DETACHED_INITIALIZATION_H_ 18 #ifndef _DETACHED_INITIALIZATION_H_
19 #define _DETACHED_INITIALIZATION_H_ 19 #define _DETACHED_INITIALIZATION_H_
20 20
21 #include <atomic> 21 #include <atomic>
22 #include <thread> 22 #include <thread>
23 #include <mutex> 23 #include <mutex>
24 #include <chrono> 24 #include <chrono>
25 #include <condition_variable> 25 #include <condition_variable>
26 26
27 /** 27 /**
28 * A detached initializer for static class members 28 * Initialization performed in a detached thread
29 * 29 *
30 * Detached initializers use a separate thread to avoid delays at instantiation. 30 * This kind of initialization shares much in common with a singleton.
sergei 2016/01/29 10:03:20 This line is OK.
31 * Variables statically initialized in a DLL cannot, however, contain threads. 31 * Rather than constructing a singleton, instead we execute an initialization fu nction exactly once.
sergei 2016/01/29 10:03:19 There is nothing about singleton. "Detached initia
32 * Thus such initialization must occur in the constructor at the earliest.
sergei 2016/01/29 10:03:20 These two lines are not related to this file.
33 *
sergei 2016/01/29 10:03:20 It's important to say in the description whether t
34 * This kind of initialization acts shares much in common with a singleton.
35 * Rather than constructing a singleton, instead we execute an initialization fu nction.
36 * The multiprocessing and synchronization issues, however, are essentially iden tical. 32 * The multiprocessing and synchronization issues, however, are essentially iden tical.
sergei 2016/01/29 10:03:20 This line is not related to this file.
37 *
38 * The designated usage of this class:
39 * 1) Define a static class member 'x' of this type with an initializer function .
40 * 2) Call 'x.SpawnInitializer()' in the constructors to run the initializer.
41 * 3) Call 'x.EnsureInitialized()' before relying upon any of the side effects o f the initializer.
42 *
43 * The implementation acts much like a multithreaded singleton initialization us ing a double-checked lock. 33 * The implementation acts much like a multithreaded singleton initialization us ing a double-checked lock.
44 * See https://en.wikipedia.org/wiki/Double-checked_locking and http://preshing. com/20130922/acquire-and-release-fences/ 34 * See https://en.wikipedia.org/wiki/Double-checked_locking and http://preshing. com/20130922/acquire-and-release-fences/
sergei 2016/01/29 10:03:20 I would say that semantically it looks completely
45 * The flag members of this class enable fast-return paths, that is, a return wi thout obtaining a mutex lock. 35 * The flag members of this class enable fast-return paths, that is, a return wi thout obtaining a mutex lock.
sergei 2016/01/29 10:03:19 I don't think we need this line.
46 * 36 *
47 * \tparam F 37 * Designated usage:
48 * The initializer function 38 * 1) Derive from this class, defining the factory Initializer().
sergei 2016/01/29 10:03:19 I am afraid, I disagree with such approach (even b
39 * 2) Call 'SpawnInitializer()' in the constructors.
40 * 3) Call 'EnsureInitialized()' before relying upon any of the side effects of the initializer.
49 * 41 *
50 * \par Serialization Guarantees 42 * \par Serialization Guarantees
51 * The visible effect of these function returns are serialized: 43 * The visible effect of these function returns are serialized:
52 * - SpawnInitializer() before ThreadMain() 44 * - SpawnInitializer() before ThreadMain()
53 * - ThreadMain() before EnsureInitialized() 45 * - ThreadMain() before EnsureInitialized()
54 * - If ThreadMain() started, ThreadMain() before destructor 46 * - If ThreadMain() started, ThreadMain() before destructor
55 */ 47 */
56 template<void (&F)()>
57 class DetachedInitializer 48 class DetachedInitializer
58 { 49 {
59 // "protected" declaration allows white-box subclass for testing 50 // "protected" declaration allows white-box subclass for testing
60 protected: 51 protected:
61 /** 52 /**
62 * Set to true after initializer thread successfully constructed; remains true thereafter. 53 * Set to true after initializer thread successfully constructed; remains true thereafter.
63 */ 54 */
64 std::atomic<bool> hasInitializerStarted; 55 std::atomic<bool> hasInitializerStarted;
65 56
66 /** 57 /**
(...skipping 29 matching lines...) Expand all
96 inline bool AlreadyInitialized() // noexcept 87 inline bool AlreadyInitialized() // noexcept
97 { 88 {
98 // Memory fence ensures load starts after any other load or store 89 // Memory fence ensures load starts after any other load or store
99 return isInitializationComplete.load(std::memory_order_acquire); 90 return isInitializationComplete.load(std::memory_order_acquire);
100 } 91 }
101 92
102 inline bool AlreadyStartedInitializer() // noexcept 93 inline bool AlreadyStartedInitializer() // noexcept
103 { 94 {
104 return hasInitializerStarted.load(std::memory_order_acquire); 95 return hasInitializerStarted.load(std::memory_order_acquire);
105 } 96 }
97
98 /**
99 * Type of initializer objects
100 *
101 * Note that the underlying function returns 'void'.
102 * This class refuses responsibility for specific error semantics.
103 * If the initializer thread throws, then so will EnsureInitialized().
sergei 2016/01/29 10:03:19 Only this line is important, the rest about void a
104 * Anything beyond this is the responsibility of the owner.
105 */
106 typedef std::function<void()> InitializerType;
106 107
107 /** 108 /**
108 * Main function for thread 109 * Factory function for initializers
109 */ 110 */
110 void ThreadMain() 111 virtual InitializerType Initializer() = 0;
112
113 /**
114 * Main function for initialization thread
115 */
116 void ThreadMain(InitializerType f)
111 { 117 {
112 try 118 try
113 { 119 {
114 F(); 120 f();
115 } 121 }
116 catch (std::exception& e) 122 catch (...)
117 { 123 {
118 // Assert initializer threw an exception 124 // Assert initializer threw an exception
119 initializerException = std::current_exception(); 125 initializerException = std::current_exception();
120 } 126 }
121 /* 127 /*
122 * Synchronize with reading the completion status in EnsureInitialized(). 128 * Synchronize with reading the completion status in EnsureInitialized().
123 * Serialize return from SpawnInitializer() and this function. 129 * Serialize return from SpawnInitializer() and this function.
sergei 2016/01/29 10:03:20 The comment is wrong. We need to lock mutex here m
124 */ 130 */
125 LockGuardType lg(mutex); 131 LockGuardType lg(mutex);
126 isInitializationComplete.store(true, std::memory_order_release); 132 isInitializationComplete.store(true, std::memory_order_release);
127 cv.notify_all(); 133 cv.notify_all();
128 } 134 }
129 135
130 /** 136 /**
131 * "noexcept" version of EnsureInitialized() used to implement both it and the destructor 137 * "noexcept" version of EnsureInitialized() used to implement both it and the destructor
132 */ 138 */
133 void EnsureInitializedNoexcept() // noexcept 139 void EnsureInitializedNoexcept() // noexcept
134 { 140 {
135 try 141 try
136 { 142 {
137 if (AlreadyInitialized()) 143 if (AlreadyInitialized())
138 { 144 {
139 return; // fast-return path 145 return; // fast-return path
sergei 2016/01/29 10:03:19 I would say we don't need these comments "fast ret
140 } 146 }
141 UniqueLockType ul(mutex); // won't throw because this class uses only scop ed locks 147 UniqueLockType ul(mutex); // won't throw because this class uses only scop ed locks
142 /* 148 /*
143 * We must always check initialization status under lock. 149 * We must always check initialization status under lock.
144 * The loop protects against spurious wake-up calls. 150 * The loop protects against spurious wake-up calls.
145 */ 151 */
146 while (!AlreadyInitialized()) 152 while (!AlreadyInitialized())
147 { 153 {
148 cv.wait(ul); // won't throw because mutex is locked 154 cv.wait(ul); // won't throw because mutex is locked
149 } 155 }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
210 */ 216 */
211 if (AlreadyStartedInitializer()) 217 if (AlreadyStartedInitializer())
212 { 218 {
213 return; 219 return;
214 } 220 }
215 /* 221 /*
216 * This thread constructor is the only statement that can throw in this function. 222 * This thread constructor is the only statement that can throw in this function.
217 * If it does throw, the initialization-started flag won't be set. 223 * If it does throw, the initialization-started flag won't be set.
218 * An exception here is thus a soft error, since a future invocation mig ht succeed. 224 * An exception here is thus a soft error, since a future invocation mig ht succeed.
219 */ 225 */
220 std::thread th([this]() -> void { ThreadMain(); }); 226 std::thread th(std::bind([this](InitializerType f) -> void { ThreadMain( f); }, Initializer()));
221 // Memory fence ensures store ends before any other load or store 227 // Memory fence ensures store ends before any other load or store
222 hasInitializerStarted.store(true, std::memory_order_release); 228 hasInitializerStarted.store(true, std::memory_order_release);
223 th.detach(); // Won't throw because the thread is both valid and joinabl e 229 th.detach(); // Won't throw because the thread is both valid and joinabl e
224 return; 230 return;
225 } 231 }
226 else 232 else
227 { 233 {
228 // Assert mutex is not locked 234 // Assert mutex is not locked
229 if (AlreadyStartedInitializer()) 235 if (AlreadyStartedInitializer())
230 { 236 {
(...skipping 17 matching lines...) Expand all
248 void EnsureInitialized() 254 void EnsureInitialized()
249 { 255 {
250 EnsureInitializedNoexcept(); 256 EnsureInitializedNoexcept();
251 if (initializerException) 257 if (initializerException)
252 { 258 {
253 std::rethrow_exception(initializerException); 259 std::rethrow_exception(initializerException);
254 } 260 }
255 } 261 }
256 }; 262 };
257 263
264 /**
265 * Detached initializers use a separate thread to avoid delays at instantiation.
266 * The constructors of variables statically initialized in a DLL cannot, however , contain threads.
267 * Thus such initialization must (generally) occur in the constructor.
268 */
269 template<void(&F)()>
270 class DetachedInitializerStaticFunction
271 : public DetachedInitializer
272 {
273 InitializerType Initializer() override
274 {
275 return InitializerType([] { F(); });
276 }
277 };
278
258 #endif // _DETACHED_INITIALIZATION_H_ 279 #endif // _DETACHED_INITIALIZATION_H_
OLDNEW
« no previous file with comments | « no previous file | src/plugin/PluginClass.h » ('j') | src/plugin/PluginClass.h » ('J')

Powered by Google App Engine
This is Rietveld