Chromium Code Reviews| 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_ |