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