Index: base/worker_pool_job.h |
diff --git a/base/worker_pool_job.h b/base/worker_pool_job.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..758c85dfd2936bcdf200dc9f38c5db8063d8b3c7 |
--- /dev/null |
+++ b/base/worker_pool_job.h |
@@ -0,0 +1,141 @@ |
+// Copyright (c) 2010 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 BASE_WORKER_POOL_JOB_H_ |
+#define BASE_WORKER_POOL_JOB_H_ |
+#pragma once |
+ |
+#include "base/basictypes.h" |
+#include "base/lock.h" |
+#include "base/message_loop_proxy.h" |
+#include "base/ref_counted.h" |
+#include "base/thread_checker.h" |
+ |
+class MessageLoop; |
+ |
+namespace base { |
+ |
+// WARNING: Are you sure you want to use WorkerPool in the first place? The |
+// thread will _not_ be joined, so the job may still be running during shutdown. |
+// Global objects that are deleted by AtExitManager should not be accessed on |
+// the WorkerPool thread, otherwise there is potential for shutdown crashes. |
+// |
+// WorkerPoolJob is a helper class for implementing jobs that get created on an |
+// origin thread, get posted to run on a WorkerPool thread, and then run back on |
+// the origin thread upon completion. WorkerPoolJob also handles cancellation |
+// of a job which prevents it from calling back. Note that we use inheritance |
+// rather than composition here, since WorkerPoolJob also handles lifetime |
+// management via refcounting. |
+class WorkerPoolJob : public base::RefCountedThreadSafe<WorkerPoolJob> { |
+ public: |
+ // ScopedHandle is provided to automate cancellation of the WorkerPoolJob. |
+ template <typename JobType> |
eroman
2010/12/22 00:51:47
Why is this templatized?
Since this is already a
willchan no longer on Chromium
2010/12/22 02:04:01
The job() accessor needs the templated param to co
|
+ class ScopedHandle { |
+ public: |
+ explicit ScopedHandle(JobType* job) : job_(job) {} |
+ |
+ ~ScopedHandle() { |
+ AutoLock auto_lock(job_->lock_); |
+ if (!job_->canceled_ && job_->state_ > NONE && |
+ job_->state_ < CANCELED_ON_WORKER) |
+ job_->canceled_ = true; |
+ } |
+ |
+ JobType* job() const { return job_.get(); } |
+ |
+ private: |
+ const scoped_refptr<JobType> job_; |
+ DISALLOW_COPY_AND_ASSIGN(ScopedHandle); |
+ }; |
+ |
+ protected: |
+ explicit WorkerPoolJob(bool is_slow); |
eroman
2010/12/22 00:51:47
I think we should get rid of this bool.
No consum
willchan no longer on Chromium
2010/12/22 02:04:01
Done.
|
+ virtual ~WorkerPoolJob(); |
eroman
2010/12/22 00:51:47
Please stress somewhere that subclasses MUST be pr
willchan no longer on Chromium
2010/12/22 02:04:01
Done.
|
+ |
+ // Starts the job. Will post itself to the WorkerPool, where it will invoke |
+ // RunJob(). After RunJob() runs, it will post itself back to the origin |
+ // thread, where it will invoke CompleteJob(). This can only be called once |
+ // and must be called on the origin thread. |
+ void StartJob(); |
+ |
+ // Cancels the job. CompleteJob() is guaranteed not to be called when this |
+ // happens. RunJob() may or may not be called, depending on when CancelJob() |
+ // is called. it's fundamentally a race. When cancellation is detected (may |
eroman
2010/12/22 00:51:47
it's --> It's
willchan no longer on Chromium
2010/12/22 02:04:01
Done.
|
+ // be on the WorkerPool thread or the origin thread), OnCanceled() is invoked. |
eroman
2010/12/22 00:51:47
Perhaps a more succinct description is to say that
willchan no longer on Chromium
2010/12/22 02:04:01
I'm going to wait until we settle the cancellation
|
+ // This can only be called once and must be called on the origin thread. It |
+ // should only be called after StartJob() is called and before |
+ // CompleteJob() is called (if it is called). |
+ void CancelJob(); |
+ |
+ // Returns true if CancelJob() has been called. |
+ bool canceled() const; |
+ |
+ // Returns true if the job is running on the worker thread. Obviously if it |
+ // returns true once, there's still no guarantee that it is still running |
+ // after it returns. Once it returns false though, then it's guaranteed to |
+ // stay false. is_running() is only allowed to be called on the origin |
+ // thread. |
+ bool is_running() const; |
+ |
+ // NOTE(willchan): I've restricted this to unit tests only, primarily because |
+ // I haven't found a good reason for allowing subtypes to access this. If |
+ // there is a motivating reason to do so, I am open to it. |
+#if defined(UNIT_TEST) |
+ scoped_refptr<MessageLoopProxy> origin_loop() const { |
+ return origin_loop_; |
+ } |
+#endif // defined(UNIT_TEST) |
+ |
+ private: |
+ friend class base::RefCountedThreadSafe<WorkerPoolJob>; |
+ template <typename JobType> friend class ScopedHandle; |
+ |
+ // State machine, primarily for enforcing that certain events only happen |
+ // once. Also lets us implement is_running(). |
+ enum State { |
+ NONE, |
+ RUNNING, |
+ FINISHING, |
+ CANCELED_ON_WORKER, |
+ DONE, |
+ }; |
+ |
+ // API for subtypes to implement. |
+ |
+ // RunJob() runs on the worker thread. If CancelJob() is called on the origin |
+ // thread , then it may never be invoked, but that's a race. |
+ virtual void RunJob() = 0; |
eroman
2010/12/22 00:51:47
Listing pure virtual methods under private section
willchan no longer on Chromium
2010/12/22 02:04:01
No, it's more correct to make them private. That
|
+ |
+ // CompleteJob() runs on the origin thread. If CancelJob() is called, then it |
+ // may never be invoked. |
+ virtual void CompleteJob() = 0; |
+ |
+ // OnCanceled() may be called on either the WorkerPool thread or the origin |
+ // thread. |
+ virtual void OnCanceled() {} |
eroman
2010/12/22 00:51:47
Please, no.
First of all, I don't like default vi
willchan no longer on Chromium
2010/12/22 02:04:01
I share your concerns here. I did it just because
|
+ |
+ void RunJobOnWorkerPool(); |
+ void CompleteJobOnOriginLoop(); |
+ |
+ // Returns true after StartJob() has been called. Only valid to be called on |
+ // the origin thread. |
+ bool started() const; |
+ |
+ // Returns true after job completes successfully or has been canceled. |
+ bool done() const; |
+ |
+ ThreadChecker thread_checker_; |
+ const scoped_refptr<MessageLoopProxy> origin_loop_; |
+ const bool is_slow_; |
+ |
+ mutable Lock lock_; // Protects all member variables below. |
+ bool canceled_; |
+ State state_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(WorkerPoolJob); |
+}; |
+ |
+} // namespace base |
+ |
+#endif // BASE_WORKER_POOL_JOB_H_ |