1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file.
4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#ifndef MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
6effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#define MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <map>
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <queue>
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "mojo/public/cpp/bindings/callback.h"
12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "mojo/public/cpp/system/core.h"
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace mojo {
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class RunLoopHandler;
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class RunLoop {
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunLoop();
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ~RunLoop();
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Sets up state needed for RunLoop. This must be invoked before creating a
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // RunLoop.
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static void SetUp();
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Cleans state created by Setup().
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static void TearDown();
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Returns the RunLoop for the current thread. Returns NULL if not yet
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // created.
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static RunLoop* current();
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Registers a RunLoopHandler for the specified handle. Only one handler can
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // be registered for a specified handle.
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void AddHandler(RunLoopHandler* handler,
37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                  const Handle& handle,
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                  MojoHandleSignals handle_signals,
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                  MojoDeadline deadline);
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void RemoveHandler(const Handle& handle);
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool HasHandler(const Handle& handle) const;
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Runs the loop servicing handles and tasks as they are ready. This returns
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // when Quit() is invoked, or there are no more handles nor tasks.
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void Run();
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Runs the loop servicing any handles and tasks that are ready. Does not wait
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // for handles or tasks to become ready before returning. Returns early if
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Quit() is invoked.
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void RunUntilIdle();
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void Quit();
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Adds a task to be performed after delay has elapsed. Must be posted to the
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // current thread's RunLoop.
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void PostDelayedTask(const Closure& task, MojoTimeTicks delay);
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private:
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  struct RunState;
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  struct WaitState;
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Contains the data needed to track a request to AddHandler().
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  struct HandlerData {
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    HandlerData()
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        : handler(NULL),
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          handle_signals(MOJO_HANDLE_SIGNAL_NONE),
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          deadline(0),
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          id(0) {}
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    RunLoopHandler* handler;
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    MojoHandleSignals handle_signals;
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    MojoTimeTicks deadline;
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // See description of |RunLoop::next_handler_id_| for details.
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    int id;
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  };
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  typedef std::map<Handle, HandlerData> HandleToHandlerData;
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
7903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Used for NotifyHandlers to specify whether HandlerData's |deadline|
8003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // should be checked prior to notifying.
8103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  enum CheckDeadline {
8203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    CHECK_DEADLINE,
8303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    IGNORE_DEADLINE
8403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  };
8503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Mode of operation of the run loop.
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  enum RunMode {
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UNTIL_EMPTY,
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    UNTIL_IDLE
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  };
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Runs the loop servicing any handles and tasks that are ready. If
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // |run_mode| is |UNTIL_IDLE|, does not wait for handles or tasks to become
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // ready before returning. Returns early if Quit() is invoked.
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void RunInternal(RunMode run_mode);
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Do one unit of delayed work, if eligible. Returns true is a task was run.
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  bool DoDelayedWork();
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Waits for a handle to be ready or until the next task must be run. Returns
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // after servicing at least one handle (or there are no more handles) unless
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // a task must be run or |non_blocking| is true, in which case it will also
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // return if no task is registered and servicing at least one handle would
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // require blocking. Returns true if a RunLoopHandler was notified.
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool Wait(bool non_blocking);
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
10703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Notifies handlers of |error|.  If |check| == CHECK_DEADLINE, this will
10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // only notify handlers whose deadline has expired and skips the rest.
10903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Returns true if a RunLoopHandler was notified.
11003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  bool NotifyHandlers(MojoResult error, CheckDeadline check);
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Removes the first invalid handle. This is called if MojoWaitMany() finds an
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // invalid handle. Returns true if a RunLoopHandler was notified.
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool RemoveFirstInvalidHandle(const WaitState& wait_state);
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Returns the state needed to pass to WaitMany().
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WaitState GetWaitState(bool non_blocking) const;
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  HandleToHandlerData handler_data_;
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // If non-NULL we're running (inside Run()). Member references a value on the
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // stack.
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunState* run_state_;
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // An ever increasing value assigned to each HandlerData::id. Used to detect
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // uniqueness while notifying. That is, while notifying expired timers we copy
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // |handler_data_| and only notify handlers whose id match. If the id does not
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // match it means the handler was removed then added so that we shouldn't
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // notify it.
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  int next_handler_id_;
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  struct PendingTask {
1335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    PendingTask(const Closure& task,
1345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                MojoTimeTicks runtime,
1355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                uint64_t sequence_number);
1365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ~PendingTask();
1375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    bool operator<(const PendingTask& other) const;
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    Closure task;
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    MojoTimeTicks run_time;
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    uint64_t sequence_number;
1435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  };
1445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // An ever increasing sequence number attached to each pending task in order
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // to preserve relative order of tasks posted at the 'same' time.
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  uint64_t next_sequence_number_;
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  typedef std::priority_queue<PendingTask> DelayedTaskQueue;
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DelayedTaskQueue delayed_tasks_;
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MOJO_DISALLOW_COPY_AND_ASSIGN(RunLoop);
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace mojo
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
155effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#endif  // MOJO_PUBLIC_CPP_UTILITY_RUN_LOOP_H_
156