aboutsummaryrefslogtreecommitdiff
path: root/chromeos/message_loops/base_message_loop.h
blob: 902b828bdef4ac233af3271d265c5ad0b16d0179 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
// Copyright 2015 The Chromium OS 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 LIBCHROMEOS_CHROMEOS_MESSAGE_LOOPS_BASE_MESSAGE_LOOP_H_
#define LIBCHROMEOS_CHROMEOS_MESSAGE_LOOPS_BASE_MESSAGE_LOOP_H_

// BaseMessageLoop is a chromeos::MessageLoop implementation based on
// base::MessageLoopForIO. This allows to mix new code using
// chromeos::MessageLoop and legacy code using base::MessageLoopForIO in the
// same thread and share a single main loop. This disadvantage of using this
// class is a less efficient implementation of CancelTask() for delayed tasks
// since base::MessageLoopForIO doesn't provide a way to remove the event.

#include <map>
#include <memory>

#include <base/location.h>
#include <base/memory/weak_ptr.h>
#include <base/message_loop/message_loop.h>
#include <base/time/time.h>

#include <chromeos/chromeos_export.h>
#include <chromeos/message_loops/message_loop.h>

namespace chromeos {

class CHROMEOS_EXPORT BaseMessageLoop : public MessageLoop {
 public:
  explicit BaseMessageLoop(base::MessageLoopForIO* base_loop);
  ~BaseMessageLoop() override;

  // MessageLoop overrides.
  TaskId PostDelayedTask(const tracked_objects::Location& from_here,
                         const base::Closure& task,
                         base::TimeDelta delay) override;
  using MessageLoop::PostDelayedTask;
  TaskId WatchFileDescriptor(const tracked_objects::Location& from_here,
                             int fd,
                             WatchMode mode,
                             bool persistent,
                             const base::Closure& task) override;
  using MessageLoop::WatchFileDescriptor;
  bool CancelTask(TaskId task_id) override;
  bool RunOnce(bool may_block) override;
  void Run() override;
  void BreakLoop() override;

  // Returns a callback that will quit the current message loop. If the message
  // loop is not running, an empty (null) callback is returned.
  base::Closure QuitClosure() const;

 private:
  // Called by base::MessageLoopForIO when is time to call the callback
  // scheduled with Post*Task() of id |task_id|, even if it was canceled.
  void OnRanPostedTask(MessageLoop::TaskId task_id);

  // Called from the message loop when the IOTask should run the scheduled
  // callback. This is a simple wrapper of IOTask::OnFileReadyPostedTask()
  // posted from the BaseMessageLoop so it is deleted when the BaseMessageLoop
  // goes out of scope since we can't cancel the callback otherwise.
  void OnFileReadyPostedTask(MessageLoop::TaskId task_id);

  // Return a new unused task_id.
  TaskId NextTaskId();

  struct DelayedTask {
    tracked_objects::Location location;

    MessageLoop::TaskId task_id;
    base::Closure closure;
  };

  std::map<MessageLoop::TaskId, DelayedTask> delayed_tasks_;

  class IOTask : public base::MessageLoopForIO::Watcher {
   public:
    IOTask(const tracked_objects::Location& location,
           BaseMessageLoop* loop,
           MessageLoop::TaskId task_id,
           int fd,
           base::MessageLoopForIO::Mode base_mode,
           bool persistent,
           const base::Closure& task);

    const tracked_objects::Location& location() const { return location_; }

    // Used to start/stop watching the file descriptor while keeping the
    // IOTask entry available.
    bool StartWatching();
    void StopWatching();

    // Called from the message loop as a PostTask() when the file descriptor is
    // available, scheduled to run from OnFileReady().
    void OnFileReadyPostedTask();

    // Cancel the IOTask and returns whether it was actually canceled, with the
    // same semantics as MessageLoop::CancelTask().
    bool CancelTask();

   private:
    tracked_objects::Location location_;
    BaseMessageLoop* loop_;

    // These are the arguments passed in the constructor, basically forwarding
    // all the arguments passed to WatchFileDescriptor() plus the assigned
    // TaskId for this task.
    MessageLoop::TaskId task_id_;
    int fd_;
    base::MessageLoopForIO::Mode base_mode_;
    bool persistent_;
    base::Closure closure_;

    base::MessageLoopForIO::FileDescriptorWatcher fd_watcher_;

    // Tells whether there is a pending call to OnFileReadPostedTask().
    bool posted_task_pending_{false};

    // base::MessageLoopForIO::Watcher overrides:
    void OnFileCanReadWithoutBlocking(int fd) override;
    void OnFileCanWriteWithoutBlocking(int fd) override;

    // Common implementation for both the read and write case.
    void OnFileReady();

    DISALLOW_COPY_AND_ASSIGN(IOTask);
  };

  std::map<MessageLoop::TaskId, IOTask> io_tasks_;

  // Flag to mark that we should run the message loop only one iteration.
  bool run_once_{false};

  // The last used TaskId. While base::MessageLoopForIO doesn't allow to cancel
  // delayed tasks, we handle that functionality by not running the callback
  // if it fires at a later point.
  MessageLoop::TaskId last_id_{kTaskIdNull};

  // The pointer to the libchrome base::MessageLoopForIO we are wrapping with
  // this interface.
  base::MessageLoopForIO* base_loop_;

  // The RunLoop instance used to run the main loop from Run().
  base::RunLoop* base_run_loop_{nullptr};

  // We use a WeakPtrFactory to schedule tasks with the base::MessageLoopForIO
  // since we can't cancel the callbacks we have scheduled there once this
  // instance is destroyed.
  base::WeakPtrFactory<BaseMessageLoop> weak_ptr_factory_;
  DISALLOW_COPY_AND_ASSIGN(BaseMessageLoop);
};

}  // namespace chromeos

#endif  // LIBCHROMEOS_CHROMEOS_MESSAGE_LOOPS_BASE_MESSAGE_LOOP_H_