// 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 #include "vm/isolate.h" #include "vm/lockers.h" #include "vm/message.h" #include "vm/os_thread.h" #include "vm/port.h" #include "vm/port_set.h" #include "vm/thread_pool.h" namespace dart { // A MessageHandler is an entity capable of accepting messages. class MessageHandler : public PortHandler { 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(); typedef uword CallbackData; typedef void (*EndCallback)(CallbackData data); // Runs this message handler on the thread pool. // // 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 failed to launch on the thread pool(due to // thread pool shutting down for example), otherwise it returns true. bool Run(ThreadPool* pool, EndCallback end_callback, CallbackData data); // Runs this message handler on current thread. // // 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. void RunSync(); // 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(); // Returns true if there are pending OOB messages for this message // handler. bool HasOOBMessages(); #if defined(TESTING) std::unique_ptr StealOOBMessage(); #endif // Returns true if there are pending normal messages for this message // handler. bool HasMessages(); struct MessageCount { intptr_t num_messages; intptr_t num_oob_messages; }; MessageCount GetMessageCounts(); // Whether to keep this message handler alive or whether it should shutdown. virtual bool KeepAliveLocked() { return true; } bool paused() const { return paused_ > 0; } void increment_paused() { paused_++; } void decrement_paused() { ASSERT(paused_ > 0); paused_--; } #if !defined(PRODUCT) 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 protected: // 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) = 0; virtual void NotifyPauseOnStart() {} virtual void NotifyPauseOnExit() {} // TODO(iposva): Set a local field before entering MessageHandler methods. Thread* thread() const { return Thread::Current(); } // 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, bool before_events = false) override; virtual void set_is_scheduled() {} private: template friend void MournFinalizerEntry(GCVisitorType*, FinalizerEntryPtr); friend class PortMap; friend class MessageHandlerTestPeer; friend class MessageHandlerTask; // ------------ START PortMap API ------------ // These functions should only be called from the PortMap. // Implementaion of PortHandler API. const char* name() const override; void OnPortClosed(Dart_Port port) override; void Shutdown() override { // Nothing to do. } // Return Isolate to which this message handler corresponds to. Isolate* isolate() const override { return nullptr; } PortSet* ports(PortMap::Locker& locker) override { return &ports_; } // Notifies this handler that all ports are being closed. void OnAllPortsClosed(); // ------------ END PortMap API ------------ // 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 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_; // Only accessed by [PortMap], protected by [PortMap]s lock. See ports() // getter. PortSet 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_; ThreadPool* pool_; EndCallback end_callback_; CallbackData callback_data_; DISALLOW_COPY_AND_ASSIGN(MessageHandler); }; } // namespace dart #endif // RUNTIME_VM_MESSAGE_HANDLER_H_