================ @@ -143,6 +169,201 @@ ReplListCompleter::operator()(llvm::StringRef Buffer, size_t Pos, return Comps; } +static llvm::Error sanitizeOopArguments(const char *ArgV0) { + llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); + if ((OutOfProcessExecutor.getNumOccurrences() || + OutOfProcessExecutorConnect.getNumOccurrences()) && + (!SystemTriple.isOSBinFormatELF())) + return llvm::make_error<llvm::StringError>( + "Out-process-executors are currently only supported on ELF", + llvm::inconvertibleErrorCode()); + + // Only one of -oop-executor and -oop-executor-connect can be used. + if (!!OutOfProcessExecutor.getNumOccurrences() && + !!OutOfProcessExecutorConnect.getNumOccurrences()) + return llvm::make_error<llvm::StringError>( + "Only one of -" + OutOfProcessExecutor.ArgStr + " and -" + + OutOfProcessExecutorConnect.ArgStr + " can be specified", + llvm::inconvertibleErrorCode()); + + // If -oop-executor was used but no value was specified then use a sensible + // default. + if (!!OutOfProcessExecutor.getNumOccurrences() && + OutOfProcessExecutor.empty()) { + llvm::SmallString<256> OOPExecutorPath(llvm::sys::fs::getMainExecutable( + ArgV0, reinterpret_cast<void *>(&sanitizeOopArguments))); + llvm::sys::path::remove_filename(OOPExecutorPath); + llvm::sys::path::append(OOPExecutorPath, "llvm-jitlink-executor"); + OutOfProcessExecutor = OOPExecutorPath.str().str(); + } + + // Out-of-process executors must run with the ORC runtime for destructor support. + if (OrcRuntimePath.empty() && (OutOfProcessExecutor.getNumOccurrences() || OutOfProcessExecutorConnect.getNumOccurrences())) { + llvm::SmallString<256> OrcPath(llvm::sys::fs::getMainExecutable( + ArgV0, reinterpret_cast<void *>(&sanitizeOopArguments))); + llvm::sys::path::remove_filename(OrcPath); // Remove clang-repl filename. + llvm::sys::path::remove_filename(OrcPath); // Remove ./bin directory. + llvm::sys::path::append(OrcPath, "lib/clang/18/lib/x86_64-unknown-linux-gnu/liborc_rt.a"); + OrcRuntimePath = OrcPath.str().str(); + } + + return llvm::Error::success(); +} + +static llvm::Expected<std::unique_ptr<llvm::orc::ExecutorProcessControl>> +launchExecutor() { + constexpr int ReadEnd = 0; + constexpr int WriteEnd = 1; + + // Pipe FDs. + int ToExecutor[2]; + int FromExecutor[2]; + + pid_t ChildPID; + + // Create pipes to/from the executor.. + if (pipe(ToExecutor) != 0 || pipe(FromExecutor) != 0) + return llvm::make_error<llvm::StringError>( + "Unable to create pipe for executor", llvm::inconvertibleErrorCode()); + + ChildPID = fork(); + + if (ChildPID == 0) { + // In the child... + + // Close the parent ends of the pipes + close(ToExecutor[WriteEnd]); + close(FromExecutor[ReadEnd]); + + // Execute the child process. + std::unique_ptr<char[]> ExecutorPath, FDSpecifier; + { + ExecutorPath = std::make_unique<char[]>(OutOfProcessExecutor.size() + 1); + strcpy(ExecutorPath.get(), OutOfProcessExecutor.data()); + + std::string FDSpecifierStr("filedescs="); + FDSpecifierStr += llvm::utostr(ToExecutor[ReadEnd]); + FDSpecifierStr += ','; + FDSpecifierStr += llvm::utostr(FromExecutor[WriteEnd]); + FDSpecifier = std::make_unique<char[]>(FDSpecifierStr.size() + 1); + strcpy(FDSpecifier.get(), FDSpecifierStr.c_str()); + } + + char *const Args[] = {ExecutorPath.get(), FDSpecifier.get(), nullptr}; + int RC = execvp(ExecutorPath.get(), Args); + if (RC != 0) { + llvm::errs() << "unable to launch out-of-process executor \"" + << ExecutorPath.get() << "\"\n"; + exit(1); + } + } + // else we're the parent... + + // Close the child ends of the pipes + close(ToExecutor[ReadEnd]); + close(FromExecutor[WriteEnd]); + + auto S = llvm::orc::SimpleRemoteEPC::Setup(); + + return llvm::orc::SimpleRemoteEPC::Create< + llvm::orc::FDSimpleRemoteEPCTransport>( + std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(), + std::move(S), FromExecutor[ReadEnd], ToExecutor[WriteEnd]); +} + +#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS +static llvm::Error createTCPSocketError(llvm::Twine Details) { + return llvm::make_error<llvm::StringError>( + formatv("Failed to connect TCP socket '{0}': {1}", + OutOfProcessExecutorConnect, Details), + llvm::inconvertibleErrorCode()); +} + +static llvm::Expected<int> connectTCPSocket(std::string Host, + std::string PortStr) { + addrinfo *AI; + addrinfo Hints{}; + Hints.ai_family = AF_INET; + Hints.ai_socktype = SOCK_STREAM; + Hints.ai_flags = AI_NUMERICSERV; + + if (int EC = getaddrinfo(Host.c_str(), PortStr.c_str(), &Hints, &AI)) + return createTCPSocketError("Address resolution failed (" + + llvm::StringRef(gai_strerror(EC)) + ")"); + + // Cycle through the returned addrinfo structures and connect to the first + // reachable endpoint. + int SockFD; + addrinfo *Server; + for (Server = AI; Server != nullptr; Server = Server->ai_next) { + // socket might fail, e.g. if the address family is not supported. Skip to + // the next addrinfo structure in such a case. + if ((SockFD = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol)) < 0) + continue; + + // If connect returns null, we exit the loop with a working socket. + if (connect(SockFD, Server->ai_addr, Server->ai_addrlen) == 0) + break; + + close(SockFD); + } + freeaddrinfo(AI); + + // If we reached the end of the loop without connecting to a valid endpoint, + // dump the last error that was logged in socket() or connect(). + if (Server == nullptr) + return createTCPSocketError(std::strerror(errno)); + + return SockFD; +} +#endif + +static llvm::Expected<std::unique_ptr<llvm::orc::ExecutorProcessControl>> +connectToExecutor() { +#ifndef LLVM_ON_UNIX + // FIXME: Add TCP support for Windows. + return llvm::make_error<StringError>( + "-" + OutOfProcessExecutorConnect.ArgStr + + " not supported on non-unix platforms", + inconvertibleErrorCode()); +#elif !LLVM_ENABLE_THREADS + // Out of process mode using SimpleRemoteEPC depends on threads. + return llvm::make_error<StringError>( + "-" + OutOfProcessExecutorConnect.ArgStr + + " requires threads, but LLVM was built with " + "LLVM_ENABLE_THREADS=Off", + inconvertibleErrorCode()); +#else + + llvm::StringRef Host, PortStr; + std::tie(Host, PortStr) = + llvm::StringRef(OutOfProcessExecutorConnect).split(':'); + if (Host.empty()) + return createTCPSocketError("Host name for -" + + OutOfProcessExecutorConnect.ArgStr + + " can not be empty"); + if (PortStr.empty()) + return createTCPSocketError("Port number in -" + + OutOfProcessExecutorConnect.ArgStr + + " can not be empty"); + int Port = 0; + if (PortStr.getAsInteger(10, Port)) + return createTCPSocketError("Port number '" + PortStr + + "' is not a valid integer"); + + llvm::Expected<int> SockFD = connectTCPSocket(Host.str(), PortStr.str()); + if (!SockFD) + return SockFD.takeError(); + + auto S = llvm::orc::SimpleRemoteEPC::Setup(); + + return llvm::orc::SimpleRemoteEPC::Create< + llvm::orc::FDSimpleRemoteEPCTransport>( + std::make_unique<llvm::orc::DynamicThreadPoolTaskDispatcher>(), + std::move(S), *SockFD, *SockFD); +#endif +} ---------------- vgvassilev wrote:
Would these not be useful for the case where a library (libInterpreter) is requested to do oop by user code? https://github.com/llvm/llvm-project/pull/79936 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits