// Copyright 2015 The Chromium 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 MOJO_CORE_EMBEDDER_SCOPED_IPC_SUPPORT_H_
#define MOJO_CORE_EMBEDDER_SCOPED_IPC_SUPPORT_H_

#include "base/component_export.h"
#include "base/memory/ref_counted.h"

namespace base {
class SingleThreadTaskRunner;
}

namespace mojo {
namespace core {

// A simple class that initialized Mojo IPC support on construction and shuts
// down IPC support on destruction, optionally blocking the destructor on clean
// IPC shutdown completion.
class COMPONENT_EXPORT(MOJO_CORE_EMBEDDER) ScopedIPCSupport {
 public:
  // ShutdownPolicy is a type for specifying the desired Mojo IPC support
  // shutdown behavior used during ScopedIPCSupport destruction.
  //
  // What follows is a quick overview of why shutdown behavior is interesting
  // and how you might decide which behavior is right for your use case.
  //
  // BACKGROUND
  // ==========
  //
  // In order to facilitate efficient and reliable transfer of Mojo message pipe
  // endpoints across process boundaries, the underlying model for a message
  // pipe is actually a self-collapsing cycle of "ports." See
  // //mojo/core/ports for gritty implementation details.
  //
  // Ports are essentially globally unique identifiers used for system-wide
  // message routing. Every message pipe consists of at least two such ports:
  // the pipe's two concrete endpoints.
  //
  // When a message pipe endpoint is transferred over another message pipe, that
  // endpoint's port (which subsequently exists only internally with no
  // publicly-reachable handle) enters a transient proxying state for the
  // remainder of its lifetime. Once sufficient information has been
  // proagated throughout the system and this proxying port can be safely
  // bypassed, it is garbage-collected.
  //
  // If a process is terminated while hosting any active proxy ports, this
  // will necessarily break the message pipe(s) to which those ports belong.
  //
  // WHEN TO USE CLEAN SHUTDOWN
  // ==========================
  //
  // Consider three processes, A, B, and C. Suppose A creates a message pipe,
  // sending one end to B and the other to C. For some brief period of time,
  // messages sent by B or C over this pipe may be proxied through A.
  //
  // If A is suddenly terminated, there may be no way for B's messages to reach
  // C (and vice versa), since the message pipe state may not have been fully
  // propagated to all concerned processes in the system. As such, both B and C
  // may have no choice but to signal peer closure on their respective ends of
  // the pipe, and thus the pipe may be broken despite a lack of intent by
  // either B or C.
  //
  // This can also happen if A creates a pipe and passes one end to B, who then
  // passes it along to C. B may temporarily proxy messages for this pipe
  // between A and C, and B's sudden demise will in turn beget the pipe's
  // own sudden demise.
  //
  // In situations where these sort of arrangements may occur, potentially
  // proxying processes must ensure they are shut down cleanly in order to avoid
  // flaky system behavior.
  //
  // WHEN TO USE FAST SHUTDOWN
  // =========================
  //
  // As a general rule of thumb, if your process never creates a message pipe
  // where both ends are passed to other processes, or never forwards a pipe
  // endpoint from one process to another, fast shutdown is safe. Satisfaction
  // of these constraints can be difficult to prove though, so clean shutdown is
  // a safe default choice.
  //
  // Content renderer processes are a good example of a case where fast shutdown
  // is safe, because as a matter of security and stability, a renderer cannot
  // be trusted to do any proxying on behalf of two other processes anyway.
  //
  // There are other practical scenarios where fast shutdown is safe even if
  // the process may have live proxies. For example, content's browser process
  // is treated as a sort of root process in the system, in the sense that if
  // the browser is terminated, no other part of the system is expected to
  // continue normal operation anyway. In this case the side-effects of fast
  // shutdown are irrelevant, so fast shutdown is preferred.
  enum class ShutdownPolicy {
    // Clean shutdown. This causes the ScopedIPCSupport destructor to *block*
    // the calling thread until clean shutdown is complete. See explanation
    // above for details.
    CLEAN,

    // Fast shutdown. In this case a cheap best-effort attempt is made to
    // shut down the IPC system, but no effort is made to wait for its
    // completion. See explanation above for details.
    FAST,
  };

  ScopedIPCSupport(
      scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner,
      ShutdownPolicy shutdown_policy);

  ScopedIPCSupport(const ScopedIPCSupport&) = delete;
  ScopedIPCSupport& operator=(const ScopedIPCSupport&) = delete;

  ~ScopedIPCSupport();

 private:
  const ShutdownPolicy shutdown_policy_;
};

}  // namespace core
}  // namespace mojo

#endif  // MOJO_CORE_EMBEDDER_SCOPED_IPC_SUPPORT_H_
