text: // Copyright 2016 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.
  
  #ifndef GARNET_LIB_INFERIOR_CONTROL_EXCEPTION_PORT_H_
  #define GARNET_LIB_INFERIOR_CONTROL_EXCEPTION_PORT_H_
  
  #include <lib/async/dispatcher.h>
  #include <lib/fit/function.h>
  #include <lib/zx/port.h>
  #include <lib/zx/process.h>
  #include <zircon/syscalls/exception.h>
  #include <zircon/types.h>
  
  #include <atomic>
  #include <mutex>
  #include <thread>
  
  #include "src/lib/fxl/macros.h"
  #include "src/lib/fxl/memory/ref_ptr.h"
  
  namespace inferior_control {
  
  class Thread;
  
  // Maintains a dedicated thread for listening for exceptions and signals
  // from multiple processes and provides an interface that processes can use
  // to subscribe to exception/signal notifications (including their threads).
  class ExceptionPort final {
   public:
    // A Key is vended as a result of a call to Bind()
    using Key = uint64_t;
  
    // Callback invoked when a packet is received.
    using PacketCallback = fit::function<void(const zx_port_packet_t& packet)>;
  
    explicit ExceptionPort(async_dispatcher_t* dispatcher, PacketCallback exception_callback,
                           PacketCallback signal_callback);
    ~ExceptionPort();
  
    // Creates an exception port and starts waiting for events on it in a special
    // thread. Returns false if there is an error during set up.
    bool Run();
  
    // Quits the listening loop, closes the exception port and joins the
    // underlying thread. This must be called AFTER a successful call to Run().
    void Quit();
  
    // Binds an exception port to |process| using key |key|.
    // Returns true on success.
    //
    // The callbacks will be posted on |dispatcher| (args to our constructor).
    //
    // This must be called AFTER a successful call to Run().
    bool Bind(const zx::process& process, Key key);
  
    // Unbinds a previously bound exception port and returns true on success.
    // This must be called AFTER a successful call to Run().
    bool Unbind(const zx::process& process, Key key);
  
    // Async-wait for signals on |thread|.
    // The signals we wait for is determined by the thread's current state.
    // If it's running we wait for it to be suspended (or terminated).
    // If it's suspended we wait for it to be running (or terminated).
    void WaitAsync(Thread* thread);
  
   private:
    // Currently resuming from exceptions requires the exception port handle.
    // This is solely for the benefit of |Server,Thread|.
    // TODO(PT-105): Delete when resuming from exceptions no longer requires the
    // eport handle.
    friend class Server;
    zx_handle_t handle() const { return eport_.get(); }
  
    // The worker function.
    void Worker();
  
    // Set to false by Quit(). This tells |port_thread_| whether it should
    // terminate its loop as soon as zx_port_wait returns.
    std::atomic_bool keep_running_;
  
    // The origin dispatcher to post observer callback events to the thread
    // that created this object.
    async_dispatcher_t* const origin_dispatcher_;
  
    // The exception port used to bind to the inferior.
    // Once created it stays valid until |port_thread_| exits.
    zx::port eport_;
  
    // The thread on which we wait on the exception port.
    std::thread port_thread_;
  
    // The functions to handle exceptions and signals.
    PacketCallback exception_callback_;
    PacketCallback signal_callback_;
  
    FXL_DISALLOW_COPY_AND_ASSIGN(ExceptionPort);
  };
  
  }  // namespace inferior_control
  
  #endif  // GARNET_LIB_INFERIOR_CONTROL_EXCEPTION_PORT_H_
  