Index: content/common/sequenced_worker_pool.h |
=================================================================== |
--- content/common/sequenced_worker_pool.h (revision 0) |
+++ content/common/sequenced_worker_pool.h (revision 0) |
@@ -0,0 +1,149 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef CONTENT_COMMON_SEQUENCED_WORKER_POOL_H_ |
+#define CONTENT_COMMON_SEQUENCED_WORKER_POOL_H_ |
+#pragma once |
+ |
+#include "base/callback.h" |
+#include "base/memory/linked_ptr.h" |
+#include "base/memory/ref_counted.h" |
+#include "base/tracked_objects.h" |
+ |
+// A worker thread pool that enforces ordering between sets of tasks. It also |
+// allows you to specify what should happen to your tasks on shutdown. |
+// |
+// To enforce ordering, get a unique sequence token from the pool and post all |
+// tasks you want to order with the token. All tasks with the same token are |
+// guaranteed to execute serially, though not necessarily on the same thread. |
+// |
+// Example: |
+// SequencedWorkerPool::SequenceToken token = pool.GetSequenceToken(); |
+// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN, |
+// FROM_HERE, base::Bind(...)); |
+// pool.PostSequencedWorkerTask(token, SequencedWorkerPool::SKIP_ON_SHUTDOWN, |
+// FROM_HERE, base::Bind(...)); |
+// |
+// You can also post tasks to the pool without ordering using PostWorkerTask. |
+// These will be executed in an unspecified order. The order of execution |
+// between tasks with different sequence tokens is also unspecified. |
+// |
+// This class is designed to be leaked on shutdown to allow the |
+// CONTINUE_ON_SHUTDOWN behavior to be implemented. To enforce the |
+// BLOCK_SHUTDOWN behavior, you must call Shutdown() which will wait until |
+// the necessary tasks have completed. |
+// |
+// Implementation note: This does not use a base::WorkerPool since that does |
+// not enforce shutdown semantics or allow us to specify how many worker |
+// threads to run. For the typical use case of random background work, we don't |
+// necessarily want to be super aggressive about creating threads. |
+class SequencedWorkerPool { |
+ public: |
+ // Defines what should happen to a task posted to the worker pool on shutdown. |
+ enum WorkerShutdown { |
+ // Tasks posted with this mode which have not run at shutdown will be |
+ // deleted rather than run, and any tasks with this mode running at |
+ // shutdown will be ignored (the worker thread will not be joined). |
+ // |
+ // This option provides a nice way to post stuff you don't want blocking |
+ // shutdown. For example, you might be doing a slow DNS lookup and if it's |
+ // blocked on the OS, you may not want to stop shutdown, since the result |
+ // doesn't really matter at that point. |
+ // |
+ // However, you need to be very careful what you do in your callback when |
+ // you use this option. Since the thread will continue to run until the OS |
+ // terminates the process, the app can be in the process of tearing down |
+ // when you're running. This means any singletons or global objects you |
+ // use may suddenly become invalid out from under you. For this reason, |
+ // it's best to use this only for slow but simple operations like the DNS |
jar (doing other things)
2011/11/23 20:08:16
DNS might not be a good example. DNS probably nee
|
+ // example. |
+ CONTINUE_ON_SHUTDOWN, |
+ |
+ // Tasks posted with this mode that have not started executing at shutdown |
+ // will be deleted rather than executed. However, tasks already in progress |
+ // will be completed. |
jar (doing other things)
2011/11/23 20:08:16
What is the alternative to "will be completed?" T
|
+ SKIP_ON_SHUTDOWN, |
+ |
+ // Tasks posted with this mode will block browser shutdown until they're |
+ // executed. Since this can have significant performance implications, use |
+ // sparingly. |
+ // |
+ // Generally, this should be used only for user data, for example, a task |
+ // writing a preference file. |
+ // |
+ // If a task is posted during shutdown, it will not get run since the |
jar (doing other things)
2011/11/23 20:08:16
Just to be clear... I think your rule is: "If this
|
+ // workers may already be stopped. In this case, the post operation will |
+ // fail (return false) and the task will be deleted. |
+ BLOCK_SHUTDOWN, |
+ }; |
+ |
+ // Opaque identifier that defines sequencing of tasks posted to the worker |
+ // pool. See NewSequenceToken(). |
+ class SequenceToken { |
+ public: |
+ SequenceToken() : id_(0) {} |
+ ~SequenceToken() {} |
+ |
+ private: |
+ friend SequencedWorkerPool; |
+ |
+ SequenceToken(int id) : id_(id) {} |
+ |
+ int id_; |
+ }; |
+ |
+ // Allows tests to perform certain actions. |
+ class TestingObserver { |
+ public: |
+ virtual void WillWaitForShutdown() = 0; |
+ }; |
+ |
+ SequencedWorkerPool(size_t max_threads); |
+ ~SequencedWorkerPool(); |
+ |
+ // Returns a unique token that can be used to sequence tasks posted to |
+ // PostSequencedWorkerTask(). Valid tokens are alwys nonzero. |
+ SequenceToken GetSequenceToken(); |
+ |
+ // Posts the given task for execution in the worker pool. Tasks posted with |
+ // this function will execute in an unspecified order on a background thread. |
+ // Returns true if the task was posted. If your tasks have ordering |
+ // requirements, see PostSequencedWorkerTask(). |
+ // |
+ // Returns true if the task was posted successfully. This may fail during |
+ // shutdown regardless of the specified ShutdownBehavior. |
+ bool PostWorkerTask(WorkerShutdown shutdown_behavior, |
+ const tracked_objects::Location& from_here, |
+ const base::Closure& task); |
+ |
+ // Like PostWorkerTask above, but provides sequencing semantics. This means |
+ // that tasks posted with the same sequence token (see GetSequenceToken()) |
+ // are guaranteed to execute in order. This is useful in cases where you're |
+ // doing operations that may depend on previous ones, like appending to a |
+ // file. |
+ // |
+ // Returns true if the task was posted successfully. This may fail during |
+ // shutdown regardless of the specified ShutdownBehavior. |
+ bool PostSequencedWorkerTask(SequenceToken sequence_token, |
+ WorkerShutdown shutdown_behavior, |
+ const tracked_objects::Location& from_here, |
+ const base::Closure& task); |
jar (doing other things)
2011/11/23 20:08:16
I'm still feeling the arg order is wrong. I think
|
+ |
+ // Implements the worker pool shutdown. This should be called during app |
+ // shutdown, and will discard/join with appropriate tasks before returning. |
+ // After this call, subsequent calls to post tasks will fail. |
+ void Shutdown(); |
+ |
+ // Called by tests to set the testing observer. This is NULL by default |
+ // and ownership of the pointer is kept with the caller. |
+ void SetTestingObserver(TestingObserver* observer); |
+ |
+ private: |
+ class Inner; |
+ scoped_refptr<Inner> inner_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(SequencedWorkerPool); |
+}; |
+ |
+#endif // CONTENT_COMMON_SEQUENCED_WORKER_POOL_H_ |