blob: 78bef94914e7dc1b0b57aa6b1558c330eeea3de1 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include "garnet/lib/debug_ipc/helper/message_loop.h"
#include <zx/event.h>
#include <zx/port.h>
#include <zx/thread.h>
namespace debug_ipc {
class ZirconExceptionWatcher;
class SocketWatcher;
class MessageLoopZircon : public MessageLoop {
public:
MessageLoopZircon();
~MessageLoopZircon();
void Init() override;
void Cleanup() override;
// Runs until timeout. Mostly used in tests.
void RunUntilTimeout(zx::duration timeout);
// Returns the current message loop or null if there isn't one.
static MessageLoopZircon* Current();
// MessageLoop implementation.
WatchHandle WatchFD(WatchMode mode, int fd, FDWatcher* watcher) override;
// Watches the given socket for read/write status. The watcher must outlive
// the returned WatchHandle. Must only be called on the message loop thread.
//
// The FDWatcher must not unregister from a callback. The handle might
// become both readable and writable at the same time which will necessitate
// calling both callbacks. The code does not expect the FDWatcher to
// disappear in between these callbacks.
WatchHandle WatchSocket(WatchMode mode, zx_handle_t socket_handle,
SocketWatcher* watcher);
// Attaches to the exception port of the given process and issues callbacks
// on the given watcher. The watcher must outlive the returned WatchHandle.
// Must only be called on the message loop thread.
WatchHandle WatchProcessExceptions(zx_handle_t process_handle,
zx_koid_t process_koid,
ZirconExceptionWatcher* watcher);
// Attaches to the exception port of the given job and issues callbacks
// on the given watcher. The watcher must outlive the returned WatchHandle.
// Must only be called on the message loop thread.
WatchHandle WatchJobExceptions(zx_handle_t job_handle, zx_koid_t job_koid,
ZirconExceptionWatcher* watcher);
// When this class issues an exception notification, the code should call
// this function to resume the thread from the exception. This is a wrapper
// for zx_task_resume_from_exception.
zx_status_t ResumeFromException(zx::thread& thread, uint32_t options);
private:
enum class WatchType { kFdio, kProcessExceptions, kJobExceptions, kSocket };
const char* WatchTypeToString(WatchType);
struct WatchInfo;
// MessageLoop protected implementation.
void RunImpl() override;
void StopWatching(int id) override;
// Triggers an event signaling that there is a pending event.
void SetHasTasks() override;
// Check for any pending C++ tasks and process them.
// Returns true if there was an event pending to be processed.
bool CheckAndProcessPendingTasks();
// Handles WatchHandles event. These are all the events that are not C++ tasks
// posted to the message loop.
void HandleException(zx_port_packet_t packet);
// Handle an event of the given type.
void OnFdioSignal(int watch_id, const WatchInfo& info,
const zx_port_packet_t& packet);
void OnProcessException(const WatchInfo& info,
const zx_port_packet_t& packet);
void OnJobException(const WatchInfo& info, const zx_port_packet_t& packet);
void OnSocketSignal(int watch_id, const WatchInfo& info,
const zx_port_packet_t& packet);
using WatchMap = std::map<int, WatchInfo>;
WatchMap watches_;
// ID used as an index into watches_.
int next_watch_id_ = 1;
zx::port port_;
// This event is signaled when there are tasks to process.
zx::event task_event_;
FXL_DISALLOW_COPY_AND_ASSIGN(MessageLoopZircon);
};
} // namespace debug_ipc