1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/sandbox/chromium/base/threading/sequenced_worker_pool.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,358 @@ 1.4 +// Copyright (c) 2012 The Chromium Authors. All rights reserved. 1.5 +// Use of this source code is governed by a BSD-style license that can be 1.6 +// found in the LICENSE file. 1.7 + 1.8 +#ifndef BASE_THREADING_SEQUENCED_WORKER_POOL_H_ 1.9 +#define BASE_THREADING_SEQUENCED_WORKER_POOL_H_ 1.10 + 1.11 +#include <cstddef> 1.12 +#include <string> 1.13 + 1.14 +#include "base/base_export.h" 1.15 +#include "base/basictypes.h" 1.16 +#include "base/callback_forward.h" 1.17 +#include "base/memory/ref_counted.h" 1.18 +#include "base/memory/scoped_ptr.h" 1.19 +#include "base/task_runner.h" 1.20 + 1.21 +namespace tracked_objects { 1.22 +class Location; 1.23 +} // namespace tracked_objects 1.24 + 1.25 +namespace base { 1.26 + 1.27 +class MessageLoopProxy; 1.28 + 1.29 +template <class T> class DeleteHelper; 1.30 + 1.31 +class SequencedTaskRunner; 1.32 + 1.33 +// A worker thread pool that enforces ordering between sets of tasks. It also 1.34 +// allows you to specify what should happen to your tasks on shutdown. 1.35 +// 1.36 +// To enforce ordering, get a unique sequence token from the pool and post all 1.37 +// tasks you want to order with the token. All tasks with the same token are 1.38 +// guaranteed to execute serially, though not necessarily on the same thread. 1.39 +// This means that: 1.40 +// 1.41 +// - No two tasks with the same token will run at the same time. 1.42 +// 1.43 +// - Given two tasks T1 and T2 with the same token such that T2 will 1.44 +// run after T1, then T2 will start after T1 is destroyed. 1.45 +// 1.46 +// - If T2 will run after T1, then all memory changes in T1 and T1's 1.47 +// destruction will be visible to T2. 1.48 +// 1.49 +// Example: 1.50 +// SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken(); 1.51 +// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN, 1.52 +// FROM_HERE, base::Bind(...)); 1.53 +// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN, 1.54 +// FROM_HERE, base::Bind(...)); 1.55 +// 1.56 +// You can make named sequence tokens to make it easier to share a token 1.57 +// across different components. 1.58 +// 1.59 +// You can also post tasks to the pool without ordering using PostWorkerTask. 1.60 +// These will be executed in an unspecified order. The order of execution 1.61 +// between tasks with different sequence tokens is also unspecified. 1.62 +// 1.63 +// This class may be leaked on shutdown to facilitate fast shutdown. The 1.64 +// expected usage, however, is to call Shutdown(), which correctly accounts 1.65 +// for CONTINUE_ON_SHUTDOWN behavior and is required for BLOCK_SHUTDOWN 1.66 +// behavior. 1.67 +// 1.68 +// Implementation note: This does not use a base::WorkerPool since that does 1.69 +// not enforce shutdown semantics or allow us to specify how many worker 1.70 +// threads to run. For the typical use case of random background work, we don't 1.71 +// necessarily want to be super aggressive about creating threads. 1.72 +// 1.73 +// Note that SequencedWorkerPool is RefCountedThreadSafe (inherited 1.74 +// from TaskRunner). 1.75 +class BASE_EXPORT SequencedWorkerPool : public TaskRunner { 1.76 + public: 1.77 + // Defines what should happen to a task posted to the worker pool on 1.78 + // shutdown. 1.79 + enum WorkerShutdown { 1.80 + // Tasks posted with this mode which have not run at shutdown will be 1.81 + // deleted rather than run, and any tasks with this mode running at 1.82 + // shutdown will be ignored (the worker thread will not be joined). 1.83 + // 1.84 + // This option provides a nice way to post stuff you don't want blocking 1.85 + // shutdown. For example, you might be doing a slow DNS lookup and if it's 1.86 + // blocked on the OS, you may not want to stop shutdown, since the result 1.87 + // doesn't really matter at that point. 1.88 + // 1.89 + // However, you need to be very careful what you do in your callback when 1.90 + // you use this option. Since the thread will continue to run until the OS 1.91 + // terminates the process, the app can be in the process of tearing down 1.92 + // when you're running. This means any singletons or global objects you 1.93 + // use may suddenly become invalid out from under you. For this reason, 1.94 + // it's best to use this only for slow but simple operations like the DNS 1.95 + // example. 1.96 + CONTINUE_ON_SHUTDOWN, 1.97 + 1.98 + // Tasks posted with this mode that have not started executing at 1.99 + // shutdown will be deleted rather than executed. However, any tasks that 1.100 + // have already begun executing when shutdown is called will be allowed 1.101 + // to continue, and will block shutdown until completion. 1.102 + // 1.103 + // Note: Because Shutdown() may block while these tasks are executing, 1.104 + // care must be taken to ensure that they do not block on the thread that 1.105 + // called Shutdown(), as this may lead to deadlock. 1.106 + SKIP_ON_SHUTDOWN, 1.107 + 1.108 + // Tasks posted with this mode will block shutdown until they're 1.109 + // executed. Since this can have significant performance implications, 1.110 + // use sparingly. 1.111 + // 1.112 + // Generally, this should be used only for user data, for example, a task 1.113 + // writing a preference file. 1.114 + // 1.115 + // If a task is posted during shutdown, it will not get run since the 1.116 + // workers may already be stopped. In this case, the post operation will 1.117 + // fail (return false) and the task will be deleted. 1.118 + BLOCK_SHUTDOWN, 1.119 + }; 1.120 + 1.121 + // Opaque identifier that defines sequencing of tasks posted to the worker 1.122 + // pool. 1.123 + class SequenceToken { 1.124 + public: 1.125 + SequenceToken() : id_(0) {} 1.126 + ~SequenceToken() {} 1.127 + 1.128 + bool Equals(const SequenceToken& other) const { 1.129 + return id_ == other.id_; 1.130 + } 1.131 + 1.132 + // Returns false if current thread is executing an unsequenced task. 1.133 + bool IsValid() const { 1.134 + return id_ != 0; 1.135 + } 1.136 + 1.137 + private: 1.138 + friend class SequencedWorkerPool; 1.139 + 1.140 + explicit SequenceToken(int id) : id_(id) {} 1.141 + 1.142 + int id_; 1.143 + }; 1.144 + 1.145 + // Allows tests to perform certain actions. 1.146 + class TestingObserver { 1.147 + public: 1.148 + virtual ~TestingObserver() {} 1.149 + virtual void OnHasWork() = 0; 1.150 + virtual void WillWaitForShutdown() = 0; 1.151 + virtual void OnDestruct() = 0; 1.152 + }; 1.153 + 1.154 + // Gets the SequencedToken of the current thread. 1.155 + // If current thread is not a SequencedWorkerPool worker thread or is running 1.156 + // an unsequenced task, returns an invalid SequenceToken. 1.157 + static SequenceToken GetSequenceTokenForCurrentThread(); 1.158 + 1.159 + // When constructing a SequencedWorkerPool, there must be a 1.160 + // MessageLoop on the current thread unless you plan to deliberately 1.161 + // leak it. 1.162 + 1.163 + // Pass the maximum number of threads (they will be lazily created as needed) 1.164 + // and a prefix for the thread name to aid in debugging. 1.165 + SequencedWorkerPool(size_t max_threads, 1.166 + const std::string& thread_name_prefix); 1.167 + 1.168 + // Like above, but with |observer| for testing. Does not take 1.169 + // ownership of |observer|. 1.170 + SequencedWorkerPool(size_t max_threads, 1.171 + const std::string& thread_name_prefix, 1.172 + TestingObserver* observer); 1.173 + 1.174 + // Returns a unique token that can be used to sequence tasks posted to 1.175 + // PostSequencedWorkerTask(). Valid tokens are always nonzero. 1.176 + SequenceToken GetSequenceToken(); 1.177 + 1.178 + // Returns the sequence token associated with the given name. Calling this 1.179 + // function multiple times with the same string will always produce the 1.180 + // same sequence token. If the name has not been used before, a new token 1.181 + // will be created. 1.182 + SequenceToken GetNamedSequenceToken(const std::string& name); 1.183 + 1.184 + // Returns a SequencedTaskRunner wrapper which posts to this 1.185 + // SequencedWorkerPool using the given sequence token. Tasks with nonzero 1.186 + // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay 1.187 + // are posted with BLOCK_SHUTDOWN behavior. 1.188 + scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunner( 1.189 + SequenceToken token); 1.190 + 1.191 + // Returns a SequencedTaskRunner wrapper which posts to this 1.192 + // SequencedWorkerPool using the given sequence token. Tasks with nonzero 1.193 + // delay are posted with SKIP_ON_SHUTDOWN behavior and tasks with zero delay 1.194 + // are posted with the given shutdown behavior. 1.195 + scoped_refptr<SequencedTaskRunner> GetSequencedTaskRunnerWithShutdownBehavior( 1.196 + SequenceToken token, 1.197 + WorkerShutdown shutdown_behavior); 1.198 + 1.199 + // Returns a TaskRunner wrapper which posts to this SequencedWorkerPool using 1.200 + // the given shutdown behavior. Tasks with nonzero delay are posted with 1.201 + // SKIP_ON_SHUTDOWN behavior and tasks with zero delay are posted with the 1.202 + // given shutdown behavior. 1.203 + scoped_refptr<TaskRunner> GetTaskRunnerWithShutdownBehavior( 1.204 + WorkerShutdown shutdown_behavior); 1.205 + 1.206 + // Posts the given task for execution in the worker pool. Tasks posted with 1.207 + // this function will execute in an unspecified order on a background thread. 1.208 + // Returns true if the task was posted. If your tasks have ordering 1.209 + // requirements, see PostSequencedWorkerTask(). 1.210 + // 1.211 + // This class will attempt to delete tasks that aren't run 1.212 + // (non-block-shutdown semantics) but can't guarantee that this happens. If 1.213 + // all worker threads are busy running CONTINUE_ON_SHUTDOWN tasks, there 1.214 + // will be no workers available to delete these tasks. And there may be 1.215 + // tasks with the same sequence token behind those CONTINUE_ON_SHUTDOWN 1.216 + // tasks. Deleting those tasks before the previous one has completed could 1.217 + // cause nondeterministic crashes because the task could be keeping some 1.218 + // objects alive which do work in their destructor, which could voilate the 1.219 + // assumptions of the running task. 1.220 + // 1.221 + // The task will be guaranteed to run to completion before shutdown 1.222 + // (BLOCK_SHUTDOWN semantics). 1.223 + // 1.224 + // Returns true if the task was posted successfully. This may fail during 1.225 + // shutdown regardless of the specified ShutdownBehavior. 1.226 + bool PostWorkerTask(const tracked_objects::Location& from_here, 1.227 + const Closure& task); 1.228 + 1.229 + // Same as PostWorkerTask but allows a delay to be specified (although doing 1.230 + // so changes the shutdown behavior). The task will be run after the given 1.231 + // delay has elapsed. 1.232 + // 1.233 + // If the delay is nonzero, the task won't be guaranteed to run to completion 1.234 + // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs. 1.235 + // If the delay is zero, this behaves exactly like PostWorkerTask, i.e. the 1.236 + // task will be guaranteed to run to completion before shutdown 1.237 + // (BLOCK_SHUTDOWN semantics). 1.238 + bool PostDelayedWorkerTask(const tracked_objects::Location& from_here, 1.239 + const Closure& task, 1.240 + TimeDelta delay); 1.241 + 1.242 + // Same as PostWorkerTask but allows specification of the shutdown behavior. 1.243 + bool PostWorkerTaskWithShutdownBehavior( 1.244 + const tracked_objects::Location& from_here, 1.245 + const Closure& task, 1.246 + WorkerShutdown shutdown_behavior); 1.247 + 1.248 + // Like PostWorkerTask above, but provides sequencing semantics. This means 1.249 + // that tasks posted with the same sequence token (see GetSequenceToken()) 1.250 + // are guaranteed to execute in order. This is useful in cases where you're 1.251 + // doing operations that may depend on previous ones, like appending to a 1.252 + // file. 1.253 + // 1.254 + // The task will be guaranteed to run to completion before shutdown 1.255 + // (BLOCK_SHUTDOWN semantics). 1.256 + // 1.257 + // Returns true if the task was posted successfully. This may fail during 1.258 + // shutdown regardless of the specified ShutdownBehavior. 1.259 + bool PostSequencedWorkerTask(SequenceToken sequence_token, 1.260 + const tracked_objects::Location& from_here, 1.261 + const Closure& task); 1.262 + 1.263 + // Like PostSequencedWorkerTask above, but allows you to specify a named 1.264 + // token, which saves an extra call to GetNamedSequenceToken. 1.265 + bool PostNamedSequencedWorkerTask(const std::string& token_name, 1.266 + const tracked_objects::Location& from_here, 1.267 + const Closure& task); 1.268 + 1.269 + // Same as PostSequencedWorkerTask but allows a delay to be specified 1.270 + // (although doing so changes the shutdown behavior). The task will be run 1.271 + // after the given delay has elapsed. 1.272 + // 1.273 + // If the delay is nonzero, the task won't be guaranteed to run to completion 1.274 + // before shutdown (SKIP_ON_SHUTDOWN semantics) to avoid shutdown hangs. 1.275 + // If the delay is zero, this behaves exactly like PostSequencedWorkerTask, 1.276 + // i.e. the task will be guaranteed to run to completion before shutdown 1.277 + // (BLOCK_SHUTDOWN semantics). 1.278 + bool PostDelayedSequencedWorkerTask( 1.279 + SequenceToken sequence_token, 1.280 + const tracked_objects::Location& from_here, 1.281 + const Closure& task, 1.282 + TimeDelta delay); 1.283 + 1.284 + // Same as PostSequencedWorkerTask but allows specification of the shutdown 1.285 + // behavior. 1.286 + bool PostSequencedWorkerTaskWithShutdownBehavior( 1.287 + SequenceToken sequence_token, 1.288 + const tracked_objects::Location& from_here, 1.289 + const Closure& task, 1.290 + WorkerShutdown shutdown_behavior); 1.291 + 1.292 + // TaskRunner implementation. Forwards to PostDelayedWorkerTask(). 1.293 + virtual bool PostDelayedTask(const tracked_objects::Location& from_here, 1.294 + const Closure& task, 1.295 + TimeDelta delay) OVERRIDE; 1.296 + virtual bool RunsTasksOnCurrentThread() const OVERRIDE; 1.297 + 1.298 + // Returns true if the current thread is processing a task with the given 1.299 + // sequence_token. 1.300 + bool IsRunningSequenceOnCurrentThread(SequenceToken sequence_token) const; 1.301 + 1.302 + // Blocks until all pending tasks are complete. This should only be called in 1.303 + // unit tests when you want to validate something that should have happened. 1.304 + // This will not flush delayed tasks; delayed tasks get deleted. 1.305 + // 1.306 + // Note that calling this will not prevent other threads from posting work to 1.307 + // the queue while the calling thread is waiting on Flush(). In this case, 1.308 + // Flush will return only when there's no more work in the queue. Normally, 1.309 + // this doesn't come up since in a test, all the work is being posted from 1.310 + // the main thread. 1.311 + void FlushForTesting(); 1.312 + 1.313 + // Spuriously signal that there is work to be done. 1.314 + void SignalHasWorkForTesting(); 1.315 + 1.316 + // Implements the worker pool shutdown. This should be called during app 1.317 + // shutdown, and will discard/join with appropriate tasks before returning. 1.318 + // After this call, subsequent calls to post tasks will fail. 1.319 + // 1.320 + // Must be called from the same thread this object was constructed on. 1.321 + void Shutdown() { Shutdown(0); } 1.322 + 1.323 + // A variant that allows an arbitrary number of new blocking tasks to 1.324 + // be posted during shutdown from within tasks that execute during shutdown. 1.325 + // Only tasks designated as BLOCKING_SHUTDOWN will be allowed, and only if 1.326 + // posted by tasks that are not designated as CONTINUE_ON_SHUTDOWN. Once 1.327 + // the limit is reached, subsequent calls to post task fail in all cases. 1.328 + // 1.329 + // Must be called from the same thread this object was constructed on. 1.330 + void Shutdown(int max_new_blocking_tasks_after_shutdown); 1.331 + 1.332 + // Check if Shutdown was called for given threading pool. This method is used 1.333 + // for aborting time consuming operation to avoid blocking shutdown. 1.334 + // 1.335 + // Can be called from any thread. 1.336 + bool IsShutdownInProgress(); 1.337 + 1.338 + protected: 1.339 + virtual ~SequencedWorkerPool(); 1.340 + 1.341 + virtual void OnDestruct() const OVERRIDE; 1.342 + 1.343 + private: 1.344 + friend class RefCountedThreadSafe<SequencedWorkerPool>; 1.345 + friend class DeleteHelper<SequencedWorkerPool>; 1.346 + 1.347 + class Inner; 1.348 + class Worker; 1.349 + 1.350 + const scoped_refptr<MessageLoopProxy> constructor_message_loop_; 1.351 + 1.352 + // Avoid pulling in too many headers by putting (almost) everything 1.353 + // into |inner_|. 1.354 + const scoped_ptr<Inner> inner_; 1.355 + 1.356 + DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool); 1.357 +}; 1.358 + 1.359 +} // namespace base 1.360 + 1.361 +#endif // BASE_THREADING_SEQUENCED_WORKER_POOL_H_