// Copyright 2017 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 MEDIA_MIDI_TASK_SERVICE_H_ #define MEDIA_MIDI_TASK_SERVICE_H_ #include #include #include "base/callback_forward.h" #include "base/memory/ref_counted.h" #include "base/sequence_checker.h" #include "base/synchronization/condition_variable.h" #include "base/synchronization/lock.h" #include "base/task/single_thread_task_runner.h" #include "base/thread_annotations.h" #include "base/threading/thread.h" #include "base/time/time.h" #include "media/midi/midi_export.h" namespace midi { // TaskService manages TaskRunners that can be used in midi and provides // functionalities to ensure thread safety. class MIDI_EXPORT TaskService final { public: using RunnerId = size_t; using InstanceId = int64_t; static constexpr RunnerId kDefaultRunnerId = 0; TaskService(); TaskService(const TaskService&) = delete; TaskService& operator=(const TaskService&) = delete; ~TaskService(); // Issues an InstanceId internally to post tasks via PostBoundTask() and // PostDelayedBoundTask() with the InstanceId. Once UnbindInstance() is // called, tasks posted via these methods with unbind InstanceId won't be // invoked any more. // Returns true if call is bound or unbound correctly. Otherwise returns // false, that happens when the BindInstance() is called twice without // unbinding the previous instance, or the UnbindInstance() is called without // any successful BindInstance() call. [[nodiscard]] bool BindInstance(); [[nodiscard]] bool UnbindInstance(); // Checks if the current thread belongs to the specified runner. bool IsOnTaskRunner(RunnerId runner_id); // Posts a task to run on a specified TaskRunner. |runner_id| should be a // positive number that represents a dedicated thread on that |task| will run. // |task| will run even without a bound instance. void PostStaticTask(RunnerId runner_id, base::OnceClosure task); // Posts a task to run on a specified TaskRunner, and ensures that the bound // instance should not quit UnbindInstance() while a bound task is running. // |runner_id| should be |kDefaultRunnerId| or a positive number. If // |kDefaultRunnerId| is specified, the task runs on the thread on which // BindInstance() was called. void PostBoundTask(RunnerId runner, base::OnceClosure task); void PostBoundDelayedTask(RunnerId runner_id, base::OnceClosure task, base::TimeDelta delay); void OverflowInstanceIdForTesting(); private: static constexpr TaskService::InstanceId kInvalidInstanceId = -1; // Returns a SingleThreadTaskRunner reference. Each TaskRunner will be // constructed on demand. scoped_refptr GetTaskRunner(RunnerId runner_id); // Helps to run a posted bound task on TaskRunner safely. void RunTask(InstanceId instance_id, RunnerId runner_id, base::OnceClosure task); // Returns true if |instance_id| is equal to |bound_instance_id_|. bool IsInstanceIdStillBound(InstanceId instance_id); // Holds InstanceId for the next bound instance, accessed on the BindInstance // call thread without any protection. InstanceId next_instance_id_ = kInvalidInstanceId; // Keeps a TaskRunner for the thread that calls BindInstance() as a default // task runner to run posted tasks. scoped_refptr default_task_runner_ GUARDED_BY(lock_); // Holds threads to host SingleThreadTaskRunners. std::vector> threads_ GUARDED_BY(lock_); // Holds InstanceId for the current bound instance. InstanceId bound_instance_id_ GUARDED_BY(lock_) = kInvalidInstanceId; base::Lock lock_; // Signalled when the number of tasks in flight is 0 and ensures that // UnbindInstance() does not return until all tasks have completed. base::ConditionVariable no_tasks_in_flight_cv_ GUARDED_BY(tasks_in_flight_lock_); // Number of tasks in flight. int tasks_in_flight_ GUARDED_BY(tasks_in_flight_lock_) = 0; base::Lock tasks_in_flight_lock_; // Verifies all UnbindInstance() calls occur on the same sequence as // BindInstance(). SEQUENCE_CHECKER(instance_binding_sequence_checker_); }; } // namespace midi #endif // MEDIA_MIDI_TASK_SERVICE_H_