text: // Copyright 2019 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 SRC_DEVELOPER_DEBUG_DEBUG_AGENT_LIMBO_PROVIDER_H_
  #define SRC_DEVELOPER_DEBUG_DEBUG_AGENT_LIMBO_PROVIDER_H_
  
  #include <fuchsia/exception/cpp/fidl.h>
  #include <lib/fit/function.h>
  #include <lib/sys/cpp/service_directory.h>
  
  #include <map>
  #include <optional>
  #include <vector>
  
  #include "src/lib/fxl/memory/weak_ptr.h"
  
  namespace debug_agent {
  
  // In charge of providing access to the ProcessLimbo.
  //
  // Fuchsia can be configured to keep processes that have excepted in a suspension state, called
  // Limbo. This provides the possibility for debuggers to attach to those process way after the
  // exception occurred. We call this process Just In Time Debugging (JITD).
  class LimboProvider {
   public:
    using OnEnterLimboCallback =
        fit::function<void(std::vector<fuchsia::exception::ProcessExceptionMetadata>)>;
  
    explicit LimboProvider(std::shared_ptr<sys::ServiceDirectory> services);
    virtual ~LimboProvider();
  
    // Init must be called after constructing the object.
    // It will get the current state of the limbo being connected and then issue async calls to keep
    // that state updated. If the provider is valid, |limbo()| is guaranteed to be up to date.
    //
    // |error_handler| will only be used if |Init| was successful. Once the error handler has been
    // issued, this provider is considered invalid and Init should be called again.
    virtual zx_status_t Init();
  
    // Callback to be called whenever new processes enter the connected limbo.
    // See |on_enter_limbo_| for more details.
    void set_on_enter_limbo(OnEnterLimboCallback cb) { on_enter_limbo_ = std::move(cb); }
  
    // Limbo can fail to initialize (eg. failed to connect). There is no point querying an invalid
    // limbo provider, so callers should check for validity before using it. If the limbo is invalid,
    // callers should either attempt to initialize again or create another limbo provider.
    //
    // NOTE: a valid limbo provider might be inactive (see ProcessLimbo fidl declaration) and/or be
    //       empty (not have any processes waiting on an exception).
    virtual bool Valid() const;
  
    virtual const std::map<zx_koid_t, fuchsia::exception::ProcessExceptionMetadata>& Limbo() const;
  
    virtual zx_status_t RetrieveException(zx_koid_t process_koid,
                                          fuchsia::exception::ProcessException* out);
  
    virtual zx_status_t ReleaseProcess(zx_koid_t process_koid);
  
   protected:
    // Callback to be triggered whenever a new process enters the the limbo. Provides the list of
    // new processes that just entered the limbo on this event. |Limbo()| is up to date at the moment
    // of this callback.
    OnEnterLimboCallback on_enter_limbo_;
  
   private:
    void Reset();
  
    void WatchActive();
    void WatchLimbo();
  
    bool valid_ = false;
  
    // Because the Process Limbo uses hanging gets (async callbacks) and this class exposes a
    // synchronous inteface, we need to keep track of the current state in order to be able to
    // return it immediatelly.
    std::map<zx_koid_t, fuchsia::exception::ProcessExceptionMetadata> limbo_;
  
    bool is_limbo_active_ = false;
  
    fuchsia::exception::ProcessLimboPtr connection_;
  
    std::shared_ptr<sys::ServiceDirectory> services_;
  };
  
  }  // namespace debug_agent
  
  #endif  // SRC_DEVELOPER_DEBUG_DEBUG_AGENT_LIMBO_PROVIDER_H_
  