• 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 <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