|  | // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #ifndef RUNTIME_VM_MESSAGE_HANDLER_H_ | 
|  | #define RUNTIME_VM_MESSAGE_HANDLER_H_ | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "vm/isolate.h" | 
|  | #include "vm/lockers.h" | 
|  | #include "vm/message.h" | 
|  | #include "vm/os_thread.h" | 
|  | #include "vm/port_set.h" | 
|  | #include "vm/thread_pool.h" | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | // A MessageHandler is an entity capable of accepting messages. | 
|  | class MessageHandler { | 
|  | protected: | 
|  | MessageHandler(); | 
|  |  | 
|  | public: | 
|  | enum MessageStatus { | 
|  | kOK,        // We successfully handled a message. | 
|  | kError,     // We encountered an error handling a message. | 
|  | kShutdown,  // The VM is shutting down. | 
|  | }; | 
|  | static const char* MessageStatusString(MessageStatus status); | 
|  |  | 
|  | virtual ~MessageHandler(); | 
|  |  | 
|  | // Allow subclasses to provide a handler name. | 
|  | virtual const char* name() const; | 
|  |  | 
|  | typedef uword CallbackData; | 
|  | typedef MessageStatus (*StartCallback)(CallbackData data); | 
|  | typedef void (*EndCallback)(CallbackData data); | 
|  |  | 
|  | // Runs this message handler on the thread pool. | 
|  | // | 
|  | // Before processing messages, the optional StartFunction is run. | 
|  | // | 
|  | // A message handler will run until it terminates either normally or | 
|  | // abnormally.  Normal termination occurs when the message handler | 
|  | // no longer has any live ports.  Abnormal termination occurs when | 
|  | // HandleMessage() indicates that an error has occurred during | 
|  | // message processing. | 
|  |  | 
|  | // Returns false if the handler terminated abnormally, otherwise it | 
|  | // returns true. | 
|  | bool Run(ThreadPool* pool, | 
|  | StartCallback start_callback, | 
|  | EndCallback end_callback, | 
|  | CallbackData data); | 
|  |  | 
|  | // Handles the next message for this message handler.  Should only | 
|  | // be used when not running the handler on the thread pool (via Run | 
|  | // or RunBlocking). | 
|  | // | 
|  | // Returns true on success. | 
|  | MessageStatus HandleNextMessage(); | 
|  |  | 
|  | // Handles any OOB messages for this message handler.  Can be used | 
|  | // even if the message handler is running on the thread pool. | 
|  | // | 
|  | // Returns true on success. | 
|  | MessageStatus HandleOOBMessages(); | 
|  |  | 
|  | // Blocks the thread on a condition variable until a message arrives, and then | 
|  | // handles all messages. | 
|  | MessageStatus PauseAndHandleAllMessages(int64_t timeout_millis); | 
|  |  | 
|  | // Returns true if there are pending OOB messages for this message | 
|  | // handler. | 
|  | bool HasOOBMessages(); | 
|  |  | 
|  | #if defined(TESTING) | 
|  | std::unique_ptr<Message> StealOOBMessage(); | 
|  | #endif | 
|  |  | 
|  | // Returns true if there are pending normal messages for this message | 
|  | // handler. | 
|  | bool HasMessages(); | 
|  |  | 
|  | // A message handler tracks how many live ports it has. | 
|  | bool HasLivePorts() const { return live_ports_ > 0; } | 
|  |  | 
|  | intptr_t live_ports() const { return live_ports_; } | 
|  |  | 
|  | bool paused() const { return paused_ > 0; } | 
|  |  | 
|  | void increment_paused() { paused_++; } | 
|  | void decrement_paused() { | 
|  | ASSERT(paused_ > 0); | 
|  | paused_--; | 
|  | } | 
|  |  | 
|  | #if !defined(PRODUCT) | 
|  | void DebugDump(); | 
|  |  | 
|  | bool should_pause_on_start() const { return should_pause_on_start_; } | 
|  |  | 
|  | void set_should_pause_on_start(bool should_pause_on_start) { | 
|  | should_pause_on_start_ = should_pause_on_start; | 
|  | } | 
|  |  | 
|  | bool is_paused_on_start() const { return is_paused_on_start_; } | 
|  |  | 
|  | bool should_pause_on_exit() const { return should_pause_on_exit_; } | 
|  |  | 
|  | void set_should_pause_on_exit(bool should_pause_on_exit) { | 
|  | should_pause_on_exit_ = should_pause_on_exit; | 
|  | } | 
|  |  | 
|  | bool is_paused_on_exit() const { return is_paused_on_exit_; } | 
|  |  | 
|  | // Timestamp of the paused on start or paused on exit. | 
|  | int64_t paused_timestamp() const { return paused_timestamp_; } | 
|  |  | 
|  | bool ShouldPauseOnStart(MessageStatus status) const; | 
|  | bool ShouldPauseOnExit(MessageStatus status) const; | 
|  | void PausedOnStart(bool paused); | 
|  | void PausedOnExit(bool paused); | 
|  | #endif | 
|  |  | 
|  | // Gives temporary ownership of |queue| and |oob_queue|. Using this object | 
|  | // has the side effect that no OOB messages will be handled if a stack | 
|  | // overflow interrupt is delivered. | 
|  | class AcquiredQueues : public ValueObject { | 
|  | public: | 
|  | explicit AcquiredQueues(MessageHandler* handler); | 
|  |  | 
|  | ~AcquiredQueues(); | 
|  |  | 
|  | MessageQueue* queue() { | 
|  | if (handler_ == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  | return handler_->queue_; | 
|  | } | 
|  |  | 
|  | MessageQueue* oob_queue() { | 
|  | if (handler_ == nullptr) { | 
|  | return nullptr; | 
|  | } | 
|  | return handler_->oob_queue_; | 
|  | } | 
|  |  | 
|  | private: | 
|  | MessageHandler* handler_; | 
|  | SafepointMonitorLocker ml_; | 
|  |  | 
|  | friend class MessageHandler; | 
|  | }; | 
|  |  | 
|  | #if defined(DEBUG) | 
|  | // Check that it is safe to access this message handler. | 
|  | // | 
|  | // For example, if this MessageHandler is an isolate, then it is | 
|  | // only safe to access it when the MessageHandler is the current | 
|  | // isolate. | 
|  | virtual void CheckAccess(); | 
|  | #endif | 
|  |  | 
|  | protected: | 
|  | // ------------ START PortMap API ------------ | 
|  | // These functions should only be called from the PortMap. | 
|  |  | 
|  | // Does this message handler correspond to the current isolate? | 
|  | virtual bool IsCurrentIsolate() const { return false; } | 
|  |  | 
|  | // Return Isolate to which this message handler corresponds to. | 
|  | virtual Isolate* isolate() const { return nullptr; } | 
|  |  | 
|  | // Posts a message on this handler's message queue. | 
|  | // If before_events is true, then the message is enqueued before any pending | 
|  | // events, but after any pending isolate library events. | 
|  | void PostMessage(std::unique_ptr<Message> message, | 
|  | bool before_events = false); | 
|  |  | 
|  | // Notifies this handler that a port is being closed. | 
|  | void ClosePort(Dart_Port port); | 
|  |  | 
|  | // Notifies this handler that all ports are being closed. | 
|  | void CloseAllPorts(); | 
|  |  | 
|  | // Returns true if the handler is owned by the PortMap. | 
|  | // | 
|  | // This is used to delete handlers when their last live port is closed. | 
|  | virtual bool OwnedByPortMap() const { return false; } | 
|  |  | 
|  | // Requests deletion of this message handler when the next task | 
|  | // completes. | 
|  | void RequestDeletion(); | 
|  |  | 
|  | void increment_live_ports(); | 
|  | void decrement_live_ports(); | 
|  | // ------------ END PortMap API ------------ | 
|  |  | 
|  | // Custom message notification.  Optionally provided by subclass. | 
|  | virtual void MessageNotify(Message::Priority priority); | 
|  |  | 
|  | // Handles a single message.  Provided by subclass. | 
|  | // | 
|  | // Returns true on success. | 
|  | virtual MessageStatus HandleMessage(std::unique_ptr<Message> message) = 0; | 
|  |  | 
|  | virtual void NotifyPauseOnStart() {} | 
|  | virtual void NotifyPauseOnExit() {} | 
|  |  | 
|  | // TODO(iposva): Set a local field before entering MessageHandler methods. | 
|  | Thread* thread() const { return Thread::Current(); } | 
|  |  | 
|  | private: | 
|  | template <typename GCVisitorType> | 
|  | friend void MournFinalized(GCVisitorType* visitor); | 
|  | friend class PortMap; | 
|  | friend class MessageHandlerTestPeer; | 
|  | friend class MessageHandlerTask; | 
|  |  | 
|  | struct PortSetEntry : public PortSet<PortSetEntry>::Entry {}; | 
|  |  | 
|  | // Called by MessageHandlerTask to process our task queue. | 
|  | void TaskCallback(); | 
|  |  | 
|  | // Checks if we have a slot for idle task execution, if we have a slot | 
|  | // for idle task execution it is scheduled immediately or we wait for | 
|  | // idle expiration and then attempt to schedule the idle task. | 
|  | // Returns true if their is scope for idle task execution so that we | 
|  | // can loop back to handle more messages or false if idle tasks are not | 
|  | // scheduled. | 
|  | bool CheckIfIdleLocked(MonitorLocker* ml); | 
|  |  | 
|  | // Triggers a run of the idle task. | 
|  | void RunIdleTaskLocked(MonitorLocker* ml); | 
|  |  | 
|  | // NOTE: These two functions release and reacquire the monitor, you may | 
|  | // need to call HandleMessages to ensure all pending messages are handled. | 
|  | void PausedOnStartLocked(MonitorLocker* ml, bool paused); | 
|  | void PausedOnExitLocked(MonitorLocker* ml, bool paused); | 
|  |  | 
|  | // Dequeue the next message.  Prefer messages from the oob_queue_ to | 
|  | // messages from the queue_. | 
|  | std::unique_ptr<Message> DequeueMessage(Message::Priority min_priority); | 
|  |  | 
|  | void ClearOOBQueue(); | 
|  |  | 
|  | // Handles any pending messages. | 
|  | MessageStatus HandleMessages(MonitorLocker* ml, | 
|  | bool allow_normal_messages, | 
|  | bool allow_multiple_normal_messages); | 
|  |  | 
|  | Monitor monitor_;  // Protects all fields in MessageHandler. | 
|  | MessageQueue* queue_; | 
|  | MessageQueue* oob_queue_; | 
|  | // This flag is not thread safe and can only reliably be accessed on a single | 
|  | // thread. | 
|  | bool oob_message_handling_allowed_; | 
|  | bool paused_for_messages_; | 
|  | PortSet<PortSetEntry> | 
|  | ports_;  // Only accessed by [PortMap], protected by [PortMap]s lock. | 
|  | intptr_t live_ports_;  // The number of open ports, including control ports. | 
|  | intptr_t paused_;      // The number of pause messages received. | 
|  | #if !defined(PRODUCT) | 
|  | bool should_pause_on_start_; | 
|  | bool should_pause_on_exit_; | 
|  | bool is_paused_on_start_; | 
|  | bool is_paused_on_exit_; | 
|  | // When isolate gets paused, remember the status of the message being | 
|  | // processed so that we can resume correctly(into potentially not-OK status). | 
|  | MessageStatus remembered_paused_on_exit_status_; | 
|  | int64_t paused_timestamp_; | 
|  | #endif | 
|  | bool task_running_; | 
|  | bool delete_me_; | 
|  | ThreadPool* pool_; | 
|  | StartCallback start_callback_; | 
|  | EndCallback end_callback_; | 
|  | CallbackData callback_data_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(MessageHandler); | 
|  | }; | 
|  |  | 
|  | }  // namespace dart | 
|  |  | 
|  | #endif  // RUNTIME_VM_MESSAGE_HANDLER_H_ |