1// Copyright 2013 The Chromium 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 MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
6#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
7
8#include <map>
9#include <queue>
10
11#include "mojo/public/cpp/bindings/callback.h"
12#include "mojo/public/cpp/system/core.h"
13
14namespace mojo {
15
16class RunLoopHandler;
17
18class RunLoop {
19 public:
20  RunLoop();
21  ~RunLoop();
22
23  // Sets up state needed for RunLoop. This must be invoked before creating a
24  // RunLoop.
25  static void SetUp();
26
27  // Cleans state created by Setup().
28  static void TearDown();
29
30  // Returns the RunLoop for the current thread. Returns NULL if not yet
31  // created.
32  static RunLoop* current();
33
34  // Registers a RunLoopHandler for the specified handle. Only one handler can
35  // be registered for a specified handle.
36  void AddHandler(RunLoopHandler* handler,
37                  const Handle& handle,
38                  MojoHandleSignals handle_signals,
39                  MojoDeadline deadline);
40  void RemoveHandler(const Handle& handle);
41  bool HasHandler(const Handle& handle) const;
42
43  // Runs the loop servicing handles and tasks as they are ready. This returns
44  // when Quit() is invoked, or there are no more handles nor tasks.
45  void Run();
46
47  // Runs the loop servicing any handles and tasks that are ready. Does not wait
48  // for handles or tasks to become ready before returning. Returns early if
49  // Quit() is invoked.
50  void RunUntilIdle();
51
52  void Quit();
53
54  // Adds a task to be performed after delay has elapsed. Must be posted to the
55  // current thread's RunLoop.
56  void PostDelayedTask(const Closure& task, MojoTimeTicks delay);
57
58 private:
59  struct RunState;
60  struct WaitState;
61
62  // Contains the data needed to track a request to AddHandler().
63  struct HandlerData {
64    HandlerData()
65        : handler(NULL),
66          handle_signals(MOJO_HANDLE_SIGNAL_NONE),
67          deadline(0),
68          id(0) {}
69
70    RunLoopHandler* handler;
71    MojoHandleSignals handle_signals;
72    MojoTimeTicks deadline;
73    // See description of |RunLoop::next_handler_id_| for details.
74    int id;
75  };
76
77  typedef std::map<Handle, HandlerData> HandleToHandlerData;
78
79  // Used for NotifyHandlers to specify whether HandlerData's |deadline|
80  // should be checked prior to notifying.
81  enum CheckDeadline {
82    CHECK_DEADLINE,
83    IGNORE_DEADLINE
84  };
85
86  // Mode of operation of the run loop.
87  enum RunMode {
88    UNTIL_EMPTY,
89    UNTIL_IDLE
90  };
91
92  // Runs the loop servicing any handles and tasks that are ready. If
93  // |run_mode| is |UNTIL_IDLE|, does not wait for handles or tasks to become
94  // ready before returning. Returns early if Quit() is invoked.
95  void RunInternal(RunMode run_mode);
96
97  // Do one unit of delayed work, if eligible. Returns true is a task was run.
98  bool DoDelayedWork();
99
100  // Waits for a handle to be ready or until the next task must be run. Returns
101  // after servicing at least one handle (or there are no more handles) unless
102  // a task must be run or |non_blocking| is true, in which case it will also
103  // return if no task is registered and servicing at least one handle would
104  // require blocking. Returns true if a RunLoopHandler was notified.
105  bool Wait(bool non_blocking);
106
107  // Notifies handlers of |error|.  If |check| == CHECK_DEADLINE, this will
108  // only notify handlers whose deadline has expired and skips the rest.
109  // Returns true if a RunLoopHandler was notified.
110  bool NotifyHandlers(MojoResult error, CheckDeadline check);
111
112  // Removes the first invalid handle. This is called if MojoWaitMany() finds an
113  // invalid handle. Returns true if a RunLoopHandler was notified.
114  bool RemoveFirstInvalidHandle(const WaitState& wait_state);
115
116  // Returns the state needed to pass to WaitMany().
117  WaitState GetWaitState(bool non_blocking) const;
118
119  HandleToHandlerData handler_data_;
120
121  // If non-NULL we're running (inside Run()). Member references a value on the
122  // stack.
123  RunState* run_state_;
124
125  // An ever increasing value assigned to each HandlerData::id. Used to detect
126  // uniqueness while notifying. That is, while notifying expired timers we copy
127  // |handler_data_| and only notify handlers whose id match. If the id does not
128  // match it means the handler was removed then added so that we shouldn't
129  // notify it.
130  int next_handler_id_;
131
132  struct PendingTask {
133    PendingTask(const Closure& task,
134                MojoTimeTicks runtime,
135                uint64_t sequence_number);
136    ~PendingTask();
137
138    bool operator<(const PendingTask& other) const;
139
140    Closure task;
141    MojoTimeTicks run_time;
142    uint64_t sequence_number;
143  };
144  // An ever increasing sequence number attached to each pending task in order
145  // to preserve relative order of tasks posted at the 'same' time.
146  uint64_t next_sequence_number_;
147  typedef std::priority_queue<PendingTask> DelayedTaskQueue;
148  DelayedTaskQueue delayed_tasks_;
149
150  MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoop);
151};
152
153}  // namespace mojo
154
155#endif  // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
156