blob: 4058aa5e89199918caf688801d8d158210a1b27a [file] [log] [blame]
// 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 "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.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 = int;
static constexpr RunnerId kDefaultRunnerId = 0;
TaskService();
~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.
bool BindInstance();
bool UnbindInstance();
// Posts a task to run on a specified TaskRunner. |runner_id| should be
// kDefaultRunnerId or a positive number. If kDefaultRunnerId is specified
// the task runs on the thread on which BindInstance() is called. Other number
// will run the task on a dedicated thread that is bound to the |runner_id|.
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.
// See PostStaticTask() for |runner_id|.
void PostBoundTask(RunnerId runner, base::OnceClosure task);
void PostBoundDelayedTask(RunnerId runner_id,
base::OnceClosure task,
base::TimeDelta delay);
private:
// Returns a SingleThreadTaskRunner reference. Each TaskRunner will be
// constructed on demand.
scoped_refptr<base::SingleThreadTaskRunner> 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);
// Keeps a TaskRunner for the thread that calls BindInstance() as a default
// task runner to run posted tasks.
scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
// Holds threads to host SingleThreadTaskRunners.
std::vector<std::unique_ptr<base::Thread>> threads_;
// Holds lock objects to ensure that tasks run while the instance is bound.
std::vector<std::unique_ptr<base::Lock>> thread_task_locks_;
// Holds InstanceId for the next bound instance.
InstanceId next_instance_id_;
// Holds InstanceId for the current bound instance.
InstanceId bound_instance_id_;
// Protects |next_instance_id_| and |bound_instance_id_|.
base::Lock instance_lock_;
// Protects all other members.
base::Lock lock_;
// If multiple locks should be obtained simultaneously, we should acquire them
// in the order below so to avoid deadklocks.
// |instance_lock_| -> |lock_| -> |(one of) thread_task_locks_|.
DISALLOW_COPY_AND_ASSIGN(TaskService);
};
}; // namespace midi
#endif // MEDIA_MIDI_TASK_SERVICE_H_