From 877e7bdbee49dbc1f1a13289f0bf2d41a6e4a2ae Mon Sep 17 00:00:00 2001 From: Balint Cristian Date: Fri, 19 Jun 2026 14:59:50 +0300 Subject: [PATCH] [CPP_RPC] Replace legacy OS-specific API with std:: libraries --- apps/cpp_rpc/README.md | 8 +- apps/cpp_rpc/main.cc | 14 +-- apps/cpp_rpc/rpc_env.cc | 169 +++++++++--------------------- apps/cpp_rpc/rpc_env.h | 13 --- apps/cpp_rpc/rpc_server.cc | 76 ++++++-------- apps/cpp_rpc/rpc_server.h | 6 +- apps/cpp_rpc/rpc_tracker_client.h | 2 +- 7 files changed, 97 insertions(+), 191 deletions(-) diff --git a/apps/cpp_rpc/README.md b/apps/cpp_rpc/README.md index d8d7eee377b9..a4557a3fd367 100644 --- a/apps/cpp_rpc/README.md +++ b/apps/cpp_rpc/README.md @@ -68,15 +68,15 @@ This folder contains a simple recipe to make RPC server in c++. ``` Command line usage server - Start the server ---host - The hostname of the server, Default=0.0.0.0 ---port - The port of the RPC, Default=9090 ---port-end - The end search port of the RPC, Default=9199 +--host - The listen address of the server, Default=0.0.0.0 (any) +--port - The port of the RPC server, Default=9090 +--port-end - The end search port of the RPC server, Default=9099 --tracker - The RPC tracker address in host:port format e.g. 10.1.1.2:9190 Default="" --key - The key used to identify the device type in tracker. Default="" --custom-addr - Custom IP Address to Report to RPC Tracker. Default="" --silent - Whether to run in silent mode. Default=False Example - ./tvm_rpc server --host=0.0.0.0 --port=9000 --port-end=9090 --tracker=127.0.0.1:9190 --key=rasp + ./tvm_rpc server --host=0.0.0.0 --port=9090 --port-end=9099 --tracker=127.0.0.1:9190 --key=rasp ``` ## Note diff --git a/apps/cpp_rpc/main.cc b/apps/cpp_rpc/main.cc index b72220222072..a349f66b929b 100644 --- a/apps/cpp_rpc/main.cc +++ b/apps/cpp_rpc/main.cc @@ -49,9 +49,9 @@ using namespace tvm::support; static const string kUsage = "Command line usage\n" " server - Start the server\n" - "--host - The hostname of the server, Default=0.0.0.0\n" - "--port - The port of the RPC, Default=9090\n" - "--port-end - The end search port of the RPC, Default=9099\n" + "--host - The listen address of the server, Default=0.0.0.0 (any)\n" + "--port - The port of the RPC server, Default=9090\n" + "--port-end - The end search port of the RPC server, Default=9099\n" "--tracker - The RPC tracker address in host:port format e.g. 10.1.1.2:9190 Default=\"\"\n" "--key - The key used to identify the device type in tracker. Default=\"\"\n" "--custom-addr - Custom IP Address to Report to RPC Tracker. Default=\"\"\n" @@ -59,15 +59,15 @@ static const string kUsage = "--silent - Whether to run in silent mode. Default=False\n" "\n" " Example\n" - " ./tvm_rpc server --host=0.0.0.0 --port=9000 --port-end=9090 " + " ./tvm_rpc server --host=0.0.0.0 --port=9090 --port-end=9099 " " --tracker=127.0.0.1:9190 --key=rasp" "\n"; /*! * \brief RpcServerArgs. - * \arg host The hostname of the server, Default=0.0.0.0 - * \arg port The port of the RPC, Default=9090 - * \arg port_end The end search port of the RPC, Default=9099 + * \arg host The listen address of the server, Default=0.0.0.0 (any) + * \arg port The port of the RPC server, Default=9090 + * \arg port_end The end search port of the RPC server, Default=9099 * \arg tracker The address of RPC tracker in host:port format e.g. 10.77.1.234:9190 Default="" * \arg key The key used to identify the device type in tracker. Default="" * \arg custom_addr Custom IP Address to Report to RPC Tracker. Default="" diff --git a/apps/cpp_rpc/rpc_env.cc b/apps/cpp_rpc/rpc_env.cc index 4df5f87024b0..aae7eec683bc 100644 --- a/apps/cpp_rpc/rpc_env.cc +++ b/apps/cpp_rpc/rpc_env.cc @@ -20,30 +20,19 @@ * \file rpc_env.cc * \brief Server environment of the RPC. */ +#include "rpc_env.h" + #include #include #include -#include -#ifndef _WIN32 -#include -#include -#include -#else -#include -#include -namespace { -int mkdir(const char* path, int /* ignored */) { return _mkdir(path); } -} // namespace -#endif -#include +#include #include -#include #include +#include #include #include "../../src/support/utils.h" -#include "rpc_env.h" namespace { std::string GenerateUntarCommand(const std::string& tar_file, const std::string& output_dir) { @@ -69,37 +58,44 @@ namespace tvm { namespace runtime { RPCEnv::RPCEnv(const std::string& wd) { - if (wd != "") { + std::error_code ec; + if (!wd.empty()) { base_ = wd + "/.cache"; - mkdir(wd.c_str(), 0777); - mkdir(base_.c_str(), 0777); + std::filesystem::create_directories(base_, ec); + if (ec) { + LOG(WARNING) << "Failed to create directory " << base_ << " : " << ec.message(); + } } else { #if defined(ANDROID) || defined(__ANDROID__) - char cwd[PATH_MAX]; - auto cmdline = fopen("/proc/self/cmdline", "r"); - fread(cwd, 1, sizeof(cwd), cmdline); - fclose(cmdline); - std::string android_base_ = "/data/data/" + std::string(cwd) + "/cache"; - struct stat statbuf; + std::string pkg_name; + if (std::ifstream cmdline("/proc/self/cmdline"); cmdline) { + std::getline(cmdline, pkg_name, '\0'); + } + std::string android_base_ = "/data/data/" + pkg_name + "/cache"; // Check if application data directory exist. If not exist, usually means we run tvm_rpc from // adb shell terminal. - if (stat(android_base_.data(), &statbuf) == -1 || !S_ISDIR(statbuf.st_mode)) { + if (!std::filesystem::is_directory(android_base_)) { // Tmp directory is always writable for 'shell' user. android_base_ = "/data/local/tmp"; } base_ = android_base_ + "/rpc"; - #elif !defined(_WIN32) - char cwd[PATH_MAX]; - if (getcwd(cwd, sizeof(cwd))) { - base_ = std::string(cwd) + "/rpc"; - } else { + base_ = std::filesystem::current_path(ec).string() + "/rpc"; + if (ec) { base_ = "./rpc"; } #else base_ = "./rpc"; #endif - mkdir(base_.c_str(), 0777); + std::filesystem::create_directories(base_, ec); + if (ec) { + LOG(WARNING) << "Failed to create directory " << base_ << " : " << ec.message(); + } + } + std::filesystem::permissions(base_, std::filesystem::perms::all, + std::filesystem::perm_options::replace, ec); + if (ec) { + LOG(WARNING) << "Failed to grant permissions to " << base_ << " : " << ec.message(); } ffi::Function::SetGlobal( @@ -157,11 +153,10 @@ std::string RPCEnv::GetPath(const std::string& file_name) const { * \brief Remove The RPC Environment cleanup function */ void RPCEnv::CleanUp() const { - CleanDir(base_); - if (!CheckPath(base_)) return; - const int ret = rmdir(base_.c_str()); - if (ret != 0) { - LOG(WARNING) << "Remove directory " << base_ << " failed"; + std::error_code ec; + std::filesystem::remove_all(base_, ec); + if (ec) { + LOG(WARNING) << "Cleanup " << base_ << " failed: " << ec.message(); } } @@ -171,55 +166,16 @@ void RPCEnv::CleanUp() const { * \return vector Files in directory. */ std::vector ListDir(const std::string& dirname) { + std::error_code ec; std::vector vec; -#ifndef _WIN32 - DIR* dp = opendir(dirname.c_str()); - if (dp == nullptr) { - int errsv = errno; - if (errsv == ENOENT) { - return vec; - } - TVM_FFI_THROW(InternalError) << "ListDir " << dirname << " error: " << strerror(errsv); + auto iter = std::filesystem::directory_iterator(dirname, ec); + if (ec) { + if (ec == std::errc::no_such_file_or_directory) return vec; + TVM_FFI_THROW(InternalError) << "ListDir " << dirname << " error: " << ec.message(); } - dirent* d; - while ((d = readdir(dp)) != nullptr) { - std::string filename = d->d_name; - if (filename != "." && filename != "..") { - std::string f = dirname; - if (f[f.length() - 1] != '/') { - f += '/'; - } - f += d->d_name; - vec.push_back(f); - } + for (const auto& entry : iter) { + vec.push_back(entry.path().generic_string()); } - closedir(dp); -#elif defined(_WIN32) - WIN32_FIND_DATAA fd; - const std::string pattern = dirname + "/*"; - HANDLE handle = FindFirstFileA(pattern.c_str(), &fd); - if (handle == INVALID_HANDLE_VALUE) { - const int errsv = GetLastError(); - if (errsv == ERROR_FILE_NOT_FOUND || errsv == ERROR_PATH_NOT_FOUND) { - return vec; - } - TVM_FFI_THROW(InternalError) << "ListDir " << dirname << " error: " << strerror(errsv); - } - do { - std::string filename = fd.cFileName; - if (filename != "." && filename != "..") { - std::string f = dirname; - if (f[f.length() - 1] != '/') { - f += '/'; - } - f += filename; - vec.push_back(f); - } - } while (FindNextFileA(handle, &fd)); - FindClose(handle); -#else - TVM_FFI_THROW(InternalError) << "Operating system not supported"; -#endif return vec; } @@ -299,7 +255,16 @@ std::string BuildSharedLibrary(std::string file) { CreateShared(file_name, {file}); } else if (support::EndsWith(file, ".tar")) { const std::string tmp_dir = "./rpc/tmp/"; - mkdir(tmp_dir.c_str(), 0777); + std::error_code ec; + std::filesystem::create_directories(tmp_dir, ec); + if (ec) { + LOG(WARNING) << "Failed to create directory " << tmp_dir << " : " << ec.message(); + } + std::filesystem::permissions(tmp_dir, std::filesystem::perms::all, + std::filesystem::perm_options::replace, ec); + if (ec) { + LOG(WARNING) << "Failed to grant permissions to " << tmp_dir << " : " << ec.message(); + } const std::string cmd = GenerateUntarCommand(file, tmp_dir); @@ -309,45 +274,15 @@ std::string BuildSharedLibrary(std::string file) { TVM_FFI_THROW(InternalError) << err_msg; } CreateShared(file_name, ListDir(tmp_dir)); - CleanDir(tmp_dir); - (void)rmdir(tmp_dir.c_str()); + std::filesystem::remove_all(tmp_dir, ec); + if (ec) { + LOG(WARNING) << "Remove " << tmp_dir << " failed: " << ec.message(); + } } else { file_name = file; } return file_name; } -/*! - * \brief CheckPath Checks file or directory if exists - * \param dirname The name of the directory - * \return True if path exists. - */ -bool CheckPath(const std::string& pathname) { -#if defined(_WIN32) - DWORD attribs = GetFileAttributesA(pathname.c_str()); - return (attribs != INVALID_FILE_ATTRIBUTES); -#else - struct stat info; - return (stat(pathname.c_str(), &info) == 0); -#endif -} - -/*! - * \brief CleanDir Removes the files from the directory - * \param dirname The name of the directory - */ -void CleanDir(const std::string& dirname) { - if (!CheckPath(dirname)) return; - auto files = ListDir(dirname); - for (const auto& filename : files) { - std::string file_path = dirname + "/"; - file_path += filename; - const int ret = std::remove(filename.c_str()); - if (ret != 0) { - LOG(WARNING) << "Remove file " << filename << " failed"; - } - } -} - } // namespace runtime } // namespace tvm diff --git a/apps/cpp_rpc/rpc_env.h b/apps/cpp_rpc/rpc_env.h index bd5e2f94227e..6a35109b2200 100644 --- a/apps/cpp_rpc/rpc_env.h +++ b/apps/cpp_rpc/rpc_env.h @@ -31,19 +31,6 @@ namespace tvm { namespace runtime { -/*! - * \brief CheckPath Checks if file or directory exists - * \param dirname The name of the directory - * \return True if path exists. - */ -bool CheckPath(const std::string& pathname); - -/*! - * \brief CleanDir Removes the files from the directory - * \param dirname The name of the directory - */ -void CleanDir(const std::string& dirname); - /*! * \brief ListDir Get the list of files in a directory * \param dirname The root directory name diff --git a/apps/cpp_rpc/rpc_server.cc b/apps/cpp_rpc/rpc_server.cc index 88971cc34c6c..db9d1fb82be5 100644 --- a/apps/cpp_rpc/rpc_server.cc +++ b/apps/cpp_rpc/rpc_server.cc @@ -34,6 +34,7 @@ #include #include #include +#include #include "../../src/runtime/rpc/rpc_endpoint.h" #include "../../src/runtime/rpc/rpc_socket_impl.h" @@ -50,25 +51,6 @@ using namespace std::chrono; namespace tvm { namespace runtime { -/*! - * \brief wait the child process end. - * \param status status value - */ -#if defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__) -static pid_t waitPidEintr(int* status) { - pid_t pid = 0; - while ((pid = waitpid(-1, status, 0)) == -1) { - if (errno == EINTR) { - continue; - } else { - perror("waitpid"); - abort(); - } - } - return pid; -} -#endif - #ifdef __ANDROID__ static std::string getNextString(std::stringstream* iss) { std::string str = iss->str(); @@ -88,7 +70,7 @@ static std::string getNextString(std::stringstream* iss) { /*! * \brief RPCServer RPC Server class. * - * \param host The hostname of the server, Default=0.0.0.0 + * \param host The listen address of the server, Default=0.0.0.0 (any) * * \param port_search_start The low end of the search range for an * available port for the RPC, Default=9090 @@ -137,7 +119,7 @@ class RPCServer { void Start() { listen_sock_.Create(); my_port_ = listen_sock_.TryBindHost(host_, port_search_start_, port_search_end_); - LOG(INFO) << "bind to " << host_ << ":" << my_port_; + LOG(INFO) << "Bind to " << host_ << ":" << my_port_; listen_sock_.Listen(1); std::future proc(std::async(std::launch::async, &RPCServer::ListenLoopProc, this)); proc.get(); @@ -176,13 +158,6 @@ class RPCServer { #if defined(__linux__) || defined(__ANDROID__) || defined(__APPLE__) // step 3: serving if (timeout != 0) { - const pid_t timer_pid = fork(); - if (timer_pid == 0) { - // Timer process - sleep(timeout); - _exit(0); - } - const pid_t worker_pid = fork(); if (worker_pid == 0) { // Worker process @@ -190,27 +165,36 @@ class RPCServer { _exit(0); } - int status_first = 0; - const pid_t finished_first = waitPidEintr(&status_first); - if (finished_first == timer_pid) { - kill(worker_pid, SIGTERM); - } else if (finished_first == worker_pid) { - kill(timer_pid, SIGTERM); - } else { - LOG(INFO) << "Child pid=" << finished_first << " unexpected, but still continue."; + int status = 0; + bool timed_out = false; + auto start_timer = std::chrono::steady_clock::now(); + while (true) { + // Check worker pid (non-blocking) + int ret = waitpid(worker_pid, &status, WNOHANG); + if (ret == worker_pid) { + break; + } else if (ret == -1) { + if (errno == EINTR) continue; + break; + } + // Check worker timeout + if (std::chrono::steady_clock::now() - start_timer >= std::chrono::seconds(timeout)) { + timed_out = true; + kill(worker_pid, SIGTERM); + waitpid(worker_pid, &status, 0); + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(50)); } - int status_second = 0; - waitPidEintr(&status_second); - // Logging. - if (finished_first == timer_pid) { + if (timed_out) { LOG(INFO) << "Child pid=" << worker_pid << " killed" << " (timeout = " << timeout << " sec)" - << ", status = " << status_second; - } else if (finished_first == worker_pid) { + << ", status = " << status; + } else { LOG(INFO) << "Child pid=" << worker_pid << " finished" - << ", status = " << status_first; + << ", status = " << status; } } else { auto pid = fork(); @@ -384,9 +368,9 @@ void ServerLoopFromChild(SOCKET socket) { /*! * \brief RPCServerCreate Creates the RPC Server. - * \param host The hostname of the server, Default=0.0.0.0 - * \param port The port of the RPC, Default=9090 - * \param port_end The end search port of the RPC, Default=9099 + * \param host The listen address of the server, Default=0.0.0.0 (any) + * \param port The port of the RPC server, Default=9090 + * \param port_end The end search port of the RPC server, Default=9099 * \param tracker_addr The address of RPC tracker in host:port format e.g. 10.77.1.234:9190 * Default="" \param key The key used to identify the device type in tracker. Default="" \param * custom_addr Custom IP Address to Report to RPC Tracker. Default="" \param silent Whether run in diff --git a/apps/cpp_rpc/rpc_server.h b/apps/cpp_rpc/rpc_server.h index 9bb61065c58a..4da43ba43ac1 100644 --- a/apps/cpp_rpc/rpc_server.h +++ b/apps/cpp_rpc/rpc_server.h @@ -42,9 +42,9 @@ void ServerLoopFromChild(SOCKET socket); /*! * \brief RPCServerCreate Creates the RPC Server. - * \param host The hostname of the server, Default=0.0.0.0 - * \param port The port of the RPC, Default=9090 - * \param port_end The end search port of the RPC, Default=9099 + * \param host The listen address of the server, Default=0.0.0.0 (any) + * \param port The port of the RPC server, Default=9090 + * \param port_end The end search port of the RPC server, Default=9099 * \param tracker The address of RPC tracker in host:port format e.g. 10.77.1.234:9190 Default="" * \param key The key used to identify the device type in tracker. Default="" * \param custom_addr Custom IP Address to Report to RPC Tracker. Default="" diff --git a/apps/cpp_rpc/rpc_tracker_client.h b/apps/cpp_rpc/rpc_tracker_client.h index 4b1e36b70d5e..63eb7b642767 100644 --- a/apps/cpp_rpc/rpc_tracker_client.h +++ b/apps/cpp_rpc/rpc_tracker_client.h @@ -206,7 +206,7 @@ class TrackerClient { auto period = (std::chrono::duration_cast( std::chrono::system_clock::now() - tbegin)) .count(); - TVM_FFI_ICHECK(period < timeout) << "Failed to connect to server" << addr.AsString(); + TVM_FFI_ICHECK(period < timeout) << "Failed to connect to tracker " << addr.AsString(); LOG(WARNING) << "Cannot connect to tracker " << addr.AsString() << " retry in " << retry_period << " seconds."; std::this_thread::sleep_for(std::chrono::seconds(retry_period));