Chromium Code Reviews| Index: base/task_scheduler/task_traits.h |
| diff --git a/base/task_scheduler/task_traits.h b/base/task_scheduler/task_traits.h |
| index 47e9b81eeecd46877ffb4f71a42d173b04aa35b8..84499d550468837e95f923d782116e854641ca64 100644 |
| --- a/base/task_scheduler/task_traits.h |
| +++ b/base/task_scheduler/task_traits.h |
| @@ -8,6 +8,7 @@ |
| #include <stdint.h> |
| #include <iosfwd> |
| +#include <utility> |
| #include "base/base_export.h" |
| #include "build/build_config.h" |
| @@ -77,72 +78,159 @@ enum class TaskShutdownBehavior { |
| BLOCK_SHUTDOWN, |
| }; |
| +// Tasks with this trait may block. This includes but is not limited to tasks |
| +// that wait on synchronous file I/O operations: read or write a file from disk, |
| +// interact with a pipe or a socket, rename or delete a file, enumerate files in |
| +// a directory, etc. This trait isn't required for the mere use of locks. For |
| +// tasks that block on base/ synchronization primitives, see |
| +// WithBaseSyncPrimitives(). |
| +struct MayBlock {}; |
| + |
| +// Tasks with this trait will pass base::AssertWaitAllowed(), i.e. will be |
| +// allowed on the following methods : |
| +// - base::WaitableEvent::Wait |
| +// - base::ConditionVariable::Wait |
| +// - base::PlatformThread::Join |
| +// - base::PlatformThread::Sleep |
| +// - base::Process::WaitForExit |
| +// - base::Process::WaitForExitWithTimeout |
| +// |
| +// Tasks should generally not use these methods. |
| +// |
| +// Instead of waiting on a WaitableEvent or a ConditionVariable, put the work |
| +// that should happen after the wait in a callback and post that callback from |
| +// where the WaitableEvent or ConditionVariable would have been signaled. If |
| +// something needs to be scheduled after many tasks have executed, use |
| +// base::BarrierClosure. |
| +// |
| +// Avoid creating threads. Instead, use |
| +// base::Create(Sequenced|SingleTreaded)TaskRunnerWithTraits(). If a thread is |
| +// really needed, make it non-joinable and add cleanup work at the end of the |
| +// thread's main function (if using base::Thread, override Cleanup()). |
| +// |
| +// On Windows, join processes asynchronously using base::win::ObjectWatcher. |
| +// |
| +// MayBlock() must be specified in conjunction with this trait if and only if |
| +// removing usage of methods listed above in the labeled tasks would still |
| +// result in tasks that may block (per MayBlock()'s definition). |
| +// |
| +// In doubt, consult with //base/task_scheduler/OWNERS. |
| +struct WithBaseSyncPrimitives {}; |
| + |
| +namespace internal { |
| + |
| +// When the following call is made: |
| +// GetTraitFromArgList(CallFirstTag(), GetterType(), args...); |
| +// The compiler prefers using the 3rd overload of GetTraitFromArgList(), because |
| +// the type of the first argument matches exactly. That overload uses |
| +// Getter::operator()(FirstArgType) to transform |first_arg| into a value that |
| +// can be used to initialize a member of TaskTraits. If |
| +// Getter::operator()(FirstArgType) isn't defined, the compiler uses the 1st or |
| +// the 2nd overload instead (depending on whether |args| is empty). The 1st |
| +// overload returns a default value. The 2nd overload discards |first_arg| and |
| +// calls back GetTraitFromArgList() with CallFirstTag() as first argument. |
|
gab
2017/04/25 17:48:14
Can you give a concrete example of the resolution
fdoray
2017/04/26 17:20:33
Improved documentation.
|
| +struct CallSecondTag {}; |
| +struct CallFirstTag : CallSecondTag {}; |
| + |
| +// Overload 1: Default value. |
| +template <class GetterType> |
| +constexpr auto GetTraitFromArgList(CallSecondTag, GetterType getter) |
| + -> decltype(getter()) { |
| + return getter(); |
| +} |
| + |
| +// Overload 2: Discard first arg. |
| +template <class GetterType, class FirstArgType, class... ArgTypes> |
| +constexpr auto GetTraitFromArgList(CallSecondTag, |
| + GetterType getter, |
| + const FirstArgType&, |
| + const ArgTypes&... args) |
| + -> decltype(GetTraitFromArgList(CallFirstTag(), getter, args...)) { |
| + return GetTraitFromArgList(CallFirstTag(), getter, args...); |
| +} |
| + |
| +// Overload 3: Get value of TaskTraits member from first arg. |
| +template <class GetterType, |
| + class FirstArgType, |
| + class... ArgTypes, |
| + class Instantiation = decltype( |
| + std::declval<GetterType>()(std::declval<FirstArgType>()))> |
| +constexpr typename GetterType::MemberType GetTraitFromArgList( |
| + CallFirstTag, |
| + GetterType getter, |
| + const FirstArgType& first_arg, |
| + const ArgTypes&...) { |
| + return getter(first_arg); |
| +} |
| + |
| +template <typename ArgType> |
| +struct BooleanArgGetterType { |
| + using MemberType = bool; |
| + constexpr MemberType operator()(ArgType) const { return true; } |
| + constexpr MemberType operator()() const { return false; } |
| +}; |
| + |
| +template <typename ArgType, ArgType DefaultValue> |
| +struct EnumArgGetterType { |
| + using MemberType = ArgType; |
| + constexpr MemberType operator()(ArgType arg) const { return arg; } |
| + constexpr MemberType operator()() const { return DefaultValue; } |
| +}; |
| + |
| +} // namespace internal |
| + |
| // Describes metadata for a single task or a group of tasks. |
| class BASE_EXPORT TaskTraits { |
| public: |
| - // Constructs a default TaskTraits for tasks that |
| + // Invoking this constructor without arguments produces TaskTraits that are |
| + // appropriate for tasks that |
| // (1) don't block (ref. MayBlock() and WithBaseSyncPrimitives()), |
| // (2) prefer inheriting the current priority to specifying their own, and |
| // (3) can either block shutdown or be skipped on shutdown |
| // (TaskScheduler implementation is free to choose a fitting default). |
| - // Tasks that require stricter guarantees and/or know the specific |
| - // TaskPriority appropriate for them should highlight those by requesting |
| - // explicit traits below. |
| - TaskTraits(); |
| - TaskTraits(const TaskTraits& other) = default; |
| - TaskTraits& operator=(const TaskTraits& other) = default; |
| - ~TaskTraits(); |
| - |
| - // Tasks with this trait may block. This includes but is not limited to tasks |
| - // that wait on synchronous file I/O operations: read or write a file from |
| - // disk, interact with a pipe or a socket, rename or delete a file, enumerate |
| - // files in a directory, etc. This trait isn't required for the mere use of |
| - // locks. For tasks that block on base/ synchronization primitives, see |
| - // WithBaseSyncPrimitives(). |
| - TaskTraits& MayBlock(); |
| - |
| - // Tasks with this trait will pass base::AssertWaitAllowed(), i.e. will be |
| - // allowed on the following methods : |
| - // - base::WaitableEvent::Wait |
| - // - base::ConditionVariable::Wait |
| - // - base::PlatformThread::Join |
| - // - base::PlatformThread::Sleep |
| - // - base::Process::WaitForExit |
| - // - base::Process::WaitForExitWithTimeout |
| - // |
| - // Tasks should generally not use these methods. |
| // |
| - // Instead of waiting on a WaitableEvent or a ConditionVariable, put the work |
| - // that should happen after the wait in a callback and post that callback from |
| - // where the WaitableEvent or ConditionVariable would have been signaled. If |
| - // something needs to be scheduled after many tasks have executed, use |
| - // base::BarrierClosure. |
| + // To get TaskTraits for tasks that require stricter guarantees and/or know |
| + // the specific TaskPriority appropriate for them, provide arguments of type |
| + // TaskPriority, TaskShutdownBehavior, MayBlock and/or WithBaseSyncPrimitives |
| + // in any order to the constructor. |
| // |
| - // Avoid creating threads. Instead, use |
| - // base::Create(Sequenced|SingleTreaded)TaskRunnerWithTraits(). If a thread is |
| - // really needed, make it non-joinable and add cleanup work at the end of the |
| - // thread's main function (if using base::Thread, override Cleanup()). |
| - // |
| - // On Windows, join processes asynchronously using base::win::ObjectWatcher. |
| - // |
| - // MayBlock() must be specified in conjunction with this trait if and only if |
| - // removing usage of methods listed above in the labeled tasks would still |
| - // result in tasks that may block (per MayBlock()'s definition). |
| - // |
| - // In doubt, consult with //base/task_scheduler/OWNERS. |
| - TaskTraits& WithBaseSyncPrimitives(); |
| + // E.g. |
| + // constexpr TaskTraits default_traits; |
| + // constexpr TaskTraits user_visible_traits = {TaskPriority::USER_VISIBLE}; |
| + // constexpr TaskTraits user_visible_may_block_traits = { |
| + // TaskPriority::USER_VISIBLE, MayBlock()}; |
| + // constexpr TaskTraits other_user_visible_may_block_traits = { |
| + // MayBlock(), TaskPriority::USER_VISIBLE}; |
| + template <class... ArgTypes> |
| + constexpr TaskTraits(const ArgTypes&... args) |
| + : priority_(internal::GetTraitFromArgList( |
| + internal::CallFirstTag(), |
| + internal::EnumArgGetterType<base::TaskPriority, |
| + base::TaskPriority::INHERITED>(), |
| + args...)), |
| + shutdown_behavior_(internal::GetTraitFromArgList( |
| + internal::CallFirstTag(), |
| + internal::EnumArgGetterType< |
| + base::TaskShutdownBehavior, |
| + base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN>(), |
| + args...)), |
| + may_block_(internal::GetTraitFromArgList( |
| + internal::CallFirstTag(), |
| + internal::BooleanArgGetterType<base::MayBlock>(), |
| + args...)), |
| + with_base_sync_primitives_(internal::GetTraitFromArgList( |
| + internal::CallFirstTag(), |
| + internal::BooleanArgGetterType<base::WithBaseSyncPrimitives>(), |
| + args...)) {} |
| - // Applies |priority| to tasks with these traits. |
| - TaskTraits& WithPriority(TaskPriority priority); |
| + constexpr TaskTraits(const TaskTraits& other) = default; |
| + TaskTraits& operator=(const TaskTraits& other) = default; |
| - // Applies |shutdown_behavior| to tasks with these traits. |
| + // Deprecated. |
| + TaskTraits& WithPriority(TaskPriority priority); |
| TaskTraits& WithShutdownBehavior(TaskShutdownBehavior shutdown_behavior); |
| - |
| - // Returns true if tasks with these traits may block. |
| - bool may_block() const { return may_block_; } |
| - |
| - // Returns true if tasks with these traits may use base/ sync primitives. |
| - bool with_base_sync_primitives() const { return with_base_sync_primitives_; } |
| + TaskTraits& MayBlock(); |
| + TaskTraits& WithBaseSyncPrimitives(); |
| // Returns the priority of tasks with these traits. |
| TaskPriority priority() const { return priority_; } |
| @@ -150,11 +238,17 @@ class BASE_EXPORT TaskTraits { |
| // Returns the shutdown behavior of tasks with these traits. |
| TaskShutdownBehavior shutdown_behavior() const { return shutdown_behavior_; } |
| + // Returns true if tasks with these traits may block. |
| + bool may_block() const { return may_block_; } |
| + |
| + // Returns true if tasks with these traits may use base/ sync primitives. |
| + bool with_base_sync_primitives() const { return with_base_sync_primitives_; } |
| + |
| private: |
| - bool may_block_; |
| - bool with_base_sync_primitives_; |
| TaskPriority priority_; |
| TaskShutdownBehavior shutdown_behavior_; |
| + bool may_block_; |
| + bool with_base_sync_primitives_; |
| }; |
| // Returns string literals for the enums defined in this file. These methods |