michael@0: // Copyright (c) 2012 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #ifndef BASE_SEQUENCED_TASKRUNNER_H_ michael@0: #define BASE_SEQUENCED_TASKRUNNER_H_ michael@0: michael@0: #include "base/base_export.h" michael@0: #include "base/sequenced_task_runner_helpers.h" michael@0: #include "base/task_runner.h" michael@0: michael@0: namespace base { michael@0: michael@0: // A SequencedTaskRunner is a subclass of TaskRunner that provides michael@0: // additional guarantees on the order that tasks are started, as well michael@0: // as guarantees on when tasks are in sequence, i.e. one task finishes michael@0: // before the other one starts. michael@0: // michael@0: // Summary michael@0: // ------- michael@0: // Non-nested tasks with the same delay will run one by one in FIFO michael@0: // order. michael@0: // michael@0: // Detailed guarantees michael@0: // ------------------- michael@0: // michael@0: // SequencedTaskRunner also adds additional methods for posting michael@0: // non-nestable tasks. In general, an implementation of TaskRunner michael@0: // may expose task-running methods which are themselves callable from michael@0: // within tasks. A non-nestable task is one that is guaranteed to not michael@0: // be run from within an already-running task. Conversely, a nestable michael@0: // task (the default) is a task that can be run from within an michael@0: // already-running task. michael@0: // michael@0: // The guarantees of SequencedTaskRunner are as follows: michael@0: // michael@0: // - Given two tasks T2 and T1, T2 will start after T1 starts if: michael@0: // michael@0: // * T2 is posted after T1; and michael@0: // * T2 has equal or higher delay than T1; and michael@0: // * T2 is non-nestable or T1 is nestable. michael@0: // michael@0: // - If T2 will start after T1 starts by the above guarantee, then michael@0: // T2 will start after T1 finishes and is destroyed if: michael@0: // michael@0: // * T2 is non-nestable, or michael@0: // * T1 doesn't call any task-running methods. michael@0: // michael@0: // - If T2 will start after T1 finishes by the above guarantee, then michael@0: // all memory changes in T1 and T1's destruction will be visible michael@0: // to T2. michael@0: // michael@0: // - If T2 runs nested within T1 via a call to the task-running michael@0: // method M, then all memory changes in T1 up to the call to M michael@0: // will be visible to T2, and all memory changes in T2 will be michael@0: // visible to T1 from the return from M. michael@0: // michael@0: // Note that SequencedTaskRunner does not guarantee that tasks are run michael@0: // on a single dedicated thread, although the above guarantees provide michael@0: // most (but not all) of the same guarantees. If you do need to michael@0: // guarantee that tasks are run on a single dedicated thread, see michael@0: // SingleThreadTaskRunner (in single_thread_task_runner.h). michael@0: // michael@0: // Some corollaries to the above guarantees, assuming the tasks in michael@0: // question don't call any task-running methods: michael@0: // michael@0: // - Tasks posted via PostTask are run in FIFO order. michael@0: // michael@0: // - Tasks posted via PostNonNestableTask are run in FIFO order. michael@0: // michael@0: // - Tasks posted with the same delay and the same nestable state michael@0: // are run in FIFO order. michael@0: // michael@0: // - A list of tasks with the same nestable state posted in order of michael@0: // non-decreasing delay is run in FIFO order. michael@0: // michael@0: // - A list of tasks posted in order of non-decreasing delay with at michael@0: // most a single change in nestable state from nestable to michael@0: // non-nestable is run in FIFO order. (This is equivalent to the michael@0: // statement of the first guarantee above.) michael@0: // michael@0: // Some theoretical implementations of SequencedTaskRunner: michael@0: // michael@0: // - A SequencedTaskRunner that wraps a regular TaskRunner but makes michael@0: // sure that only one task at a time is posted to the TaskRunner, michael@0: // with appropriate memory barriers in between tasks. michael@0: // michael@0: // - A SequencedTaskRunner that, for each task, spawns a joinable michael@0: // thread to run that task and immediately quit, and then michael@0: // immediately joins that thread. michael@0: // michael@0: // - A SequencedTaskRunner that stores the list of posted tasks and michael@0: // has a method Run() that runs each runnable task in FIFO order michael@0: // that can be called from any thread, but only if another michael@0: // (non-nested) Run() call isn't already happening. michael@0: class BASE_EXPORT SequencedTaskRunner : public TaskRunner { michael@0: public: michael@0: // The two PostNonNestable*Task methods below are like their michael@0: // nestable equivalents in TaskRunner, but they guarantee that the michael@0: // posted task will not run nested within an already-running task. michael@0: // michael@0: // A simple corollary is that posting a task as non-nestable can michael@0: // only delay when the task gets run. That is, posting a task as michael@0: // non-nestable may not affect when the task gets run, or it could michael@0: // make it run later than it normally would, but it won't make it michael@0: // run earlier than it normally would. michael@0: michael@0: // TODO(akalin): Get rid of the boolean return value for the methods michael@0: // below. michael@0: michael@0: bool PostNonNestableTask(const tracked_objects::Location& from_here, michael@0: const Closure& task); michael@0: michael@0: virtual bool PostNonNestableDelayedTask( michael@0: const tracked_objects::Location& from_here, michael@0: const Closure& task, michael@0: base::TimeDelta delay) = 0; michael@0: michael@0: // Submits a non-nestable task to delete the given object. Returns michael@0: // true if the object may be deleted at some point in the future, michael@0: // and false if the object definitely will not be deleted. michael@0: template michael@0: bool DeleteSoon(const tracked_objects::Location& from_here, michael@0: const T* object) { michael@0: return michael@0: subtle::DeleteHelperInternal::DeleteViaSequencedTaskRunner( michael@0: this, from_here, object); michael@0: } michael@0: michael@0: // Submits a non-nestable task to release the given object. Returns michael@0: // true if the object may be released at some point in the future, michael@0: // and false if the object definitely will not be released. michael@0: template michael@0: bool ReleaseSoon(const tracked_objects::Location& from_here, michael@0: T* object) { michael@0: return michael@0: subtle::ReleaseHelperInternal::ReleaseViaSequencedTaskRunner( michael@0: this, from_here, object); michael@0: } michael@0: michael@0: protected: michael@0: virtual ~SequencedTaskRunner() {} michael@0: michael@0: private: michael@0: template friend class subtle::DeleteHelperInternal; michael@0: template friend class subtle::ReleaseHelperInternal; michael@0: michael@0: bool DeleteSoonInternal(const tracked_objects::Location& from_here, michael@0: void(*deleter)(const void*), michael@0: const void* object); michael@0: michael@0: bool ReleaseSoonInternal(const tracked_objects::Location& from_here, michael@0: void(*releaser)(const void*), michael@0: const void* object); michael@0: }; michael@0: michael@0: } // namespace base michael@0: michael@0: #endif // BASE_SEQUENCED_TASKRUNNER_H_