message_loop_task_queues.h 4.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef FLUTTER_FML_MESSAGE_LOOP_TASK_QUEUES_H_
#define FLUTTER_FML_MESSAGE_LOOP_TASK_QUEUES_H_

#include <map>
#include <mutex>
#include <vector>

#include "flutter/fml/closure.h"
#include "flutter/fml/delayed_task.h"
#include "flutter/fml/macros.h"
#include "flutter/fml/memory/ref_counted.h"
16
#include "flutter/fml/synchronization/shared_mutex.h"
17 18 19 20
#include "flutter/fml/wakeable.h"

namespace fml {

21 22 23 24 25 26 27 28 29 30 31
class TaskQueueId {
 public:
  static const size_t kUnmerged;

  explicit TaskQueueId(size_t value) : value_(value) {}

  operator int() const { return value_; }

 private:
  size_t value_ = kUnmerged;
};
32

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
static const TaskQueueId _kUnmerged = TaskQueueId(TaskQueueId::kUnmerged);

// This is keyed by the |TaskQueueId| and contains all the queue
// components that make up a single TaskQueue.
class TaskQueueEntry {
 public:
  using TaskObservers = std::map<intptr_t, fml::closure>;
  Wakeable* wakeable;
  TaskObservers task_observers;
  DelayedTaskQueue delayed_tasks;

  // Note: Both of these can be _kUnmerged, which indicates that
  // this queue has not been merged or subsumed. OR exactly one
  // of these will be _kUnmerged, if owner_of is _kUnmerged, it means
  // that the queue has been subsumed or else it owns another queue.
  TaskQueueId owner_of;
  TaskQueueId subsumed_by;

  TaskQueueEntry();

 private:
  FML_DISALLOW_COPY_ASSIGN_AND_MOVE(TaskQueueEntry);
};

57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
enum class FlushType {
  kSingle,
  kAll,
};

// This class keeps track of all the tasks and observers that
// need to be run on it's MessageLoopImpl. This also wakes up the
// loop at the required times.
class MessageLoopTaskQueues
    : public fml::RefCountedThreadSafe<MessageLoopTaskQueues> {
 public:
  // Lifecycle.

  static fml::RefPtr<MessageLoopTaskQueues> GetInstance();

  TaskQueueId CreateTaskQueue();

  void Dispose(TaskQueueId queue_id);

76 77
  void DisposeTasks(TaskQueueId queue_id);

78 79 80
  // Tasks methods.

  void RegisterTask(TaskQueueId queue_id,
81
                    const fml::closure& task,
82 83
                    fml::TimePoint target_time);

84
  bool HasPendingTasks(TaskQueueId queue_id) const;
85

86
  fml::closure GetNextTaskToRun(TaskQueueId queue_id, fml::TimePoint from_time);
87

88
  size_t GetNumPendingTasks(TaskQueueId queue_id) const;
89 90 91 92 93

  // Observers methods.

  void AddTaskObserver(TaskQueueId queue_id,
                       intptr_t key,
94
                       const fml::closure& callback);
95 96 97

  void RemoveTaskObserver(TaskQueueId queue_id, intptr_t key);

98
  std::vector<fml::closure> GetObserversToNotify(TaskQueueId queue_id) const;
99 100 101 102 103

  // Misc.

  void SetWakeable(TaskQueueId queue_id, fml::Wakeable* wakeable);

104 105 106 107 108 109 110 111 112
  // Invariants for merge and un-merge
  //  1. RegisterTask will always submit to the queue_id that is passed
  //     to it. It is not aware of whether a queue is merged or not. Same with
  //     task observers.
  //  2. When we get the tasks to run now, we look at both the queue_ids
  //     for the owner, subsumed will spin.
  //  3. Each task queue can only be merged and subsumed once.
  //
  //  Methods currently aware of the merged state of the queues:
113
  //  HasPendingTasks, GetNextTaskToRun, GetNumPendingTasks
114 115 116 117 118 119 120 121 122

  // This method returns false if either the owner or subsumed has already been
  // merged with something else.
  bool Merge(TaskQueueId owner, TaskQueueId subsumed);

  // Will return false if the owner has not been merged before.
  bool Unmerge(TaskQueueId owner);

  // Returns true if owner owns the subsumed task queue.
123
  bool Owns(TaskQueueId owner, TaskQueueId subsumed) const;
124

125
 private:
126 127
  class MergedQueuesRunner;

128 129 130 131
  MessageLoopTaskQueues();

  ~MessageLoopTaskQueues();

132
  void WakeUpUnlocked(TaskQueueId queue_id, fml::TimePoint time) const;
133

134
  bool HasPendingTasksUnlocked(TaskQueueId queue_id) const;
135

136
  const DelayedTask& PeekNextTaskUnlocked(TaskQueueId owner,
137
                                          TaskQueueId& top_queue_id) const;
138

139
  fml::TimePoint GetNextWakeTimeUnlocked(TaskQueueId queue_id) const;
140 141

  static std::mutex creation_mutex_;
142
  static fml::RefPtr<MessageLoopTaskQueues> instance_;
143

144
  mutable std::mutex queue_mutex_;
145
  std::map<TaskQueueId, std::unique_ptr<TaskQueueEntry>> queue_entries_;
146

147
  size_t task_queue_id_counter_;
148

149 150 151 152 153 154 155 156 157 158
  std::atomic_int order_;

  FML_FRIEND_MAKE_REF_COUNTED(MessageLoopTaskQueues);
  FML_FRIEND_REF_COUNTED_THREAD_SAFE(MessageLoopTaskQueues);
  FML_DISALLOW_COPY_ASSIGN_AND_MOVE(MessageLoopTaskQueues);
};

}  // namespace fml

#endif  // FLUTTER_FML_MESSAGE_LOOP_TASK_QUEUES_H_