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