Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
4 : // Use of this source code is governed by a BSD-style license that can be
5 : // found in the LICENSE file.
6 :
7 : #ifndef BASE_MESSAGE_PUMP_H_
8 : #define BASE_MESSAGE_PUMP_H_
9 :
10 : #include "nsISupportsImpl.h"
11 :
12 : class nsIEventTarget;
13 :
14 : namespace base {
15 :
16 : class TimeTicks;
17 :
18 67 : class MessagePump {
19 : public:
20 2544 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MessagePump)
21 :
22 : // Please see the comments above the Run method for an illustration of how
23 : // these delegate methods are used.
24 67 : class Delegate {
25 : public:
26 1 : virtual ~Delegate() {}
27 :
28 : // Called from within Run in response to ScheduleWork or when the message
29 : // pump would otherwise call DoDelayedWork. Returns true to indicate that
30 : // work was done. DoDelayedWork will not be called if DoWork returns true.
31 : virtual bool DoWork() = 0;
32 :
33 : // Called from within Run in response to ScheduleDelayedWork or when the
34 : // message pump would otherwise sleep waiting for more work. Returns true
35 : // to indicate that delayed work was done. DoIdleWork will not be called
36 : // if DoDelayedWork returns true. Upon return |next_delayed_work_time|
37 : // indicates the time when DoDelayedWork should be called again. If
38 : // |next_delayed_work_time| is null (per Time::is_null), then the queue of
39 : // future delayed work (timer events) is currently empty, and no additional
40 : // calls to this function need to be scheduled.
41 : virtual bool DoDelayedWork(TimeTicks* next_delayed_work_time) = 0;
42 :
43 : // Called from within Run just before the message pump goes to sleep.
44 : // Returns true to indicate that idle work was done.
45 : virtual bool DoIdleWork() = 0;
46 : };
47 :
48 : // The Run method is called to enter the message pump's run loop.
49 : //
50 : // Within the method, the message pump is responsible for processing native
51 : // messages as well as for giving cycles to the delegate periodically. The
52 : // message pump should take care to mix delegate callbacks with native
53 : // message processing so neither type of event starves the other of cycles.
54 : //
55 : // The anatomy of a typical run loop:
56 : //
57 : // for (;;) {
58 : // bool did_work = DoInternalWork();
59 : // if (should_quit_)
60 : // break;
61 : //
62 : // did_work |= delegate_->DoWork();
63 : // if (should_quit_)
64 : // break;
65 : //
66 : // did_work |= delegate_->DoDelayedWork();
67 : // if (should_quit_)
68 : // break;
69 : //
70 : // if (did_work)
71 : // continue;
72 : //
73 : // did_work = delegate_->DoIdleWork();
74 : // if (should_quit_)
75 : // break;
76 : //
77 : // if (did_work)
78 : // continue;
79 : //
80 : // WaitForWork();
81 : // }
82 : //
83 : // Here, DoInternalWork is some private method of the message pump that is
84 : // responsible for dispatching the next UI message or notifying the next IO
85 : // completion (for example). WaitForWork is a private method that simply
86 : // blocks until there is more work of any type to do.
87 : //
88 : // Notice that the run loop cycles between calling DoInternalWork, DoWork,
89 : // and DoDelayedWork methods. This helps ensure that neither work queue
90 : // starves the other. This is important for message pumps that are used to
91 : // drive animations, for example.
92 : //
93 : // Notice also that after each callout to foreign code, the run loop checks
94 : // to see if it should quit. The Quit method is responsible for setting this
95 : // flag. No further work is done once the quit flag is set.
96 : //
97 : // NOTE: Care must be taken to handle Run being called again from within any
98 : // of the callouts to foreign code. Native message pumps may also need to
99 : // deal with other native message pumps being run outside their control
100 : // (e.g., the MessageBox API on Windows pumps UI messages!). To be specific,
101 : // the callouts (DoWork and DoDelayedWork) MUST still be provided even in
102 : // nested sub-loops that are "seemingly" outside the control of this message
103 : // pump. DoWork in particular must never be starved for time slices unless
104 : // it returns false (meaning it has run out of things to do).
105 : //
106 : virtual void Run(Delegate* delegate) = 0;
107 :
108 : // Quit immediately from the most recently entered run loop. This method may
109 : // only be used on the thread that called Run.
110 : virtual void Quit() = 0;
111 :
112 : // Schedule a DoWork callback to happen reasonably soon. Does nothing if a
113 : // DoWork callback is already scheduled. This method may be called from any
114 : // thread. Once this call is made, DoWork should not be "starved" at least
115 : // until it returns a value of false.
116 : virtual void ScheduleWork() = 0;
117 :
118 : // This method may only called from the thread that called Run.
119 : //
120 : // Ensure that DoWork will be called if a nested loop is entered.
121 : // If a MessagePump can already guarantee that DoWork will be called
122 : // "reasonably soon", this method can be a no-op to avoid expensive
123 : // atomic tests and/or syscalls required for ScheduleWork().
124 0 : virtual void ScheduleWorkForNestedLoop() { ScheduleWork(); };
125 :
126 : // Schedule a DoDelayedWork callback to happen at the specified time,
127 : // cancelling any pending DoDelayedWork callback. This method may only be
128 : // used on the thread that called Run.
129 : virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) = 0;
130 :
131 : // If returned, just use the nsThread.
132 1238 : virtual nsIEventTarget* GetXPCOMThread()
133 : {
134 1238 : return nullptr;
135 : }
136 :
137 : protected:
138 1 : virtual ~MessagePump() {};
139 : };
140 :
141 : } // namespace base
142 :
143 : #endif // BASE_MESSAGE_PUMP_H_
|