blob: 4058aa5e89199918caf688801d8d158210a1b27a [file] [log] [blame]
toyoshimccb8ff92017-06-13 05:31:46 -07001// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef MEDIA_MIDI_TASK_SERVICE_H_
6#define MEDIA_MIDI_TASK_SERVICE_H_
7
8#include "base/callback_forward.h"
9#include "base/macros.h"
10#include "base/memory/ref_counted.h"
11#include "base/single_thread_task_runner.h"
12#include "base/synchronization/lock.h"
13#include "base/threading/thread.h"
14#include "base/time/time.h"
15#include "media/midi/midi_export.h"
16
17namespace midi {
18
19// TaskService manages TaskRunners that can be used in midi and provides
20// functionalities to ensure thread safety.
21class MIDI_EXPORT TaskService final {
22 public:
23 using RunnerId = size_t;
24 using InstanceId = int;
25
26 static constexpr RunnerId kDefaultRunnerId = 0;
27
28 TaskService();
29 ~TaskService();
30
31 // Issues an InstanceId internally to post tasks via PostBoundTask() and
32 // PostDelayedBoundTask() with the InstanceId. Once UnbindInstance() is
33 // called, tasks posted via these methods with unbind InstanceId won't be
34 // invoked any more.
35 // Returns true if call is bound or unbound correctly. Otherwise returns
36 // false, that happens when the BindInstance() is called twice without
37 // unbinding the previous instance.
38 bool BindInstance();
39 bool UnbindInstance();
40
41 // Posts a task to run on a specified TaskRunner. |runner_id| should be
42 // kDefaultRunnerId or a positive number. If kDefaultRunnerId is specified
43 // the task runs on the thread on which BindInstance() is called. Other number
44 // will run the task on a dedicated thread that is bound to the |runner_id|.
45 void PostStaticTask(RunnerId runner_id, base::OnceClosure task);
46
47 // Posts a task to run on a specified TaskRunner, and ensures that the bound
48 // instance should not quit UnbindInstance() while a bound task is running.
49 // See PostStaticTask() for |runner_id|.
50 void PostBoundTask(RunnerId runner, base::OnceClosure task);
51 void PostBoundDelayedTask(RunnerId runner_id,
52 base::OnceClosure task,
53 base::TimeDelta delay);
54
55 private:
56 // Returns a SingleThreadTaskRunner reference. Each TaskRunner will be
57 // constructed on demand.
58 scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(RunnerId runner_id);
59
60 // Helps to run a posted bound task on TaskRunner safely.
61 void RunTask(InstanceId instance_id,
62 RunnerId runner_id,
63 base::OnceClosure task);
64
65 // Keeps a TaskRunner for the thread that calls BindInstance() as a default
66 // task runner to run posted tasks.
67 scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
68
69 // Holds threads to host SingleThreadTaskRunners.
70 std::vector<std::unique_ptr<base::Thread>> threads_;
71
72 // Holds lock objects to ensure that tasks run while the instance is bound.
73 std::vector<std::unique_ptr<base::Lock>> thread_task_locks_;
74
75 // Holds InstanceId for the next bound instance.
76 InstanceId next_instance_id_;
77
78 // Holds InstanceId for the current bound instance.
79 InstanceId bound_instance_id_;
80
81 // Protects |next_instance_id_| and |bound_instance_id_|.
82 base::Lock instance_lock_;
83
84 // Protects all other members.
85 base::Lock lock_;
86
87 // If multiple locks should be obtained simultaneously, we should acquire them
88 // in the order below so to avoid deadklocks.
89 // |instance_lock_| -> |lock_| -> |(one of) thread_task_locks_|.
90
91 DISALLOW_COPY_AND_ASSIGN(TaskService);
92};
93
94}; // namespace midi
95
96#endif // MEDIA_MIDI_TASK_SERVICE_H_