Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
1001void execute_process() noexcept(false);1003private:1004detail::Streams stream_;1006#ifdef WIN321007HANDLE process_handle_;1008std::future<void> cleanup_future_;1009#else1010// Pid of the child process1011int child_pid_ = -1;1012#endif1014std::string exe_name_;1016// Command provided as sequence1017std::vector<std::string> vargs_;1018std::vector<char*> cargv_;1020int retcode_ = -1;1021};1023inline void Popen::init_args() {1024populate_c_argv();1025}1027template <typename F, typename... Args>1028inline void Popen::init_args(F&& farg, Args&&... args)1029{1030detail::ArgumentDeducer argd(this);1031argd.set_option(std::forward<F>(farg));1032init_args(std::forward<Args>(args)...);1033}1035inline void Popen::populate_c_argv()1036{1037cargv_.clear();1038cargv_.reserve(vargs_.size() + 1);1039for (auto& arg : vargs_) cargv_.push_back(&arg[0]);1040cargv_.push_back(nullptr);1041}1043inline int Popen::wait() noexcept(false)1044{1045#ifdef WIN321046int ret = WaitForSingleObject(process_handle_, INFINITE);1048// WaitForSingleObject with INFINITE should only return when process has signaled1049if (ret != WAIT_OBJECT_0) {1050throw OSError("Unexpected return code from WaitForSingleObject", 0);1051}1053DWORD dretcode_;1055if (FALSE == GetExitCodeProcess(process_handle_, &dretcode_))1056throw OSError("Failed during call to GetExitCodeProcess", 0);1058CloseHandle(process_handle_);1060return (int)dretcode_;1061#else1062int ret, status;1063std::tie(ret, status) = util::wait_for_child_exit(child_pid_);1064if (ret == -1) {1065if (errno != ECHILD) throw OSError("waitpid failed", errno);1066return 0;1067}1068if (WIFEXITED(status)) return WEXITSTATUS(status);1069if (WIFSIGNALED(status)) return WTERMSIG(status);1070else return 255;1072return 0;1073#endif1074}1076inline void Popen::execute_process() noexcept(false)1077{1078#ifdef WIN321079if (exe_name_.length()) {1080this->vargs_.insert(this->vargs_.begin(), this->exe_name_);1081this->populate_c_argv();1082}1083this->exe_name_ = vargs_[0];1085std::string argument;1086std::string command_line;1087bool first_arg = true;1089for (auto arg : this->vargs_) {1090if (!first_arg) {1091command_line += " ";1092} else {1093first_arg = false;1094}1095argument = arg;1096util::quote_argument(argument, command_line, /*force=*/false);1097}1099// CreateProcessA can modify szCmdLine so we allocate needed memory1100char *szCmdline = new char[command_line.size() + 1];1101strcpy_s(szCmdline, command_line.size() + 1, command_line.c_str());1102PROCESS_INFORMATION piProcInfo;1103STARTUPINFOA siStartInfo;1104BOOL bSuccess = FALSE;1105DWORD creation_flags = CREATE_NO_WINDOW;1107// Set up members of the PROCESS_INFORMATION structure.1108ZeroMemory(&piProcInfo, sizeof(PROCESS_INFORMATION));1110// Set up members of the STARTUPINFOA structure.1111// This structure specifies the STDIN and STDOUT handles for redirection.1113ZeroMemory(&siStartInfo, sizeof(STARTUPINFOA));1114siStartInfo.cb = sizeof(STARTUPINFOA);1116siStartInfo.hStdError = this->stream_.g_hChildStd_ERR_Wr;1117siStartInfo.hStdOutput = this->stream_.g_hChildStd_OUT_Wr;1118siStartInfo.hStdInput = this->stream_.g_hChildStd_IN_Rd;1120siStartInfo.dwFlags |= STARTF_USESTDHANDLES;1122// Create the child process.1123bSuccess = CreateProcessA(NULL,1124szCmdline, // command line1125NULL, // process security attributes1126NULL, // primary thread security attributes1127TRUE, // handles are inherited1128creation_flags, // creation flags1129NULL, // use parent's environment1130NULL, // use parent's current directory1131&siStartInfo, // STARTUPINFOA pointer1132&piProcInfo); // receives PROCESS_INFORMATION1134// If an error occurs, exit the application.1135if (!bSuccess) {1136DWORD errorMessageID = ::GetLastError();1137throw CalledProcessError("CreateProcess failed: " + util::get_last_error(errorMessageID), errorMessageID);1138}1140CloseHandle(piProcInfo.hThread);1142/*1143TODO: use common apis to close linux handles1144*/1146this->process_handle_ = piProcInfo.hProcess;1148this->cleanup_future_ = std::async(std::launch::async, [this] {1149WaitForSingleObject(this->process_handle_, INFINITE);1151CloseHandle(this->stream_.g_hChildStd_ERR_Wr);1152CloseHandle(this->stream_.g_hChildStd_OUT_Wr);1153CloseHandle(this->stream_.g_hChildStd_IN_Rd);1154});1156/*1157NOTE: In the linux version, there is a check to make sure that the process1158has been started. Here, we do nothing because CreateProcess will throw1159if we fail to create the process.1160*/1163#else1165int err_rd_pipe, err_wr_pipe;1166std::tie(err_rd_pipe, err_wr_pipe) = util::pipe_cloexec();1168if (exe_name_.length()) {1169vargs_.insert(vargs_.begin(), exe_name_);1170populate_c_argv();1171}1172exe_name_ = vargs_[0];1174child_pid_ = fork();1176if (child_pid_ < 0) {1177subprocess_close(err_rd_pipe);1178subprocess_close(err_wr_pipe);1179throw OSError("fork failed", errno);1180}1182if (child_pid_ == 0)1183{1184// Close descriptors belonging to parent1185stream_.close_parent_fds();1187//Close the read end of the error pipe1188subprocess_close(err_rd_pipe);1190detail::Child chld(this, err_wr_pipe);1191chld.execute_child();1192}1193else1194{1195subprocess_close(err_wr_pipe);// close child side of pipe, else get stuck in read below1197stream_.close_child_fds();1199try {1200char err_buf[SP_MAX_ERR_BUF_SIZ] = {0,};1202FILE* err_fp = fdopen(err_rd_pipe, "r");1203if (!err_fp) {1204subprocess_close(err_rd_pipe);1205throw OSError("fdopen failed", errno);1206}1207int read_bytes = util::read_atmost_n(err_fp, err_buf, SP_MAX_ERR_BUF_SIZ);1208fclose(err_fp);1210if (read_bytes || strlen(err_buf)) {1211// Call waitpid to reap the child process1212// waitpid suspends the calling process until the1213// child terminates.1214int retcode = wait();1216// Throw whatever information we have about child failure1217throw CalledProcessError(err_buf, retcode);1218}1219} catch (std::exception& exp) {1220stream_.cleanup_fds();1221throw;1222}1224}1225#endif1226}1228namespace detail {1230inline void ArgumentDeducer::set_option(executable&& exe) {1231popen_->exe_name_ = std::move(exe.arg_value);1232}1234inline void ArgumentDeducer::set_option(input&& inp) {1235if (inp.rd_ch_ != -1) popen_->stream_.read_from_parent_ = inp.rd_ch_;1236if (inp.wr_ch_ != -1) popen_->stream_.write_to_child_ = inp.wr_ch_;1237}1239inline void ArgumentDeducer::set_option(output&& out) {1240if (out.wr_ch_ != -1) popen_->stream_.write_to_parent_ = out.wr_ch_;1241if (out.rd_ch_ != -1) popen_->stream_.read_from_child_ = out.rd_ch_;1242}1244inline void ArgumentDeducer::set_option(error&& err) {1245if (err.deferred_) {1246if (popen_->stream_.write_to_parent_) {1247popen_->stream_.err_write_ = popen_->stream_.write_to_parent_;1248} else {1249throw std::runtime_error("Set output before redirecting error to output");1250}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.