Files
swift-mirror/include/swift/AST/PluginRegistry.h
Rintaro Ishizaki 0c9f099d88 [Macros] Add option to disable sandbox for exectuable plugins
`-disable-sandbox` to disable sandboxing when invoking subprocess from
from the frontend. Since `sandbox(7)` in macOS doesn't support nested
sandbox, complation used to fail when the parent build process is sandboxed.
2023-11-27 13:44:40 -08:00

195 lines
6.1 KiB
C++

//===--- PluginRegistry.h ---------------------------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_PLUGIN_REGISTRY_H
#define SWIFT_PLUGIN_REGISTRY_H
#include "swift/Basic/StringExtras.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/Program.h"
#include <mutex>
#include <vector>
namespace swift {
/// Represent a 'dlopen'ed plugin library.
class LoadedLibraryPlugin {
// Opaque handle used to interface with OS-specific dynamic library.
void *handle;
/// Cache of loaded symbols.
llvm::StringMap<void *> resolvedSymbols;
/// Path to the plugin library.
const std::string LibraryPath;
public:
LoadedLibraryPlugin(void *handle, StringRef path)
: handle(handle), LibraryPath(path) {}
/// Finds the address of the given symbol within the library.
void *getAddressOfSymbol(const char *symbolName);
NullTerminatedStringRef getLibraryPath() {
return {LibraryPath.c_str(), LibraryPath.size()};
}
};
/// Represent a "resolved" executable plugin.
///
/// Plugin clients usually deal with this object to communicate with the actual
/// plugin implementation.
/// This object has a file path of the plugin executable, and is responsible to
/// launch it and manages the process. When the plugin process crashes, this
/// should automatically relaunch the process so the clients can keep using this
/// object as the interface.
class LoadedExecutablePlugin {
/// Represents the current process of the executable plugin.
struct PluginProcess {
const llvm::sys::ProcessInfo process;
const int input;
const int output;
bool isStale = false;
PluginProcess(llvm::sys::ProcessInfo process, int input, int output)
: process(process), input(input), output(output) {}
~PluginProcess();
ssize_t write(const void *buf, size_t nbyte) const;
ssize_t read(void *buf, size_t nbyte) const;
};
/// Launched current process.
std::unique_ptr<PluginProcess> Process;
/// Path to the plugin executable.
const std::string ExecutablePath;
/// Last modification time of the `ExecutablePath` when this is initialized.
const llvm::sys::TimePoint<> LastModificationTime;
/// Opaque value of the protocol capability of the pluugin. This is a
/// value from ASTGen.
const void *capability = nullptr;
/// Callbacks to be called when the connection is restored.
llvm::SmallVector<std::function<void(void)> *, 0> onReconnect;
/// Disable sandbox.
bool disableSandbox = false;
/// Flag to dump plugin messagings.
bool dumpMessaging = false;
/// Cleanup function to call ASTGen.
std::function<void(void)> cleanup;
std::mutex mtx;
public:
LoadedExecutablePlugin(llvm::StringRef ExecutablePath,
llvm::sys::TimePoint<> LastModificationTime,
bool disableSandbox)
: ExecutablePath(ExecutablePath),
LastModificationTime(LastModificationTime),
disableSandbox(disableSandbox){};
~LoadedExecutablePlugin();
/// The last modification time of 'ExecutablePath' when this object is
/// created.
llvm::sys::TimePoint<> getLastModificationTime() const {
return LastModificationTime;
}
/// Indicates that the current process is usable.
bool isAlive() const { return Process != nullptr && !Process->isStale; }
/// Mark the current process "stale".
void setStale() const { Process->isStale = true; }
void lock() { mtx.lock(); }
void unlock() { mtx.unlock(); }
// Launch the plugin if it's not already running, or it's stale. Return an
// error if it's fails to execute it.
llvm::Error spawnIfNeeded();
/// Send a message to the plugin.
llvm::Error sendMessage(llvm::StringRef message) const;
/// Wait for a message from plugin and returns it.
llvm::Expected<std::string> waitForNextMessage() const;
bool isInitialized() const { return bool(cleanup); }
void setCleanup(std::function<void(void)> cleanup) {
this->cleanup = cleanup;
}
/// Add "on reconnect" callback.
/// These callbacks are called when `spawnIfNeeded()` relaunched the plugin.
void addOnReconnect(std::function<void(void)> *fn) {
onReconnect.push_back(fn);
}
/// Remove "on reconnect" callback.
void removeOnReconnect(std::function<void(void)> *fn) {
llvm::erase_value(onReconnect, fn);
}
llvm::sys::procid_t getPid() { return Process->process.Pid; }
llvm::sys::process_t getProcess() { return Process->process.Process; }
NullTerminatedStringRef getExecutablePath() {
return {ExecutablePath.c_str(), ExecutablePath.size()};
}
const void *getCapability() { return capability; };
void setCapability(const void *newValue) { capability = newValue; };
void setDumpMessaging(bool flag) { dumpMessaging = flag; }
};
class PluginRegistry {
/// Record of loaded plugin library modules.
llvm::StringMap<std::unique_ptr<LoadedLibraryPlugin>> LoadedPluginLibraries;
/// Record of loaded plugin executables.
llvm::StringMap<std::unique_ptr<LoadedExecutablePlugin>>
LoadedPluginExecutables;
/// Flag to dump plugin messagings.
bool dumpMessaging = false;
std::mutex mtx;
public:
PluginRegistry();
/// Load a dynamic link library specified by \p path.
/// If \p path plugin is already loaded, this returns the cached object.
llvm::Expected<LoadedLibraryPlugin *> loadLibraryPlugin(llvm::StringRef path);
/// Load an executable plugin specified by \p path .
/// If \p path plugin is already loaded, this returns the cached object.
llvm::Expected<LoadedExecutablePlugin *>
loadExecutablePlugin(llvm::StringRef path, bool disableSandbox);
};
} // namespace swift
#endif // SWIFT_PLUGIN_REGISTRY_H