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..5323bc281910f570118689148f47ae6967129ab2 100644 |
--- a/base/task_scheduler/task_traits.h |
+++ b/base/task_scheduler/task_traits.h |
@@ -8,6 +8,8 @@ |
#include <stdint.h> |
#include <iosfwd> |
+#include <type_traits> |
+#include <utility> |
#include "base/base_export.h" |
#include "build/build_config.h" |
@@ -77,72 +79,180 @@ 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(). |
robliao
2017/04/21 18:02:06
WithBaseSyncPrimitives() -> the WithBaseSyncPrimit
fdoray
2017/04/21 20:35:20
Done.
|
+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 |
robliao
2017/04/21 18:02:06
This guidance should probably be placed somewhere
fdoray
2017/04/21 20:35:20
Done. Writing a CL that adds it to base::Thread/ba
fdoray
2017/04/21 20:43:18
https://codereview.chromium.org/2834783004/
|
+// 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 { |
robliao
2017/04/21 18:02:06
Place this is task_traits_details.h or task_traits
robliao
2017/04/21 18:03:13
Wow, that didn't come out right at all.
Place this
fdoray
2017/04/21 20:35:19
Done.
|
+ |
+// CheckNoArgOfType() generates a compile-time error if it receives an argument |
+// of type UnwantedType. The 2nd overload checks the type of the first argument |
robliao
2017/04/21 18:02:06
Nit: 2nd -> second and 1st -> first
fdoray
2017/04/21 20:35:19
Done.
|
+// and makes a recursive call with the remaining arguments. The 1st overload |
+// takes no argument and is used to end the recursion. Both overloads return a |
+// bool because it is invalid for a constexpr function to return void. |
+template <class UnwantedType> |
+constexpr bool CheckNoArgOfType() { |
+ return true; |
+} |
+ |
+template <class UnwantedType, class FirstArgType, class... ArgTypes> |
+constexpr bool CheckNoArgOfType(const FirstArgType&, const ArgTypes&... args) { |
+ static_assert(!std::is_same<UnwantedType, FirstArgType>::value, |
+ "Multiple arguments of the same type were provided to the " |
+ "constructor of TaskTraits."); |
+ return CheckNoArgOfType<UnwantedType>(args...); |
+} |
+ |
+// When the following call is made: |
+// GetValueFromArgList(CallFirstTag(), GetterType(), args...); |
+// The compiler prefers using the 3rd overload of GetValueFromArgList(), because |
+// the type of the first argument matches exactly. That overload uses |
+// Getter::operator()(FirstArgType) to extract a value from |first_arg|. 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 obtained from Getter::operator()(). The 2nd |
+// overload discards |first_arg| and calls back GetValueFromArgList() with |
+// CallFirstTag() as first argument. |
+struct CallSecondTag {}; |
+struct CallFirstTag : CallSecondTag {}; |
+ |
+// Overload 1: Default value. |
+template <class GetterType> |
+constexpr auto GetValueFromArgList(CallSecondTag, GetterType getter) |
+ -> decltype(getter()) { |
+ return getter(); |
+} |
+ |
+// Overload 2: Discard first argument. |
+template <class GetterType, class FirstArgType, class... ArgTypes> |
+constexpr auto GetValueFromArgList(CallSecondTag, |
+ GetterType getter, |
+ const FirstArgType&, |
+ const ArgTypes&... args) |
+ -> decltype(GetValueFromArgList(CallFirstTag(), getter, args...)) { |
+ return GetValueFromArgList(CallFirstTag(), getter, args...); |
+} |
+ |
+// Overload 3: Get value from first argument. Check that no argument in |args| |
+// has the same type as |first_arg|. |
+template <class GetterType, |
+ class FirstArgType, |
+ class... ArgTypes, |
+ class Instantiation = decltype( |
+ std::declval<GetterType>()(std::declval<FirstArgType>()))> |
+constexpr typename GetterType::ValueType GetValueFromArgList( |
+ CallFirstTag, |
+ GetterType getter, |
+ const FirstArgType& first_arg, |
+ const ArgTypes&... args) { |
+ // CheckNoArgOfType() is invoked as part of a comma operator statement to |
+ // avoid an unused return value warning. |
+ return CheckNoArgOfType<FirstArgType>(args...), getter(first_arg); |
+} |
+ |
+template <typename ArgType> |
+struct BooleanArgGetter { |
+ using ValueType = bool; |
+ constexpr ValueType operator()(ArgType) const { return true; } |
+ constexpr ValueType operator()() const { return false; } |
+}; |
+ |
+template <typename ArgType, ArgType DefaultValue> |
+struct EnumArgGetter { |
+ using ValueType = ArgType; |
+ constexpr ValueType operator()(ArgType arg) const { return arg; } |
+ constexpr ValueType 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. |
+ // 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. |
// |
- // 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. |
- 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::GetValueFromArgList( |
+ internal::CallFirstTag(), |
+ internal::EnumArgGetter<base::TaskPriority, |
+ base::TaskPriority::INHERITED>(), |
+ args...)), |
+ shutdown_behavior_(internal::GetValueFromArgList( |
+ internal::CallFirstTag(), |
+ internal::EnumArgGetter< |
+ base::TaskShutdownBehavior, |
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN>(), |
+ args...)), |
+ may_block_(internal::GetValueFromArgList( |
+ internal::CallFirstTag(), |
+ internal::BooleanArgGetter<base::MayBlock>(), |
+ args...)), |
+ with_base_sync_primitives_(internal::GetValueFromArgList( |
+ internal::CallFirstTag(), |
+ internal::BooleanArgGetter<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 +260,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 |