1// Copyright 2015 The Chromium OS 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 LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_H_
6#define LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_H_
7
8#include <string>
9
10#include <base/callback.h>
11#include <base/location.h>
12#include <base/time/time.h>
13#include <brillo/brillo_export.h>
14
15namespace brillo {
16
17class BRILLO_EXPORT MessageLoop {
18 public:
19  virtual ~MessageLoop();
20
21  // A unique task identifier used to refer to scheduled callbacks.
22  using TaskId = uint64_t;
23
24  // The kNullEventId is reserved for an invalid task and will never be used
25  // to refer to a real task.
26  static const TaskId kTaskIdNull;
27
28  // Return the MessageLoop for the current thread. It is a fatal error to
29  // request the current MessageLoop if SetAsCurrent() was not called on the
30  // current thread. If you really need to, use ThreadHasCurrent() to check if
31  // there is a current thread.
32  static MessageLoop* current();
33
34  // Return whether there is a MessageLoop in the current thread.
35  static bool ThreadHasCurrent();
36
37  // Set this message loop as the current thread main loop. Only one message
38  // loop can be set at a time. Use ReleaseFromCurrent() to release it.
39  void SetAsCurrent();
40
41  // Release this instance from the current thread. This instance must have
42  // been previously set with SetAsCurrent().
43  void ReleaseFromCurrent();
44
45  // Schedule a Closure |task| to be executed after a |delay|. Returns a task
46  // identifier for the scheduled task that can be used to cancel the task
47  // before it is fired by passing it to CancelTask().
48  // In case of an error scheduling the task, the kTaskIdNull is returned.
49  // Note that once the call is executed or canceled, the TaskId could be reused
50  // at a later point.
51  // This methond can only be called from the same thread running the main loop.
52  virtual TaskId PostDelayedTask(const tracked_objects::Location& from_here,
53                                 const base::Closure& task,
54                                 base::TimeDelta delay) = 0;
55  // Variant without the Location for easier usage.
56  TaskId PostDelayedTask(const base::Closure& task, base::TimeDelta delay) {
57    return PostDelayedTask(tracked_objects::Location(), task, delay);
58  }
59
60  // A convenience method to schedule a call with no delay.
61  // This methond can only be called from the same thread running the main loop.
62  TaskId PostTask(const base::Closure& task) {
63    return PostDelayedTask(task, base::TimeDelta());
64  }
65  TaskId PostTask(const tracked_objects::Location& from_here,
66                  const base::Closure& task) {
67    return PostDelayedTask(from_here, task, base::TimeDelta());
68  }
69
70  // Watch mode flag used to watch for file descriptors.
71  enum WatchMode {
72    kWatchRead,
73    kWatchWrite,
74  };
75
76  // Watch a file descriptor |fd| for it to be ready to perform the operation
77  // passed in |mode| without blocking. When that happens, the |task| closure
78  // will be executed. If |persistent| is true, the file descriptor will
79  // continue to be watched and |task| will continue to be called until the task
80  // is canceled with CancelTask().
81  // Returns the TaskId describing this task. In case of error, returns
82  // kTaskIdNull.
83  virtual TaskId WatchFileDescriptor(const tracked_objects::Location& from_here,
84                                     int fd,
85                                     WatchMode mode,
86                                     bool persistent,
87                                     const base::Closure& task) = 0;
88
89  // Convenience function to call WatchFileDescriptor() without a location.
90  TaskId WatchFileDescriptor(int fd,
91                             WatchMode mode,
92                             bool persistent,
93                             const base::Closure& task) {
94    return WatchFileDescriptor(
95        tracked_objects::Location(), fd, mode, persistent, task);
96  }
97
98  // Cancel a scheduled task. Returns whether the task was canceled. For
99  // example, if the callback was already executed (or is being executed) or was
100  // already canceled this method will fail. Note that the TaskId can be reused
101  // after it was executed or cancelled.
102  virtual bool CancelTask(TaskId task_id) = 0;
103
104  // ---------------------------------------------------------------------------
105  // Methods used to run and stop the message loop.
106
107  // Run one iteration of the message loop, dispatching up to one task. The
108  // |may_block| tells whether this method is allowed to block waiting for a
109  // task to be ready to run. Returns whether it ran a task. Note that even
110  // if |may_block| is true, this method can return false immediately if there
111  // are no more tasks registered.
112  virtual bool RunOnce(bool may_block) = 0;
113
114  // Run the main loop until there are no more registered tasks.
115  virtual void Run();
116
117  // Quit the running main loop immediately. This method will make the current
118  // running Run() method to return right after the current task returns back
119  // to the message loop without processing any other task.
120  virtual void BreakLoop();
121
122 protected:
123  MessageLoop() = default;
124
125 private:
126  // Tells whether Run() should quit the message loop in the default
127  // implementation.
128  bool should_exit_ = false;
129
130  DISALLOW_COPY_AND_ASSIGN(MessageLoop);
131};
132
133}  // namespace brillo
134
135#endif  // LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_H_
136