[clang] [clang][MBD] set up module build daemon infrastructure (PR #67562)

Connor Sughrue via cfe-commits cfe-commits at lists.llvm.org
Sat Sep 30 07:50:48 PDT 2023


https://github.com/cpsughrue updated https://github.com/llvm/llvm-project/pull/67562

>From 5def87462e3b48cfebafdc2526ac929f5cb9cea3 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Sun, 9 Jul 2023 23:19:58 -0400
Subject: [PATCH 1/3] [clang][MBD] set up module build daemon infrastructure

The module build daemon (mbd) will serve as a cc1 tool that helps convert
implicit module command lines to explicit module command lines. A clang
invocation will check to see if a mbd exists, if not the invocation will spawn
one. After the mbd is up and running and a handshake has successfully been
carried out between the mbd and clang invocation the clang invocation will
share it's command line with the mbd. The mbd will then scan the translation
unit and build all modular dependencies before returning a modified cc1 command
 line such that all arguments related to modules are converted from the
implicit option to their explicit option.

This commit sets up the basic mbd infrastructure. Including the ability to
spawn a mbd and carry out a handshake between the clang invocation and mbd.

RFC: https://discourse.llvm.org/t/rfc-modules-build-daemon-build-system-agnostic-support-for-explicitly-built-modules/71524
---
 clang/include/clang/Driver/Options.td         |  12 +
 .../include/clang/Frontend/FrontendOptions.h  |   7 +
 .../clang/Tooling/ModuleBuildDaemon/Client.h  |  44 +++
 .../ModuleBuildDaemon/SocketMsgSupport.h      | 134 +++++++++
 .../Tooling/ModuleBuildDaemon/SocketSupport.h |  31 ++
 .../clang/Tooling/ModuleBuildDaemon/Utils.h   |  28 ++
 clang/lib/Driver/ToolChains/Clang.cpp         |  14 +-
 clang/lib/Tooling/CMakeLists.txt              |   1 +
 .../Tooling/ModuleBuildDaemon/CMakeLists.txt  |   9 +
 .../lib/Tooling/ModuleBuildDaemon/Client.cpp  | 167 +++++++++++
 .../ModuleBuildDaemon/SocketSupport.cpp       | 128 +++++++++
 clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp |  32 +++
 clang/test/Driver/unknown-arg.c               |   2 +-
 clang/test/ModuleBuildDaemon/handshake.c      |  18 ++
 clang/test/ModuleBuildDaemon/launch.c         |  14 +
 clang/tools/driver/CMakeLists.txt             |   3 +
 clang/tools/driver/cc1_main.cpp               |  28 +-
 clang/tools/driver/cc1modbuildd_main.cpp      | 267 ++++++++++++++++++
 clang/tools/driver/driver.cpp                 |  17 +-
 19 files changed, 947 insertions(+), 9 deletions(-)
 create mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
 create mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
 create mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
 create mode 100644 clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
 create mode 100644 clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
 create mode 100644 clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
 create mode 100644 clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
 create mode 100644 clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp
 create mode 100644 clang/test/ModuleBuildDaemon/handshake.c
 create mode 100644 clang/test/ModuleBuildDaemon/launch.c
 create mode 100644 clang/tools/driver/cc1modbuildd_main.cpp

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index efd90942948af27..d31d28255e81a8a 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2836,6 +2836,18 @@ defm declspec : BoolOption<"f", "declspec",
   NegFlag<SetFalse, [], [ClangOption], "Disallow">,
   BothFlags<[], [ClangOption, CC1Option],
           " __declspec as a keyword">>, Group<f_clang_Group>;
+
+def fmodule_build_daemon : Flag<["-"], "fmodule-build-daemon">, Group<f_Group>,
+  Flags<[NoXarchOption]>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Enables module build daemon functionality">,
+  MarshallingInfoFlag<FrontendOpts<"ModuleBuildDaemon">>;
+def fmodule_build_daemon_EQ : Joined<["-"], "fmodule-build-daemon=">, Group<f_Group>,
+  Flags<[NoXarchOption]>,
+  Visibility<[ClangOption, CC1Option]>,
+  HelpText<"Enables module build daemon functionality and defines location of output files">,
+  MarshallingInfoString<FrontendOpts<"ModuleBuildDaemonPath">>;
+
 def fmodules_cache_path : Joined<["-"], "fmodules-cache-path=">, Group<i_Group>,
   Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>,
   MetaVarName<"<directory>">,
diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h
index 117e35de6f76c4c..8ce97a57d413c0b 100644
--- a/clang/include/clang/Frontend/FrontendOptions.h
+++ b/clang/include/clang/Frontend/FrontendOptions.h
@@ -350,6 +350,9 @@ class FrontendOptions {
   /// Whether to share the FileManager when building modules.
   unsigned ModulesShareFileManager : 1;
 
+  /// Connect to module build daemon
+  unsigned ModuleBuildDaemon : 1;
+
   CodeCompleteOptions CodeCompleteOpts;
 
   /// Specifies the output format of the AST.
@@ -435,6 +438,10 @@ class FrontendOptions {
   /// The output file, if any.
   std::string OutputFile;
 
+  /// If given, the path to the module build daemon's output files and socket
+  /// address
+  std::string ModuleBuildDaemonPath;
+
   /// If given, the new suffix for fix-it rewritten files.
   std::string FixItSuffix;
 
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
new file mode 100644
index 000000000000000..d7506fa3011cffb
--- /dev/null
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
@@ -0,0 +1,44 @@
+//===----------------------------- Protocol.h -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_CLIENT_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_CLIENT_H
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+
+#define MAX_BUFFER 4096
+#define SOCKET_FILE_NAME "mbd.sock"
+#define STDOUT_FILE_NAME "mbd.out"
+#define STDERR_FILE_NAME "mbd.err"
+
+using namespace clang;
+using namespace llvm;
+
+namespace cc1modbuildd {
+
+// Returns where to store log files and socket address. Of the format
+// /tmp/clang-<BLAKE3HashOfClagnFullVersion>/
+std::string getBasePath();
+
+llvm::Error attemptHandshake(int SocketFD);
+
+llvm::Error spawnModuleBuildDaemon(StringRef BasePath, const char *Argv0);
+
+Expected<int> getModuleBuildDaemon(const char *Argv0, StringRef BasePath);
+
+llvm::Error handshakeModuleBuildDaemon(const CompilerInvocation &Clang,
+                                       const char *Argv0);
+
+} // namespace cc1modbuildd
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_PROTOCAL_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
new file mode 100644
index 000000000000000..16666c177eaa80c
--- /dev/null
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
@@ -0,0 +1,134 @@
+//===------------------------- SocketMsgSupport.h -------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETMSGSUPPORT_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETMSGSUPPORT_H
+
+#include "clang/Tooling/ModuleBuildDaemon/Client.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace cc1modbuildd {
+
+enum class ActionType { HANDSHAKE };
+enum class StatusType { REQUEST, SUCCESS, FAILURE };
+
+struct BaseMsg {
+  ActionType MsgAction;
+  StatusType MsgStatus;
+
+  BaseMsg() = default;
+  BaseMsg(ActionType Action, StatusType Status)
+      : MsgAction(Action), MsgStatus(Status) {}
+};
+
+struct HandshakeMsg : public BaseMsg {
+  HandshakeMsg() = default;
+  HandshakeMsg(ActionType Action, StatusType Status)
+      : BaseMsg(Action, Status) {}
+};
+
+template <typename T> std::string getBufferFromSocketMsg(T Msg) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  std::string Buffer;
+  llvm::raw_string_ostream OS(Buffer);
+  llvm::yaml::Output YamlOut(OS);
+
+  YamlOut << Msg;
+  return Buffer;
+}
+
+template <typename T> Expected<T> getSocketMsgFromBuffer(const char *Buffer) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  T ClientRequest;
+  llvm::yaml::Input YamlIn(Buffer);
+  YamlIn >> ClientRequest;
+
+  if (YamlIn.error()) {
+    std::string Msg = "Syntax or semantic error during YAML parsing";
+    return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+  }
+
+  return ClientRequest;
+}
+
+template <typename T> Expected<T> readSocketMsgFromSocket(int FD) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  Expected<std::string> MaybeResponseBuffer = readFromSocket(FD);
+  if (!MaybeResponseBuffer)
+    return std::move(MaybeResponseBuffer.takeError());
+
+  // Wait for response from module build daemon
+  Expected<T> MaybeResponse =
+      getSocketMsgFromBuffer<T>(std::move(*MaybeResponseBuffer).c_str());
+  if (!MaybeResponse)
+    return std::move(MaybeResponse.takeError());
+  return std::move(*MaybeResponse);
+}
+
+template <typename T> llvm::Error writeSocketMsgToSocket(T Msg, int FD) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  std::string Buffer = getBufferFromSocketMsg(Msg);
+  if (llvm::Error Err = writeToSocket(Buffer, FD))
+    return std::move(Err);
+
+  return llvm::Error::success();
+}
+
+template <typename T>
+Expected<int> connectAndWriteSocketMsgToSocket(T Msg, StringRef SocketPath) {
+  static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
+                "T must inherit from cc1modbuildd::BaseMsg");
+
+  Expected<int> MaybeFD = connectToSocket(SocketPath);
+  if (!MaybeFD)
+    return std::move(MaybeFD.takeError());
+  int FD = std::move(*MaybeFD);
+
+  if (llvm::Error Err = writeSocketMsgToSocket(Msg, FD))
+    return std::move(Err);
+
+  return FD;
+}
+
+} // namespace cc1modbuildd
+
+template <>
+struct llvm::yaml::ScalarEnumerationTraits<cc1modbuildd::StatusType> {
+  static void enumeration(IO &Io, cc1modbuildd::StatusType &Value) {
+    Io.enumCase(Value, "REQUEST", cc1modbuildd::StatusType::REQUEST);
+    Io.enumCase(Value, "SUCCESS", cc1modbuildd::StatusType::SUCCESS);
+    Io.enumCase(Value, "FAILURE", cc1modbuildd::StatusType::FAILURE);
+  }
+};
+
+template <>
+struct llvm::yaml::ScalarEnumerationTraits<cc1modbuildd::ActionType> {
+  static void enumeration(IO &Io, cc1modbuildd::ActionType &Value) {
+    Io.enumCase(Value, "HANDSHAKE", cc1modbuildd::ActionType::HANDSHAKE);
+  }
+};
+
+template <> struct llvm::yaml::MappingTraits<cc1modbuildd::HandshakeMsg> {
+  static void mapping(IO &Io, cc1modbuildd::HandshakeMsg &Info) {
+    Io.mapRequired("Action", Info.MsgAction);
+    Io.mapRequired("Status", Info.MsgStatus);
+  }
+};
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETMSGSUPPORT_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
new file mode 100644
index 000000000000000..bc21084faab3966
--- /dev/null
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
@@ -0,0 +1,31 @@
+//===-------------------------- SocketSupport.h ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
+
+#include "clang/Frontend/CompilerInstance.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace cc1modbuildd {
+
+Expected<int> createSocket();
+Expected<int> connectToSocket(StringRef SocketPath);
+Expected<int> connectAndWriteToSocket(std::string Buffer, StringRef SocketPath);
+Expected<std::string> readFromSocket(int FD);
+llvm::Error writeToSocket(std::string Buffer, int WriteFD);
+
+} // namespace cc1modbuildd
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_SOCKETSUPPORT_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
new file mode 100644
index 000000000000000..000081be92793cb
--- /dev/null
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
@@ -0,0 +1,28 @@
+//===------------------------------ Utils.h -------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions required by both the module build daemon (server) and clang
+// invocation (client)
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_UTILS_H
+#define LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_UTILS_H
+
+#include "llvm/Support/Error.h"
+#include <string>
+
+namespace cc1modbuildd {
+
+void writeError(llvm::Error Err, std::string Msg);
+std::string getFullErrorMsg(llvm::Error Err, std::string Msg);
+llvm::Error makeStringError(llvm::Error Err, std::string Msg);
+
+} // namespace cc1modbuildd
+
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_UTILS_H
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index a694d00b569a590..2d003baf39572f5 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5,7 +5,6 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
-
 #include "Clang.h"
 #include "AMDGPU.h"
 #include "Arch/AArch64.h"
@@ -3738,6 +3737,19 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D,
        Std->containsValue("c++latest") || Std->containsValue("gnu++latest"));
   bool HaveModules = HaveStdCXXModules;
 
+  // -fmodule-build-daemon enables module build daemon functionality
+  if (Args.hasArg(options::OPT_fmodule_build_daemon))
+    Args.AddLastArg(CmdArgs, options::OPT_fmodule_build_daemon);
+
+  // by default module build daemon socket address and output files are saved
+  // under /tmp/ but that can be overridden by providing the
+  // -fmodule-build-daemon=<path> flag
+  if (Arg *A = Args.getLastArg(options::OPT_fmodule_build_daemon_EQ)) {
+    CmdArgs.push_back(
+        Args.MakeArgString(Twine("-fmodule-build-daemon=") + A->getValue()));
+    CmdArgs.push_back("-fmodule-build-daemon");
+  }
+
   // -fmodules enables the use of precompiled modules (off by default).
   // Users can pass -fno-cxx-modules to turn off modules support for
   // C++/Objective-C++ programs.
diff --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt
index aff39e4de13c0b2..85752e577332650 100644
--- a/clang/lib/Tooling/CMakeLists.txt
+++ b/clang/lib/Tooling/CMakeLists.txt
@@ -13,6 +13,7 @@ add_subdirectory(DumpTool)
 add_subdirectory(Syntax)
 add_subdirectory(DependencyScanning)
 add_subdirectory(Transformer)
+add_subdirectory(ModuleBuildDaemon)
 
 # Replace the last lib component of the current binary directory with include
 string(FIND ${CMAKE_CURRENT_BINARY_DIR} "/lib/" PATH_LIB_START REVERSE)
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt b/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
new file mode 100644
index 000000000000000..9c1f5dc1aa2c0c0
--- /dev/null
+++ b/clang/lib/Tooling/ModuleBuildDaemon/CMakeLists.txt
@@ -0,0 +1,9 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+
+add_clang_library(clangModuleBuildDaemon
+  Client.cpp
+  SocketSupport.cpp
+  Utils.cpp
+  )
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp b/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
new file mode 100644
index 000000000000000..f247c4c64da957a
--- /dev/null
+++ b/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
@@ -0,0 +1,167 @@
+//===----------------------------- Client.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ModuleBuildDaemon/Client.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/Utils.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/BLAKE3.h"
+
+// TODO: Make portable
+#if LLVM_ON_UNIX
+
+#include <cerrno>
+#include <filesystem>
+#include <fstream>
+#include <signal.h>
+#include <spawn.h>
+#include <string>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+using namespace clang;
+using namespace llvm;
+using namespace cc1modbuildd;
+
+std::string cc1modbuildd::getBasePath() {
+  llvm::BLAKE3 Hash;
+  Hash.update(getClangFullVersion());
+  auto HashResult = Hash.final<sizeof(uint64_t)>();
+  uint64_t HashValue =
+      llvm::support::endian::read<uint64_t, llvm::support::native>(
+          HashResult.data());
+  std::string Key = toString(llvm::APInt(64, HashValue), 36, /*Signed*/ false);
+
+  // set paths
+  SmallString<128> BasePath;
+  llvm::sys::path::system_temp_directory(/*erasedOnReboot*/ true, BasePath);
+  llvm::sys::path::append(BasePath, "clang-" + Key);
+  return BasePath.c_str();
+}
+
+llvm::Error cc1modbuildd::attemptHandshake(int SocketFD) {
+
+  HandshakeMsg Request{ActionType::HANDSHAKE, StatusType::REQUEST};
+  std::string Buffer = getBufferFromSocketMsg(Request);
+
+  if (llvm::Error Err = writeToSocket(Buffer, SocketFD))
+    return std::move(Err);
+
+  Expected<HandshakeMsg> MaybeServerResponse =
+      readSocketMsgFromSocket<HandshakeMsg>(SocketFD);
+  if (!MaybeServerResponse)
+    return std::move(MaybeServerResponse.takeError());
+
+  HandshakeMsg ServerResponse = std::move(*MaybeServerResponse);
+
+  assert(ServerResponse.MsgAction == ActionType::HANDSHAKE &&
+         "At this point response ActionType should only ever be HANDSHAKE");
+
+  if (ServerResponse.MsgStatus == StatusType::SUCCESS)
+    return llvm::Error::success();
+
+  return llvm::make_error<StringError>(
+      "Received failed handshake response from module build daemon",
+      inconvertibleErrorCode());
+}
+
+llvm::Error cc1modbuildd::spawnModuleBuildDaemon(StringRef BasePath,
+                                                 const char *Argv0) {
+  std::string BasePathStr = BasePath.str();
+  const char *Args[] = {Argv0, "-cc1modbuildd", BasePathStr.c_str(), nullptr};
+  pid_t pid;
+  int EC = posix_spawn(&pid, Args[0],
+                       /*file_actions*/ nullptr,
+                       /*spawnattr*/ nullptr, const_cast<char **>(Args),
+                       /*envp*/ nullptr);
+  if (EC)
+    return createStringError(std::error_code(EC, std::generic_category()),
+                             "failed to spawn module build daemon");
+
+  return llvm::Error::success();
+}
+
+Expected<int> cc1modbuildd::getModuleBuildDaemon(const char *Argv0,
+                                                 StringRef BasePath) {
+
+  SmallString<128> SocketPath = BasePath;
+  llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
+
+  if (llvm::sys::fs::exists(SocketPath)) {
+    Expected<int> MaybeFD = connectToSocket(SocketPath);
+    if (MaybeFD)
+      return std::move(*MaybeFD);
+    consumeError(MaybeFD.takeError());
+  }
+
+  if (llvm::Error Err = cc1modbuildd::spawnModuleBuildDaemon(BasePath, Argv0))
+    return std::move(Err);
+
+  const unsigned int MICROSEC_IN_SEC = 1000000;
+  constexpr unsigned int MAX_TIME = 30 * MICROSEC_IN_SEC;
+  const unsigned short INTERVAL = 100;
+
+  unsigned int CumulativeTime = 0;
+  unsigned int WaitTime = 0;
+
+  while (CumulativeTime <= MAX_TIME) {
+    // Wait a bit then check to see if the module build daemon has initialized
+    usleep(WaitTime);
+
+    if (llvm::sys::fs::exists(SocketPath)) {
+      Expected<int> MaybeFD = connectToSocket(SocketPath);
+      if (MaybeFD)
+        return std::move(*MaybeFD);
+      consumeError(MaybeFD.takeError());
+    }
+
+    CumulativeTime += INTERVAL;
+  }
+
+  // After waiting 30 seconds give up
+  return llvm::make_error<StringError>(
+      "Module build daemon could not be spawned", inconvertibleErrorCode());
+}
+
+llvm::Error
+cc1modbuildd::handshakeModuleBuildDaemon(const CompilerInvocation &Clang,
+                                         const char *Argv0) {
+
+  // The module build daemon stores all output files and its socket address
+  // under BasePath. Either set BasePath to a user provided option or create an
+  // appropriate BasePath based on the hash of the clang version
+  std::string BasePath;
+  if (!Clang.getFrontendOpts().ModuleBuildDaemonPath.empty())
+    BasePath = Clang.getFrontendOpts().ModuleBuildDaemonPath;
+  else
+    BasePath = cc1modbuildd::getBasePath();
+
+  // If module build daemon does not exist spawn module build daemon
+  Expected<int> MaybeDaemonFD =
+      cc1modbuildd::getModuleBuildDaemon(Argv0, BasePath);
+  if (!MaybeDaemonFD)
+    return makeStringError(MaybeDaemonFD.takeError(),
+                           "Attempt to connect to daemon has failed: ");
+  int DaemonFD = std::move(*MaybeDaemonFD);
+
+  if (llvm::Error HandshakeErr = attemptHandshake(DaemonFD))
+    return makeStringError(std::move(HandshakeErr),
+                           "Attempted hadshake with daemon has failed: ");
+
+  return llvm::Error::success();
+}
+
+#endif // LLVM_ON_UNIX
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
new file mode 100644
index 000000000000000..58526e4422f457b
--- /dev/null
+++ b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
@@ -0,0 +1,128 @@
+//===------------------------- SocketSupport.cpp --------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+#include "clang/Basic/Version.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Tooling/ModuleBuildDaemon/Client.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ScopeExit.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/Support/BLAKE3.h"
+
+// TODO: Make portable
+#if LLVM_ON_UNIX
+
+#include <cerrno>
+#include <filesystem>
+#include <fstream>
+#include <signal.h>
+#include <spawn.h>
+#include <string>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+Expected<int> cc1modbuildd::createSocket() {
+  int FD;
+  if ((FD = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+    std::string Msg = "socket create error: " + std::string(strerror(errno));
+    return createStringError(inconvertibleErrorCode(), Msg);
+  }
+  return FD;
+}
+
+Expected<int> cc1modbuildd::connectToSocket(StringRef SocketPath) {
+
+  Expected<int> MaybeFD = cc1modbuildd::createSocket();
+  if (!MaybeFD)
+    return std::move(MaybeFD.takeError());
+
+  int FD = std::move(*MaybeFD);
+
+  struct sockaddr_un Addr;
+  memset(&Addr, 0, sizeof(Addr));
+  Addr.sun_family = AF_UNIX;
+  strncpy(Addr.sun_path, SocketPath.str().c_str(), sizeof(Addr.sun_path) - 1);
+
+  if (connect(FD, (struct sockaddr *)&Addr, sizeof(Addr)) == -1) {
+    close(FD);
+    std::string msg = "socket connect error: " + std::string(strerror(errno));
+    return createStringError(inconvertibleErrorCode(), msg);
+  }
+  return FD;
+}
+
+Expected<int> cc1modbuildd::connectAndWriteToSocket(std::string Buffer,
+                                                    StringRef SocketPath) {
+
+  Expected<int> MaybeConnectedFD = connectToSocket(SocketPath);
+  if (!MaybeConnectedFD)
+    return std::move(MaybeConnectedFD.takeError());
+
+  int ConnectedFD = std::move(*MaybeConnectedFD);
+  llvm::Error Err = writeToSocket(Buffer, ConnectedFD);
+  if (Err)
+    return std::move(Err);
+
+  return ConnectedFD;
+}
+
+Expected<std::string> cc1modbuildd::readFromSocket(int FD) {
+
+  const size_t BUFFER_SIZE = 4096;
+  std::vector<char> Buffer(BUFFER_SIZE);
+  size_t TotalBytesRead = 0;
+
+  ssize_t n;
+  while ((n = read(FD, Buffer.data() + TotalBytesRead,
+                   Buffer.size() - TotalBytesRead)) > 0) {
+
+    TotalBytesRead += n;
+    // Read until ...\n encountered (last line of YAML document)
+    if (std::string(&Buffer[TotalBytesRead - 4], 4) == "...\n")
+      break;
+    if (Buffer.size() - TotalBytesRead < BUFFER_SIZE)
+      Buffer.resize(Buffer.size() + BUFFER_SIZE);
+  }
+
+  if (n < 0) {
+    std::string Msg = "socket read error: " + std::string(strerror(errno));
+    return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+  }
+  if (n == 0)
+    return llvm::make_error<StringError>("EOF", inconvertibleErrorCode());
+  return std::string(Buffer.begin(), Buffer.end());
+}
+
+llvm::Error cc1modbuildd::writeToSocket(std::string Buffer, int WriteFD) {
+
+  ssize_t BytesToWrite = static_cast<ssize_t>(Buffer.size());
+  const char *Bytes = Buffer.c_str();
+
+  while (BytesToWrite) {
+    ssize_t BytesWritten = write(WriteFD, Bytes, BytesToWrite);
+    if (BytesWritten == -1) {
+      std::string Msg = "socket write error: " + std::string(strerror(errno));
+      return llvm::make_error<StringError>(Msg, inconvertibleErrorCode());
+    }
+
+    if (!BytesWritten || BytesWritten > BytesToWrite)
+      return llvm::errorCodeToError(
+          std::error_code(EIO, std::generic_category()));
+
+    BytesToWrite -= BytesWritten;
+    Bytes += BytesWritten;
+  }
+  return llvm::Error::success();
+}
+
+#endif // LLVM_ON_UNIX
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp b/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp
new file mode 100644
index 000000000000000..0e291987faf93f8
--- /dev/null
+++ b/clang/lib/Tooling/ModuleBuildDaemon/Utils.cpp
@@ -0,0 +1,32 @@
+//===------------------------------ Utils.cpp -----------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <clang/Tooling/ModuleBuildDaemon/Utils.h>
+#include <llvm/Support/Error.h>
+#include <string>
+
+using namespace llvm;
+
+void cc1modbuildd::writeError(llvm::Error Err, std::string Msg) {
+  handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+    errs() << Msg << EIB.message() << '\n';
+  });
+}
+
+std::string cc1modbuildd::getFullErrorMsg(llvm::Error Err, std::string Msg) {
+  std::string ErrMessage;
+  handleAllErrors(std::move(Err), [&](ErrorInfoBase &EIB) {
+    ErrMessage = Msg + EIB.message();
+  });
+  return ErrMessage;
+}
+
+llvm::Error cc1modbuildd::makeStringError(llvm::Error Err, std::string Msg) {
+  std::string ErrMsg = getFullErrorMsg(std::move(Err), Msg);
+  return llvm::make_error<StringError>(ErrMsg, inconvertibleErrorCode());
+}
diff --git a/clang/test/Driver/unknown-arg.c b/clang/test/Driver/unknown-arg.c
index 52ea0f5ff3220fc..3a22b824adc5c74 100644
--- a/clang/test/Driver/unknown-arg.c
+++ b/clang/test/Driver/unknown-arg.c
@@ -59,7 +59,7 @@
 // SILENT-NOT: warning:
 // CC1AS-DID-YOU-MEAN: error: unknown argument '-hell'; did you mean '-help'?
 // CC1AS-DID-YOU-MEAN: error: unknown argument '--version'; did you mean '-version'?
-// UNKNOWN-INTEGRATED: error: unknown integrated tool '-cc1asphalt'. Valid tools include '-cc1' and '-cc1as'.
+// UNKNOWN-INTEGRATED: error: unknown integrated tool '-cc1asphalt'. Valid tools include '-cc1', '-cc1as', '-cc1gen-reproducer', and '-cc1modbuildd'.
 
 // RUN: %clang -S %s -o %t.s  -Wunknown-to-clang-option 2>&1 | FileCheck --check-prefix=IGNORED %s
 
diff --git a/clang/test/ModuleBuildDaemon/handshake.c b/clang/test/ModuleBuildDaemon/handshake.c
new file mode 100644
index 000000000000000..ac9a5ebab87e4de
--- /dev/null
+++ b/clang/test/ModuleBuildDaemon/handshake.c
@@ -0,0 +1,18 @@
+// Check that clang invocation can spawn and handshake with module build daemon
+
+// REQUIRES: !system-windows
+
+//  RUN: if pgrep -f "cc1modbuildd mbd-handshake"; then pkill -f "cc1modbuildd mbd-handshake"; fi
+//  RUN: rm -rf mbd-handshake %t
+//  RUN: split-file %s %t
+
+//--- main.c
+int main() {return 0;}
+
+// RUN: %clang -fmodule-build-daemon=mbd-handshake %t/main.c > output
+// RUN: cat output | FileCheck %s
+
+// CHECK: Completed successfull handshake with module build daemon
+
+// RUN: if pgrep -f "cc1modbuildd mbd-handshake"; then pkill -f "cc1modbuildd mbd-handshake"; fi
+// RUN: rm -rf mbd-handshake %t
diff --git a/clang/test/ModuleBuildDaemon/launch.c b/clang/test/ModuleBuildDaemon/launch.c
new file mode 100644
index 000000000000000..878bdfa4052f542
--- /dev/null
+++ b/clang/test/ModuleBuildDaemon/launch.c
@@ -0,0 +1,14 @@
+// Check that module build daemon can create unix socket
+
+// REQUIRES: !system-windows
+
+// RUN: if pgrep -f "cc1modbuildd mbd-launch"; then pkill -f "cc1modbuildd mbd-launch"; fi
+// RUN: rm -rf mbd-launch %t
+
+// RUN: %clang -cc1modbuildd mbd-launch -v
+// RUN: cat mbd-launch/mbd.out | FileCheck %s
+
+// CHECK: mbd created and binded to socket address at: mbd-launch/mbd.sock
+
+// RUN: if pgrep -f "cc1modbuildd mbd-launch"; then pkill -f "cc1modbuildd mbd-launch"; fi
+// RUN: rm -rf mbd-launch %t
diff --git a/clang/tools/driver/CMakeLists.txt b/clang/tools/driver/CMakeLists.txt
index 2182486f93a5553..9f4c7a01f848938 100644
--- a/clang/tools/driver/CMakeLists.txt
+++ b/clang/tools/driver/CMakeLists.txt
@@ -28,6 +28,7 @@ add_clang_tool(clang
   cc1_main.cpp
   cc1as_main.cpp
   cc1gen_reproducer_main.cpp
+  cc1modbuildd_main.cpp
 
   DEPENDS
   intrinsics_gen
@@ -39,9 +40,11 @@ clang_target_link_libraries(clang
   PRIVATE
   clangBasic
   clangCodeGen
+  clangDependencyScanning
   clangDriver
   clangFrontend
   clangFrontendTool
+  clangModuleBuildDaemon
   clangSerialization
   )
 
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index e9d2c6aad371dbb..25db6bf09082e0d 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -25,6 +25,7 @@
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Frontend/Utils.h"
 #include "clang/FrontendTool/Utils.h"
+#include "clang/Tooling/ModuleBuildDaemon/Client.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/Config/llvm-config.h"
 #include "llvm/LinkAllPasses.h"
@@ -63,7 +64,7 @@ using namespace llvm::opt;
 
 static void LLVMErrorHandler(void *UserData, const char *Message,
                              bool GenCrashDiag) {
-  DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
+  DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine *>(UserData);
 
   Diags.Report(diag::err_fe_error_backend) << Message;
 
@@ -201,7 +202,7 @@ static int PrintSupportedExtensions(std::string TargetStr) {
   const llvm::Triple &MachineTriple = TheTargetMachine->getTargetTriple();
   const llvm::MCSubtargetInfo *MCInfo = TheTargetMachine->getMCSubtargetInfo();
   const llvm::ArrayRef<llvm::SubtargetFeatureKV> Features =
-    MCInfo->getAllProcessorFeatures();
+      MCInfo->getAllProcessorFeatures();
 
   llvm::StringMap<llvm::StringRef> DescMap;
   for (const llvm::SubtargetFeatureKV &feature : Features)
@@ -270,7 +271,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
       Clang->getHeaderSearchOpts().ResourceDir.empty())
     Clang->getHeaderSearchOpts().ResourceDir =
-      CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
+        CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
 
   // Create the actual diagnostics engine.
   Clang->createDiagnostics();
@@ -279,8 +280,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
 
   // Set an error handler, so that any LLVM backend diagnostics go through our
   // error handler.
-  llvm::install_fatal_error_handler(LLVMErrorHandler,
-                                  static_cast<void*>(&Clang->getDiagnostics()));
+  llvm::install_fatal_error_handler(
+      LLVMErrorHandler, static_cast<void *>(&Clang->getDiagnostics()));
 
   DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
   if (!Success) {
@@ -288,6 +289,23 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
     return 1;
   }
 
+#if LLVM_ON_UNIX
+  // Handle module build daemon functionality if enabled
+  if (Clang->getFrontendOpts().ModuleBuildDaemon) {
+
+    llvm::Error HandshakeErr =
+        cc1modbuildd::handshakeModuleBuildDaemon(Clang->getInvocation(), Argv0);
+    if (HandshakeErr) {
+      handleAllErrors(std::move(HandshakeErr), [&](ErrorInfoBase &EIB) {
+        errs() << EIB.message() << '\n';
+      });
+      return 1;
+    }
+    outs() << "Completed successfull handshake with module build daemon"
+           << '\n';
+  }
+#endif
+
   // Execute the frontend actions.
   {
     llvm::TimeTraceScope TimeScope("ExecuteCompiler");
diff --git a/clang/tools/driver/cc1modbuildd_main.cpp b/clang/tools/driver/cc1modbuildd_main.cpp
new file mode 100644
index 000000000000000..bb8ace9dfde6510
--- /dev/null
+++ b/clang/tools/driver/cc1modbuildd_main.cpp
@@ -0,0 +1,267 @@
+//===------- cc1modbuildd_main.cpp - Clang CC1 Module Build Daemon --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/SocketSupport.h"
+#include "clang/Tooling/ModuleBuildDaemon/Utils.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Program.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/Threading.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
+
+// TODO: Make portable
+#if LLVM_ON_UNIX
+
+#include <errno.h>
+#include <fstream>
+#include <mutex>
+#include <optional>
+#include <signal.h>
+#include <sstream>
+#include <stdbool.h>
+#include <string>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <type_traits>
+#include <unistd.h>
+#include <unordered_map>
+
+using namespace llvm;
+using namespace clang;
+using namespace cc1modbuildd;
+
+// Create unbuffered STDOUT stream so that any logging done by module build
+// daemon can be viewed without having to terminate the process
+static raw_fd_ostream &unbuff_outs() {
+  static raw_fd_ostream S(STDOUT_FILENO, false, true);
+  return S;
+}
+
+namespace {
+
+class ModuleBuildDaemonServer {
+public:
+  SmallString<128> BasePath;
+  SmallString<128> SocketPath;
+  SmallString<128> PidPath;
+
+  ModuleBuildDaemonServer(SmallString<128> Path, ArrayRef<const char *> Argv)
+      : BasePath(Path), SocketPath(Path) {
+    llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
+  }
+
+  ~ModuleBuildDaemonServer() { shutdownDaemon(SIGTERM); }
+
+  int forkDaemon();
+  int launchDaemon();
+  int listenForClients();
+
+  static void handleClient(int Client);
+
+  void shutdownDaemon(int signal) {
+    unlink(SocketPath.c_str());
+    shutdown(ListenSocketFD, SHUT_RD);
+    close(ListenSocketFD);
+    exit(EXIT_SUCCESS);
+  }
+
+private:
+  // Initializes and returns DiagnosticsEngine
+  pid_t Pid = -1;
+  int ListenSocketFD = -1;
+};
+
+// Required to handle SIGTERM by calling Shutdown
+ModuleBuildDaemonServer *DaemonPtr = nullptr;
+void handleSignal(int Signal) {
+  if (DaemonPtr != nullptr) {
+    DaemonPtr->shutdownDaemon(Signal);
+  }
+}
+} // namespace
+
+static bool verbose = false;
+static void verbose_print(const llvm::Twine &message) {
+  if (verbose) {
+    unbuff_outs() << message << '\n';
+  }
+}
+
+// Forks and detaches process, creating module build daemon
+int ModuleBuildDaemonServer::forkDaemon() {
+
+  pid_t pid = fork();
+
+  if (pid < 0) {
+    exit(EXIT_FAILURE);
+  }
+  if (pid > 0) {
+    exit(EXIT_SUCCESS);
+  }
+
+  Pid = getpid();
+
+  close(STDIN_FILENO);
+  close(STDOUT_FILENO);
+  close(STDERR_FILENO);
+
+  SmallString<128> STDOUT = BasePath;
+  llvm::sys::path::append(STDOUT, STDOUT_FILE_NAME);
+  freopen(STDOUT.c_str(), "a", stdout);
+
+  SmallString<128> STDERR = BasePath;
+  llvm::sys::path::append(STDERR, STDERR_FILE_NAME);
+  freopen(STDERR.c_str(), "a", stderr);
+
+  if (signal(SIGTERM, handleSignal) == SIG_ERR) {
+    errs() << "failed to handle SIGTERM" << '\n';
+    exit(EXIT_FAILURE);
+  }
+  if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
+    errs() << "failed to ignore SIGHUP" << '\n';
+    exit(EXIT_FAILURE);
+  }
+  if (setsid() == -1) {
+    errs() << "setsid failed" << '\n';
+    exit(EXIT_FAILURE);
+  }
+
+  return EXIT_SUCCESS;
+}
+
+// Creates unix socket for IPC with module build daemon
+int ModuleBuildDaemonServer::launchDaemon() {
+
+  // new socket
+  if ((ListenSocketFD = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+    std::perror("Socket create error: ");
+    exit(EXIT_FAILURE);
+  }
+
+  struct sockaddr_un addr;
+  memset(&addr, 0, sizeof(struct sockaddr_un));
+  addr.sun_family = AF_UNIX;
+  strncpy(addr.sun_path, SocketPath.c_str(), sizeof(addr.sun_path) - 1);
+
+  // bind to local address
+  if (bind(ListenSocketFD, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
+
+    // If the socket address is already in use, exit because another module
+    // build daemon has successfully launched. When translation units are
+    // compiled in parallel, until the socket file is created, all clang
+    // invocations will spawn a module build daemon.
+    if (errno == EADDRINUSE) {
+      close(ListenSocketFD);
+      exit(EXIT_SUCCESS);
+    }
+    std::perror("Socket bind error: ");
+    exit(EXIT_FAILURE);
+  }
+  verbose_print("mbd created and binded to socket address at: " + SocketPath);
+
+  // set socket to accept incoming connection request
+  unsigned MaxBacklog = llvm::hardware_concurrency().compute_thread_count();
+  if (listen(ListenSocketFD, MaxBacklog) == -1) {
+    std::perror("Socket listen error: ");
+    exit(EXIT_FAILURE);
+  }
+
+  return 0;
+}
+
+// Function submitted to thread pool with each client connection. Not
+// responsible for closing client connections
+void ModuleBuildDaemonServer::handleClient(int Client) {
+
+  // Read handshake from client
+  Expected<HandshakeMsg> MaybeHandshakeMsg =
+      readSocketMsgFromSocket<HandshakeMsg>(Client);
+
+  if (!MaybeHandshakeMsg) {
+    writeError(MaybeHandshakeMsg.takeError(),
+               "Failed to read handshake message from socket: ");
+    return;
+  }
+
+  // Handle HANDSHAKE
+  HandshakeMsg Msg(ActionType::HANDSHAKE, StatusType::SUCCESS);
+  llvm::Error WriteErr = writeSocketMsgToSocket(Msg, Client);
+
+  if (WriteErr) {
+    writeError(std::move(WriteErr),
+               "Failed to notify client that handshake was received");
+    return;
+  }
+  return;
+}
+
+int ModuleBuildDaemonServer::listenForClients() {
+
+  llvm::ThreadPool Pool;
+  int Client;
+
+  while (true) {
+
+    if ((Client = accept(ListenSocketFD, NULL, NULL)) == -1) {
+      std::perror("Socket accept error: ");
+      continue;
+    }
+
+    Pool.async(handleClient, Client);
+  }
+  return 0;
+}
+
+// Module build daemon is spawned with the following command line:
+//
+// clang -cc1modbuildd <path> -v
+//
+// <path> defines the location of all files created by the module build daemon
+// and should follow the format /path/to/dir. For example, `clang
+// -cc1modbuildd /tmp/` creates a socket file at `/tmp/mbd.sock`
+//
+// When a module build daemon is spawned by a cc1 invocations, <path> follows
+// the format /tmp/clang-<BLAKE3HashOfClangFullVersion> and looks something like
+// /tmp/clang-3NXKISKJ0WJTN
+//
+// -v is optional and provides berbose debug information
+//
+int cc1modbuildd_main(ArrayRef<const char *> Argv) {
+
+  if (Argv.size() < 1) {
+    outs() << "spawning a module build daemon requies a command line format of "
+              "`clang -cc1modbuildd <path>`. <path> defines where the module "
+              "build daemon will create mbd.out, mbd.err, mbd.sock"
+           << '\n';
+    return 1;
+  }
+
+  // Where to store log files and socket address
+  // TODO: Add check to confirm BasePath is directory
+  SmallString<128> BasePath(Argv[0]);
+  llvm::sys::fs::create_directories(BasePath);
+  ModuleBuildDaemonServer Daemon(BasePath, Argv);
+
+  // Used to handle signals
+  DaemonPtr = &Daemon;
+
+  if (find(Argv, StringRef("-v")) != Argv.end())
+    verbose = true;
+
+  Daemon.forkDaemon();
+  Daemon.launchDaemon();
+  Daemon.listenForClients();
+
+  return 0;
+}
+
+#endif // LLVM_ON_UNIX
diff --git a/clang/tools/driver/driver.cpp b/clang/tools/driver/driver.cpp
index 531b5b4a61c1804..9697bc6d457776d 100644
--- a/clang/tools/driver/driver.cpp
+++ b/clang/tools/driver/driver.cpp
@@ -213,6 +213,9 @@ extern int cc1as_main(ArrayRef<const char *> Argv, const char *Argv0,
 extern int cc1gen_reproducer_main(ArrayRef<const char *> Argv,
                                   const char *Argv0, void *MainAddr,
                                   const llvm::ToolContext &);
+#if LLVM_ON_UNIX
+extern int cc1modbuildd_main(ArrayRef<const char *> Argv);
+#endif
 
 static void insertTargetAndModeArgs(const ParsedClangName &NameParts,
                                     SmallVectorImpl<const char *> &ArgVector,
@@ -369,9 +372,19 @@ static int ExecuteCC1Tool(SmallVectorImpl<const char *> &ArgV,
   if (Tool == "-cc1gen-reproducer")
     return cc1gen_reproducer_main(ArrayRef(ArgV).slice(2), ArgV[0],
                                   GetExecutablePathVP, ToolContext);
-  // Reject unknown tools.
+  if (Tool == "-cc1modbuildd") {
+#if LLVM_ON_UNIX
+    return cc1modbuildd_main(ArrayRef(ArgV).slice(2));
+#else
+    llvm::errs() << "-cc1modbuildd not supported by current platform" << '\n';
+    return 1;
+#endif
+  }
+
+  // Reject unknown tools
   llvm::errs() << "error: unknown integrated tool '" << Tool << "'. "
-               << "Valid tools include '-cc1' and '-cc1as'.\n";
+               << "Valid tools include '-cc1', '-cc1as', '-cc1gen-reproducer', "
+                  "and '-cc1modbuildd'.\n";
   return 1;
 }
 

>From 62485d65dad7f9ed81d8a9fdc1e59446f2ff5955 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Fri, 29 Sep 2023 00:30:25 -0400
Subject: [PATCH 2/3] Fix accidental formats

---
 clang/tools/driver/cc1_main.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 25db6bf09082e0d..93efc91722def3d 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -64,7 +64,7 @@ using namespace llvm::opt;
 
 static void LLVMErrorHandler(void *UserData, const char *Message,
                              bool GenCrashDiag) {
-  DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine *>(UserData);
+  DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
 
   Diags.Report(diag::err_fe_error_backend) << Message;
 
@@ -202,7 +202,7 @@ static int PrintSupportedExtensions(std::string TargetStr) {
   const llvm::Triple &MachineTriple = TheTargetMachine->getTargetTriple();
   const llvm::MCSubtargetInfo *MCInfo = TheTargetMachine->getMCSubtargetInfo();
   const llvm::ArrayRef<llvm::SubtargetFeatureKV> Features =
-      MCInfo->getAllProcessorFeatures();
+    MCInfo->getAllProcessorFeatures();
 
   llvm::StringMap<llvm::StringRef> DescMap;
   for (const llvm::SubtargetFeatureKV &feature : Features)
@@ -271,7 +271,7 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
   if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
       Clang->getHeaderSearchOpts().ResourceDir.empty())
     Clang->getHeaderSearchOpts().ResourceDir =
-        CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
+      CompilerInvocation::GetResourcesPath(Argv0, MainAddr);
 
   // Create the actual diagnostics engine.
   Clang->createDiagnostics();
@@ -280,8 +280,8 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
 
   // Set an error handler, so that any LLVM backend diagnostics go through our
   // error handler.
-  llvm::install_fatal_error_handler(
-      LLVMErrorHandler, static_cast<void *>(&Clang->getDiagnostics()));
+  llvm::install_fatal_error_handler(LLVMErrorHandler,
+                                  static_cast<void*>(&Clang->getDiagnostics()));
 
   DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
   if (!Success) {

>From ca3d6f987b75065f00ab32697a9623052cea6bd2 Mon Sep 17 00:00:00 2001
From: cpsughrue <cpsughrue at gmail.com>
Date: Fri, 29 Sep 2023 00:30:25 -0400
Subject: [PATCH 3/3] Address feedback

 - Fix accidental formats
 - Clarify HelpText for -fmodule-build-daemon=
 - Correct file name in header license comment and header guard comment
 - Moved #define(s) used by both the client and server from Client.h to Util.h
 - Change socket write functions to take buffer as StringRef instead of std::string
 - Fix exponential backoff behavior when waiting for module build daemon to spawn
 - Remove unused function from SocketSupport.cpp
 - Modify where path to stdout and stderr file descriptors get set
 - Add error message for when -fmodule-build-daemon is used on unsupported platform
 - Remove  parameter from shutdownDaemon because it was never used
 - Do not delete temp directory at end of llvm-lit test
 - Rename launchDaemon to createDaemonSocket
 - Rename handshakeModuleBuildDaemon to spawnModuleBuildDaemonAndHandshake
 - Close client before daemon handleClient returns
 - Rework read from socket to buffer to better handle stream
---
 clang/include/clang/Driver/Options.td         |  3 +-
 .../clang/Tooling/ModuleBuildDaemon/Client.h  | 13 +--
 .../ModuleBuildDaemon/SocketMsgSupport.h      | 10 +--
 .../Tooling/ModuleBuildDaemon/SocketSupport.h |  5 +-
 .../clang/Tooling/ModuleBuildDaemon/Utils.h   |  5 ++
 .../lib/Tooling/ModuleBuildDaemon/Client.cpp  | 18 ++--
 .../ModuleBuildDaemon/SocketSupport.cpp       | 39 +++------
 clang/test/ModuleBuildDaemon/handshake.c      |  1 -
 clang/test/ModuleBuildDaemon/launch.c         |  1 -
 clang/tools/driver/cc1_main.cpp               | 12 +--
 clang/tools/driver/cc1modbuildd_main.cpp      | 85 ++++++++++++-------
 11 files changed, 97 insertions(+), 95 deletions(-)

diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index d31d28255e81a8a..6b1c6d8ce1c8687 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -2845,7 +2845,8 @@ def fmodule_build_daemon : Flag<["-"], "fmodule-build-daemon">, Group<f_Group>,
 def fmodule_build_daemon_EQ : Joined<["-"], "fmodule-build-daemon=">, Group<f_Group>,
   Flags<[NoXarchOption]>,
   Visibility<[ClangOption, CC1Option]>,
-  HelpText<"Enables module build daemon functionality and defines location of output files">,
+  HelpText<"Enables module build daemon functionality and defines the path to "
+           "where the module build daemon will write log and socket files">,
   MarshallingInfoString<FrontendOpts<"ModuleBuildDaemonPath">>;
 
 def fmodules_cache_path : Joined<["-"], "fmodules-cache-path=">, Group<i_Group>,
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
index d7506fa3011cffb..eb4cac1aa8b168d 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Client.h
@@ -1,4 +1,4 @@
-//===----------------------------- Protocol.h -----------------------------===//
+//===------------------------------ Client.h ------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -16,11 +16,6 @@
 #include "llvm/Support/YAMLParser.h"
 #include "llvm/Support/YAMLTraits.h"
 
-#define MAX_BUFFER 4096
-#define SOCKET_FILE_NAME "mbd.sock"
-#define STDOUT_FILE_NAME "mbd.out"
-#define STDERR_FILE_NAME "mbd.err"
-
 using namespace clang;
 using namespace llvm;
 
@@ -36,9 +31,9 @@ llvm::Error spawnModuleBuildDaemon(StringRef BasePath, const char *Argv0);
 
 Expected<int> getModuleBuildDaemon(const char *Argv0, StringRef BasePath);
 
-llvm::Error handshakeModuleBuildDaemon(const CompilerInvocation &Clang,
-                                       const char *Argv0);
+llvm::Error spawnModuleBuildDaemonAndHandshake(const CompilerInvocation &Clang,
+                                               const char *Argv0);
 
 } // namespace cc1modbuildd
 
-#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_PROTOCAL_H
+#endif // LLVM_CLANG_TOOLING_MODULEBUILDDAEMON_CLIENT_H
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
index 16666c177eaa80c..0c2994e04892517 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketMsgSupport.h
@@ -47,7 +47,7 @@ template <typename T> std::string getBufferFromSocketMsg(T Msg) {
   return Buffer;
 }
 
-template <typename T> Expected<T> getSocketMsgFromBuffer(const char *Buffer) {
+template <typename T> Expected<T> getSocketMsgFromBuffer(StringRef Buffer) {
   static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
                 "T must inherit from cc1modbuildd::BaseMsg");
 
@@ -67,13 +67,13 @@ template <typename T> Expected<T> readSocketMsgFromSocket(int FD) {
   static_assert(std::is_base_of<cc1modbuildd::BaseMsg, T>::value,
                 "T must inherit from cc1modbuildd::BaseMsg");
 
-  Expected<std::string> MaybeResponseBuffer = readFromSocket(FD);
-  if (!MaybeResponseBuffer)
-    return std::move(MaybeResponseBuffer.takeError());
+  std::string BufferConsumer;
+  if (llvm::Error ReadErr = readFromSocket(FD, BufferConsumer))
+    return std::move(ReadErr);
 
   // Wait for response from module build daemon
   Expected<T> MaybeResponse =
-      getSocketMsgFromBuffer<T>(std::move(*MaybeResponseBuffer).c_str());
+      getSocketMsgFromBuffer<T>(std::move(BufferConsumer).c_str());
   if (!MaybeResponse)
     return std::move(MaybeResponse.takeError());
   return std::move(*MaybeResponse);
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
index bc21084faab3966..712f65e695086b0 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/SocketSupport.h
@@ -22,9 +22,8 @@ namespace cc1modbuildd {
 
 Expected<int> createSocket();
 Expected<int> connectToSocket(StringRef SocketPath);
-Expected<int> connectAndWriteToSocket(std::string Buffer, StringRef SocketPath);
-Expected<std::string> readFromSocket(int FD);
-llvm::Error writeToSocket(std::string Buffer, int WriteFD);
+llvm::Error readFromSocket(int FD, std::string &BufferConsumer);
+llvm::Error writeToSocket(StringRef Buffer, int WriteFD);
 
 } // namespace cc1modbuildd
 
diff --git a/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h b/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
index 000081be92793cb..63ac2bf54c6ba8d 100644
--- a/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
+++ b/clang/include/clang/Tooling/ModuleBuildDaemon/Utils.h
@@ -17,6 +17,11 @@
 #include "llvm/Support/Error.h"
 #include <string>
 
+#define MAX_BUFFER 4096
+#define SOCKET_FILE_NAME "mbd.sock"
+#define STDOUT_FILE_NAME "mbd.out"
+#define STDERR_FILE_NAME "mbd.err"
+
 namespace cc1modbuildd {
 
 void writeError(llvm::Error Err, std::string Msg);
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp b/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
index f247c4c64da957a..766b78ee940d416 100644
--- a/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
+++ b/clang/lib/Tooling/ModuleBuildDaemon/Client.cpp
@@ -45,7 +45,7 @@ std::string cc1modbuildd::getBasePath() {
           HashResult.data());
   std::string Key = toString(llvm::APInt(64, HashValue), 36, /*Signed*/ false);
 
-  // set paths
+  // Set paths
   SmallString<128> BasePath;
   llvm::sys::path::system_temp_directory(/*erasedOnReboot*/ true, BasePath);
   llvm::sys::path::append(BasePath, "clang-" + Key);
@@ -111,13 +111,12 @@ Expected<int> cc1modbuildd::getModuleBuildDaemon(const char *Argv0,
     return std::move(Err);
 
   const unsigned int MICROSEC_IN_SEC = 1000000;
-  constexpr unsigned int MAX_TIME = 30 * MICROSEC_IN_SEC;
-  const unsigned short INTERVAL = 100;
+  constexpr unsigned int MAX_WAIT_TIME = 30 * MICROSEC_IN_SEC;
 
   unsigned int CumulativeTime = 0;
-  unsigned int WaitTime = 0;
+  unsigned int WaitTime = 10;
 
-  while (CumulativeTime <= MAX_TIME) {
+  while (CumulativeTime <= MAX_WAIT_TIME) {
     // Wait a bit then check to see if the module build daemon has initialized
     usleep(WaitTime);
 
@@ -128,7 +127,9 @@ Expected<int> cc1modbuildd::getModuleBuildDaemon(const char *Argv0,
       consumeError(MaybeFD.takeError());
     }
 
-    CumulativeTime += INTERVAL;
+    CumulativeTime += WaitTime;
+    // Exponential backoff
+    WaitTime = WaitTime * 2;
   }
 
   // After waiting 30 seconds give up
@@ -136,9 +137,8 @@ Expected<int> cc1modbuildd::getModuleBuildDaemon(const char *Argv0,
       "Module build daemon could not be spawned", inconvertibleErrorCode());
 }
 
-llvm::Error
-cc1modbuildd::handshakeModuleBuildDaemon(const CompilerInvocation &Clang,
-                                         const char *Argv0) {
+llvm::Error cc1modbuildd::spawnModuleBuildDaemonAndHandshake(
+    const CompilerInvocation &Clang, const char *Argv0) {
 
   // The module build daemon stores all output files and its socket address
   // under BasePath. Either set BasePath to a user provided option or create an
diff --git a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
index 58526e4422f457b..ae1e40a9a44376a 100644
--- a/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
+++ b/clang/lib/Tooling/ModuleBuildDaemon/SocketSupport.cpp
@@ -10,6 +10,7 @@
 #include "clang/Basic/Version.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Tooling/ModuleBuildDaemon/Client.h"
+#include "clang/Tooling/ModuleBuildDaemon/Utils.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/SmallString.h"
@@ -61,37 +62,17 @@ Expected<int> cc1modbuildd::connectToSocket(StringRef SocketPath) {
   return FD;
 }
 
-Expected<int> cc1modbuildd::connectAndWriteToSocket(std::string Buffer,
-                                                    StringRef SocketPath) {
-
-  Expected<int> MaybeConnectedFD = connectToSocket(SocketPath);
-  if (!MaybeConnectedFD)
-    return std::move(MaybeConnectedFD.takeError());
-
-  int ConnectedFD = std::move(*MaybeConnectedFD);
-  llvm::Error Err = writeToSocket(Buffer, ConnectedFD);
-  if (Err)
-    return std::move(Err);
-
-  return ConnectedFD;
-}
-
-Expected<std::string> cc1modbuildd::readFromSocket(int FD) {
-
-  const size_t BUFFER_SIZE = 4096;
-  std::vector<char> Buffer(BUFFER_SIZE);
-  size_t TotalBytesRead = 0;
+llvm::Error cc1modbuildd::readFromSocket(int FD, std::string &BufferConsumer) {
 
+  char Buffer[MAX_BUFFER];
   ssize_t n;
-  while ((n = read(FD, Buffer.data() + TotalBytesRead,
-                   Buffer.size() - TotalBytesRead)) > 0) {
 
-    TotalBytesRead += n;
+  while ((n = read(FD, Buffer, MAX_BUFFER)) > 0) {
+
+    BufferConsumer.assign(Buffer, n);
     // Read until ...\n encountered (last line of YAML document)
-    if (std::string(&Buffer[TotalBytesRead - 4], 4) == "...\n")
+    if (BufferConsumer.find("...\n") != std::string::npos)
       break;
-    if (Buffer.size() - TotalBytesRead < BUFFER_SIZE)
-      Buffer.resize(Buffer.size() + BUFFER_SIZE);
   }
 
   if (n < 0) {
@@ -100,13 +81,13 @@ Expected<std::string> cc1modbuildd::readFromSocket(int FD) {
   }
   if (n == 0)
     return llvm::make_error<StringError>("EOF", inconvertibleErrorCode());
-  return std::string(Buffer.begin(), Buffer.end());
+  return llvm::Error::success();
 }
 
-llvm::Error cc1modbuildd::writeToSocket(std::string Buffer, int WriteFD) {
+llvm::Error cc1modbuildd::writeToSocket(StringRef Buffer, int WriteFD) {
 
   ssize_t BytesToWrite = static_cast<ssize_t>(Buffer.size());
-  const char *Bytes = Buffer.c_str();
+  const char *Bytes = Buffer.data();
 
   while (BytesToWrite) {
     ssize_t BytesWritten = write(WriteFD, Bytes, BytesToWrite);
diff --git a/clang/test/ModuleBuildDaemon/handshake.c b/clang/test/ModuleBuildDaemon/handshake.c
index ac9a5ebab87e4de..5dd8f1b5a03a84c 100644
--- a/clang/test/ModuleBuildDaemon/handshake.c
+++ b/clang/test/ModuleBuildDaemon/handshake.c
@@ -15,4 +15,3 @@ int main() {return 0;}
 // CHECK: Completed successfull handshake with module build daemon
 
 // RUN: if pgrep -f "cc1modbuildd mbd-handshake"; then pkill -f "cc1modbuildd mbd-handshake"; fi
-// RUN: rm -rf mbd-handshake %t
diff --git a/clang/test/ModuleBuildDaemon/launch.c b/clang/test/ModuleBuildDaemon/launch.c
index 878bdfa4052f542..d447cf9e26774b8 100644
--- a/clang/test/ModuleBuildDaemon/launch.c
+++ b/clang/test/ModuleBuildDaemon/launch.c
@@ -11,4 +11,3 @@
 // CHECK: mbd created and binded to socket address at: mbd-launch/mbd.sock
 
 // RUN: if pgrep -f "cc1modbuildd mbd-launch"; then pkill -f "cc1modbuildd mbd-launch"; fi
-// RUN: rm -rf mbd-launch %t
diff --git a/clang/tools/driver/cc1_main.cpp b/clang/tools/driver/cc1_main.cpp
index 93efc91722def3d..b4b628ec732c22c 100644
--- a/clang/tools/driver/cc1_main.cpp
+++ b/clang/tools/driver/cc1_main.cpp
@@ -289,12 +289,11 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
     return 1;
   }
 
-#if LLVM_ON_UNIX
   // Handle module build daemon functionality if enabled
   if (Clang->getFrontendOpts().ModuleBuildDaemon) {
-
-    llvm::Error HandshakeErr =
-        cc1modbuildd::handshakeModuleBuildDaemon(Clang->getInvocation(), Argv0);
+#if LLVM_ON_UNIX
+    llvm::Error HandshakeErr = cc1modbuildd::spawnModuleBuildDaemonAndHandshake(
+        Clang->getInvocation(), Argv0);
     if (HandshakeErr) {
       handleAllErrors(std::move(HandshakeErr), [&](ErrorInfoBase &EIB) {
         errs() << EIB.message() << '\n';
@@ -303,8 +302,11 @@ int cc1_main(ArrayRef<const char *> Argv, const char *Argv0, void *MainAddr) {
     }
     outs() << "Completed successfull handshake with module build daemon"
            << '\n';
-  }
+#else
+    errs() << "-fmodule-build-daemon not supported by current platform" << '\n';
+    return 1;
 #endif
+  }
 
   // Execute the frontend actions.
   {
diff --git a/clang/tools/driver/cc1modbuildd_main.cpp b/clang/tools/driver/cc1modbuildd_main.cpp
index bb8ace9dfde6510..1f934de3d6e9ac1 100644
--- a/clang/tools/driver/cc1modbuildd_main.cpp
+++ b/clang/tools/driver/cc1modbuildd_main.cpp
@@ -48,26 +48,33 @@ static raw_fd_ostream &unbuff_outs() {
 
 namespace {
 
+struct ClientConnection {
+  int ClientFD;
+  std::string Buffer;
+};
+
 class ModuleBuildDaemonServer {
 public:
-  SmallString<128> BasePath;
-  SmallString<128> SocketPath;
-  SmallString<128> PidPath;
+  SmallString<256> SocketPath;
+  SmallString<256> STDERR;
+  SmallString<256> STDOUT;
 
-  ModuleBuildDaemonServer(SmallString<128> Path, ArrayRef<const char *> Argv)
-      : BasePath(Path), SocketPath(Path) {
+  ModuleBuildDaemonServer(StringRef Path, ArrayRef<const char *> Argv)
+      : SocketPath(Path), STDERR(Path), STDOUT(Path) {
     llvm::sys::path::append(SocketPath, SOCKET_FILE_NAME);
+    llvm::sys::path::append(STDOUT, STDOUT_FILE_NAME);
+    llvm::sys::path::append(STDERR, STDERR_FILE_NAME);
   }
 
-  ~ModuleBuildDaemonServer() { shutdownDaemon(SIGTERM); }
+  ~ModuleBuildDaemonServer() { shutdownDaemon(); }
 
   int forkDaemon();
-  int launchDaemon();
+  int createDaemonSocket();
   int listenForClients();
 
-  static void handleClient(int Client);
+  static void handleClient(ClientConnection Connection);
 
-  void shutdownDaemon(int signal) {
+  void shutdownDaemon() {
     unlink(SocketPath.c_str());
     shutdown(ListenSocketFD, SHUT_RD);
     close(ListenSocketFD);
@@ -84,14 +91,14 @@ class ModuleBuildDaemonServer {
 ModuleBuildDaemonServer *DaemonPtr = nullptr;
 void handleSignal(int Signal) {
   if (DaemonPtr != nullptr) {
-    DaemonPtr->shutdownDaemon(Signal);
+    DaemonPtr->shutdownDaemon();
   }
 }
 } // namespace
 
-static bool verbose = false;
-static void verbose_print(const llvm::Twine &message) {
-  if (verbose) {
+static bool VerboseLog = false;
+static void printVerboseLog(const llvm::Twine &message) {
+  if (VerboseLog) {
     unbuff_outs() << message << '\n';
   }
 }
@@ -114,12 +121,7 @@ int ModuleBuildDaemonServer::forkDaemon() {
   close(STDOUT_FILENO);
   close(STDERR_FILENO);
 
-  SmallString<128> STDOUT = BasePath;
-  llvm::sys::path::append(STDOUT, STDOUT_FILE_NAME);
   freopen(STDOUT.c_str(), "a", stdout);
-
-  SmallString<128> STDERR = BasePath;
-  llvm::sys::path::append(STDERR, STDERR_FILE_NAME);
   freopen(STDERR.c_str(), "a", stderr);
 
   if (signal(SIGTERM, handleSignal) == SIG_ERR) {
@@ -139,7 +141,7 @@ int ModuleBuildDaemonServer::forkDaemon() {
 }
 
 // Creates unix socket for IPC with module build daemon
-int ModuleBuildDaemonServer::launchDaemon() {
+int ModuleBuildDaemonServer::createDaemonSocket() {
 
   // new socket
   if ((ListenSocketFD = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
@@ -166,7 +168,7 @@ int ModuleBuildDaemonServer::launchDaemon() {
     std::perror("Socket bind error: ");
     exit(EXIT_FAILURE);
   }
-  verbose_print("mbd created and binded to socket address at: " + SocketPath);
+  printVerboseLog("mbd created and binded to socket address at: " + SocketPath);
 
   // set socket to accept incoming connection request
   unsigned MaxBacklog = llvm::hardware_concurrency().compute_thread_count();
@@ -180,27 +182,43 @@ int ModuleBuildDaemonServer::launchDaemon() {
 
 // Function submitted to thread pool with each client connection. Not
 // responsible for closing client connections
-void ModuleBuildDaemonServer::handleClient(int Client) {
+// TODO: Setup something like ScopedHandle to auto close client on return
+void ModuleBuildDaemonServer::handleClient(ClientConnection Connection) {
 
   // Read handshake from client
-  Expected<HandshakeMsg> MaybeHandshakeMsg =
-      readSocketMsgFromSocket<HandshakeMsg>(Client);
+  if (llvm::Error ReadErr =
+          readFromSocket(Connection.ClientFD, Connection.Buffer)) {
+    writeError(std::move(ReadErr), "Daemon failed to read buffer from socket");
+    close(Connection.ClientFD);
+    return;
+  }
 
+  // Wait for response from module build daemon
+  Expected<HandshakeMsg> MaybeHandshakeMsg =
+      getSocketMsgFromBuffer<HandshakeMsg>(Connection.Buffer);
   if (!MaybeHandshakeMsg) {
     writeError(MaybeHandshakeMsg.takeError(),
-               "Failed to read handshake message from socket: ");
+               "Failed to convert buffer to HandshakeMsg: ");
+    close(Connection.ClientFD);
     return;
   }
 
-  // Handle HANDSHAKE
+  // Have received HandshakeMsg - send HandshakeMsg response to clang invocation
   HandshakeMsg Msg(ActionType::HANDSHAKE, StatusType::SUCCESS);
-  llvm::Error WriteErr = writeSocketMsgToSocket(Msg, Client);
-
-  if (WriteErr) {
+  if (llvm::Error WriteErr = writeSocketMsgToSocket(Msg, Connection.ClientFD)) {
     writeError(std::move(WriteErr),
                "Failed to notify client that handshake was received");
+    close(Connection.ClientFD);
     return;
   }
+
+  // Remove HandshakeMsg from Buffer in preperation for next read. Not currently
+  // necessary but will be once Daemon increases communication
+  size_t Position = Connection.Buffer.find("...\n");
+  if (Position != std::string::npos)
+    Connection.Buffer = Connection.Buffer.substr(Position + 4);
+
+  close(Connection.ClientFD);
   return;
 }
 
@@ -216,7 +234,10 @@ int ModuleBuildDaemonServer::listenForClients() {
       continue;
     }
 
-    Pool.async(handleClient, Client);
+    ClientConnection Connection;
+    Connection.ClientFD = Client;
+
+    Pool.async(handleClient, Connection);
   }
   return 0;
 }
@@ -247,7 +268,7 @@ int cc1modbuildd_main(ArrayRef<const char *> Argv) {
 
   // Where to store log files and socket address
   // TODO: Add check to confirm BasePath is directory
-  SmallString<128> BasePath(Argv[0]);
+  std::string BasePath(Argv[0]);
   llvm::sys::fs::create_directories(BasePath);
   ModuleBuildDaemonServer Daemon(BasePath, Argv);
 
@@ -255,10 +276,10 @@ int cc1modbuildd_main(ArrayRef<const char *> Argv) {
   DaemonPtr = &Daemon;
 
   if (find(Argv, StringRef("-v")) != Argv.end())
-    verbose = true;
+    VerboseLog = true;
 
   Daemon.forkDaemon();
-  Daemon.launchDaemon();
+  Daemon.createDaemonSocket();
   Daemon.listenForClients();
 
   return 0;



More information about the cfe-commits mailing list