1// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_MESSAGE_HANDLER_H_
6#define RUNTIME_VM_MESSAGE_HANDLER_H_
7
8#include <memory>
9
10#include "vm/isolate.h"
11#include "vm/lockers.h"
12#include "vm/message.h"
13#include "vm/os_thread.h"
14#include "vm/port_set.h"
15#include "vm/thread_pool.h"
16
17namespace dart {
18
19// A MessageHandler is an entity capable of accepting messages.
20class MessageHandler {
21 protected:
22 MessageHandler();
23
24 public:
25 enum MessageStatus {
26 kOK, // We successfully handled a message.
27 kError, // We encountered an error handling a message.
28 kRestart, // The VM is restarting.
29 kShutdown, // The VM is shutting down.
30 };
31 static const char* MessageStatusString(MessageStatus status);
32
33 virtual ~MessageHandler();
34
35 // Allow subclasses to provide a handler name.
36 virtual const char* name() const;
37
38 typedef uword CallbackData;
39 typedef MessageStatus (*StartCallback)(CallbackData data);
40 typedef void (*EndCallback)(CallbackData data);
41
42 // Runs this message handler on the thread pool.
43 //
44 // Before processing messages, the optional StartFunction is run.
45 //
46 // A message handler will run until it terminates either normally or
47 // abnormally. Normal termination occurs when the message handler
48 // no longer has any live ports. Abnormal termination occurs when
49 // HandleMessage() indicates that an error has occurred during
50 // message processing.
51 void Run(ThreadPool* pool,
52 StartCallback start_callback,
53 EndCallback end_callback,
54 CallbackData data);
55
56 // Handles the next message for this message handler. Should only
57 // be used when not running the handler on the thread pool (via Run
58 // or RunBlocking).
59 //
60 // Returns true on success.
61 MessageStatus HandleNextMessage();
62
63 // Handles any OOB messages for this message handler. Can be used
64 // even if the message handler is running on the thread pool.
65 //
66 // Returns true on success.
67 MessageStatus HandleOOBMessages();
68
69 // Blocks the thread on a condition variable until a message arrives, and then
70 // handles all messages.
71 MessageStatus PauseAndHandleAllMessages(int64_t timeout_millis);
72
73 // Returns true if there are pending OOB messages for this message
74 // handler.
75 bool HasOOBMessages();
76
77 // Returns true if there are pending normal messages for this message
78 // handler.
79 bool HasMessages();
80
81 // A message handler tracks how many live ports it has.
82 bool HasLivePorts() const { return live_ports_ > 0; }
83
84 intptr_t live_ports() const { return live_ports_; }
85
86 bool paused() const { return paused_ > 0; }
87
88 void increment_paused() { paused_++; }
89 void decrement_paused() {
90 ASSERT(paused_ > 0);
91 paused_--;
92 }
93
94#if !defined(PRODUCT)
95 void DebugDump();
96
97 bool should_pause_on_start() const { return should_pause_on_start_; }
98
99 void set_should_pause_on_start(bool should_pause_on_start) {
100 should_pause_on_start_ = should_pause_on_start;
101 }
102
103 bool is_paused_on_start() const { return is_paused_on_start_; }
104
105 bool should_pause_on_exit() const { return should_pause_on_exit_; }
106
107 void set_should_pause_on_exit(bool should_pause_on_exit) {
108 should_pause_on_exit_ = should_pause_on_exit;
109 }
110
111 bool is_paused_on_exit() const { return is_paused_on_exit_; }
112
113 // Timestamp of the paused on start or paused on exit.
114 int64_t paused_timestamp() const { return paused_timestamp_; }
115
116 bool ShouldPauseOnStart(MessageStatus status) const;
117 bool ShouldPauseOnExit(MessageStatus status) const;
118 void PausedOnStart(bool paused);
119 void PausedOnExit(bool paused);
120#endif
121
122 // Gives temporary ownership of |queue| and |oob_queue|. Using this object
123 // has the side effect that no OOB messages will be handled if a stack
124 // overflow interrupt is delivered.
125 class AcquiredQueues : public ValueObject {
126 public:
127 explicit AcquiredQueues(MessageHandler* handler);
128
129 ~AcquiredQueues();
130
131 MessageQueue* queue() {
132 if (handler_ == NULL) {
133 return NULL;
134 }
135 return handler_->queue_;
136 }
137
138 MessageQueue* oob_queue() {
139 if (handler_ == NULL) {
140 return NULL;
141 }
142 return handler_->oob_queue_;
143 }
144
145 private:
146 MessageHandler* handler_;
147 SafepointMonitorLocker ml_;
148
149 friend class MessageHandler;
150 };
151
152#if defined(DEBUG)
153 // Check that it is safe to access this message handler.
154 //
155 // For example, if this MessageHandler is an isolate, then it is
156 // only safe to access it when the MessageHandler is the current
157 // isolate.
158 virtual void CheckAccess();
159#endif
160
161 protected:
162 // ------------ START PortMap API ------------
163 // These functions should only be called from the PortMap.
164
165 // Does this message handler correspond to the current isolate?
166 virtual bool IsCurrentIsolate() const { return false; }
167
168 // Return Isolate to which this message handler corresponds to.
169 virtual Isolate* isolate() const { return NULL; }
170
171 // Posts a message on this handler's message queue.
172 // If before_events is true, then the message is enqueued before any pending
173 // events, but after any pending isolate library events.
174 void PostMessage(std::unique_ptr<Message> message,
175 bool before_events = false);
176
177 // Notifies this handler that a port is being closed.
178 void ClosePort(Dart_Port port);
179
180 // Notifies this handler that all ports are being closed.
181 void CloseAllPorts();
182
183 // Returns true if the handler is owned by the PortMap.
184 //
185 // This is used to delete handlers when their last live port is closed.
186 virtual bool OwnedByPortMap() const { return false; }
187
188 // Requests deletion of this message handler when the next task
189 // completes.
190 void RequestDeletion();
191
192 void increment_live_ports();
193 void decrement_live_ports();
194 // ------------ END PortMap API ------------
195
196 // Custom message notification. Optionally provided by subclass.
197 virtual void MessageNotify(Message::Priority priority);
198
199 // Handles a single message. Provided by subclass.
200 //
201 // Returns true on success.
202 virtual MessageStatus HandleMessage(std::unique_ptr<Message> message) = 0;
203
204 virtual void NotifyPauseOnStart() {}
205 virtual void NotifyPauseOnExit() {}
206
207 // TODO(iposva): Set a local field before entering MessageHandler methods.
208 Thread* thread() const { return Thread::Current(); }
209
210 private:
211 friend class PortMap;
212 friend class MessageHandlerTestPeer;
213 friend class MessageHandlerTask;
214
215 struct PortSetEntry : public PortSet<PortSetEntry>::Entry {};
216
217 // Called by MessageHandlerTask to process our task queue.
218 void TaskCallback();
219
220 // Checks if we have a slot for idle task execution, if we have a slot
221 // for idle task execution it is scheduled immediately or we wait for
222 // idle expiration and then attempt to schedule the idle task.
223 // Returns true if their is scope for idle task execution so that we
224 // can loop back to handle more messages or false if idle tasks are not
225 // scheduled.
226 bool CheckIfIdleLocked(MonitorLocker* ml);
227
228 // Triggers a run of the idle task.
229 void RunIdleTaskLocked(MonitorLocker* ml);
230
231 // NOTE: These two functions release and reacquire the monitor, you may
232 // need to call HandleMessages to ensure all pending messages are handled.
233 void PausedOnStartLocked(MonitorLocker* ml, bool paused);
234 void PausedOnExitLocked(MonitorLocker* ml, bool paused);
235
236 // Dequeue the next message. Prefer messages from the oob_queue_ to
237 // messages from the queue_.
238 std::unique_ptr<Message> DequeueMessage(Message::Priority min_priority);
239
240 void ClearOOBQueue();
241
242 // Handles any pending messages.
243 MessageStatus HandleMessages(MonitorLocker* ml,
244 bool allow_normal_messages,
245 bool allow_multiple_normal_messages);
246
247 Monitor monitor_; // Protects all fields in MessageHandler.
248 MessageQueue* queue_;
249 MessageQueue* oob_queue_;
250 // This flag is not thread safe and can only reliably be accessed on a single
251 // thread.
252 bool oob_message_handling_allowed_;
253 bool paused_for_messages_;
254 PortSet<PortSetEntry>
255 ports_; // Only accessed by [PortMap], protected by [PortMap]s lock.
256 intptr_t live_ports_; // The number of open ports, including control ports.
257 intptr_t paused_; // The number of pause messages received.
258#if !defined(PRODUCT)
259 bool should_pause_on_start_;
260 bool should_pause_on_exit_;
261 bool is_paused_on_start_;
262 bool is_paused_on_exit_;
263 int64_t paused_timestamp_;
264#endif
265 bool task_running_;
266 bool delete_me_;
267 ThreadPool* pool_;
268 StartCallback start_callback_;
269 EndCallback end_callback_;
270 CallbackData callback_data_;
271
272 DISALLOW_COPY_AND_ASSIGN(MessageHandler);
273};
274
275} // namespace dart
276
277#endif // RUNTIME_VM_MESSAGE_HANDLER_H_
278