• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter 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 FLUTTER_FML_MESSAGE_LOOP_TASK_QUEUES_H_
6 #define FLUTTER_FML_MESSAGE_LOOP_TASK_QUEUES_H_
7 
8 #include <map>
9 #include <mutex>
10 #include <vector>
11 
12 #include "flutter/fml/closure.h"
13 #include "flutter/fml/delayed_task.h"
14 #include "flutter/fml/macros.h"
15 #include "flutter/fml/memory/ref_counted.h"
16 #include "flutter/fml/synchronization/thread_annotations.h"
17 #include "flutter/fml/wakeable.h"
18 
19 namespace fml {
20 
21 class TaskQueueId {
22  public:
23   static const size_t kUnmerged;
24 
TaskQueueId(size_t value)25   explicit TaskQueueId(size_t value) : value_(value) {}
26 
27   operator int() const { return value_; }
28 
29  private:
30   size_t value_ = kUnmerged;
31 };
32 
33 static const TaskQueueId _kUnmerged = TaskQueueId(ULONG_MAX);
34 
35 // This is keyed by the |TaskQueueId| and contains all the queue
36 // components that make up a single TaskQueue.
37 class TaskQueueEntry {
38  public:
39   using TaskObservers = std::map<intptr_t, fml::closure>;
40   Wakeable* wakeable;
41   TaskObservers task_observers;
42   DelayedTaskQueue delayed_tasks;
43 
44   // Note: Both of these can be _kUnmerged, which indicates that
45   // this queue has not been merged or subsumed. OR exactly one
46   // of these will be _kUnmerged, if owner_of is _kUnmerged, it means
47   // that the queue has been subsumed or else it owns another queue.
48   TaskQueueId owner_of;
49   TaskQueueId subsumed_by;
50 
51   TaskQueueEntry();
52 
53  private:
54   FML_DISALLOW_COPY_ASSIGN_AND_MOVE(TaskQueueEntry);
55 };
56 
57 enum class FlushType {
58   kSingle,
59   kAll,
60 };
61 
62 // This class keeps track of all the tasks and observers that
63 // need to be run on it's MessageLoopImpl. This also wakes up the
64 // loop at the required times.
65 class MessageLoopTaskQueues
66     : public fml::RefCountedThreadSafe<MessageLoopTaskQueues> {
67  public:
68   // Lifecycle.
69 
70   static fml::RefPtr<MessageLoopTaskQueues> GetInstance();
71 
72   TaskQueueId CreateTaskQueue();
73 
74   void Dispose(TaskQueueId queue_id);
75 
76   void DisposeTasks(TaskQueueId queue_id);
77 
78   // Tasks methods.
79 
80   void RegisterTask(TaskQueueId queue_id,
81                     fml::closure task,
82                     fml::TimePoint target_time);
83 
84   bool HasPendingTasks(TaskQueueId queue_id) const;
85 
86   void GetTasksToRunNow(TaskQueueId queue_id,
87                         FlushType type,
88                         std::vector<fml::closure>& invocations);
89 
90   size_t GetNumPendingTasks(TaskQueueId queue_id) const;
91 
92   // Observers methods.
93 
94   void AddTaskObserver(TaskQueueId queue_id,
95                        intptr_t key,
96                        fml::closure callback);
97 
98   void RemoveTaskObserver(TaskQueueId queue_id, intptr_t key);
99 
100   std::vector<fml::closure> GetObserversToNotify(TaskQueueId queue_id) const;
101 
102   // Misc.
103 
104   void SetWakeable(TaskQueueId queue_id, fml::Wakeable* wakeable);
105 
106   // Invariants for merge and un-merge
107   //  1. RegisterTask will always submit to the queue_id that is passed
108   //     to it. It is not aware of whether a queue is merged or not. Same with
109   //     task observers.
110   //  2. When we get the tasks to run now, we look at both the queue_ids
111   //     for the owner, subsumed will spin.
112   //  3. Each task queue can only be merged and subsumed once.
113   //
114   //  Methods currently aware of the merged state of the queues:
115   //  HasPendingTasks, GetTasksToRunNow, GetNumPendingTasks
116 
117   // This method returns false if either the owner or subsumed has already been
118   // merged with something else.
119   bool Merge(TaskQueueId owner, TaskQueueId subsumed);
120 
121   // Will return false if the owner has not been merged before.
122   bool Unmerge(TaskQueueId owner);
123 
124   // Returns true if owner owns the subsumed task queue.
125   bool Owns(TaskQueueId owner, TaskQueueId subsumed) const;
126 
127  private:
128   class MergedQueuesRunner;
129 
130   MessageLoopTaskQueues();
131 
132   ~MessageLoopTaskQueues();
133 
134   void WakeUpUnlocked(TaskQueueId queue_id, fml::TimePoint time) const;
135 
136   bool HasPendingTasksUnlocked(TaskQueueId queue_id) const;
137 
138   const DelayedTask& PeekNextTaskUnlocked(TaskQueueId queue_id,
139                                           TaskQueueId& top_queue_id) const;
140 
141   fml::TimePoint GetNextWakeTimeUnlocked(TaskQueueId queue_id) const;
142 
143   static std::mutex creation_mutex_;
144   static fml::RefPtr<MessageLoopTaskQueues> instance_
145       FML_GUARDED_BY(creation_mutex_);
146 
147   mutable std::mutex queue_mutex_;
148   std::map<TaskQueueId, std::unique_ptr<TaskQueueEntry>> queue_entries_;
149   size_t task_queue_id_counter_;
150 
151   std::atomic_int order_;
152 
153   FML_FRIEND_MAKE_REF_COUNTED(MessageLoopTaskQueues);
154   FML_FRIEND_REF_COUNTED_THREAD_SAFE(MessageLoopTaskQueues);
155   FML_DISALLOW_COPY_ASSIGN_AND_MOVE(MessageLoopTaskQueues);
156 };
157 
158 }  // namespace fml
159 
160 #endif  // FLUTTER_FML_MESSAGE_LOOP_TASK_QUEUES_H_
161