Bitcoin Core 30.99.0
P2P Digital Currency
util.cpp
Go to the documentation of this file.
1// Copyright (c) The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <mp/config.h>
6#include <mp/util.h>
7
8#include <cerrno>
9#include <cstdio>
10#include <filesystem>
11#include <iostream>
12#include <kj/common.h>
13#include <kj/string-tree.h>
14#include <pthread.h>
15#include <sstream>
16#include <string>
17#include <sys/types.h>
18#include <sys/resource.h>
19#include <sys/socket.h>
20#include <sys/wait.h>
21#include <system_error>
22#include <thread> // NOLINT(misc-include-cleaner) // IWYU pragma: keep
23#include <unistd.h>
24#include <utility>
25#include <vector>
26
27#ifdef __linux__
28#include <sys/syscall.h>
29#endif
30
31#ifdef HAVE_PTHREAD_GETTHREADID_NP
32#include <pthread_np.h>
33#endif // HAVE_PTHREAD_GETTHREADID_NP
34
35namespace fs = std::filesystem;
36
37namespace mp {
38namespace {
39
40std::vector<char*> MakeArgv(const std::vector<std::string>& args)
41{
42 std::vector<char*> argv;
43 argv.reserve(args.size() + 1);
44 for (const auto& arg : args) {
45 argv.push_back(const_cast<char*>(arg.c_str()));
46 }
47 argv.push_back(nullptr);
48 return argv;
49}
50
52size_t MaxFd()
53{
54 struct rlimit nofile;
55 if (getrlimit(RLIMIT_NOFILE, &nofile) == 0) {
56 return nofile.rlim_cur - 1;
57 } else {
58 return 1023;
59 }
60}
61
62} // namespace
63
64std::string ThreadName(const char* exe_name)
65{
66 char thread_name[16] = {0};
67#ifdef HAVE_PTHREAD_GETNAME_NP
68 pthread_getname_np(pthread_self(), thread_name, sizeof(thread_name));
69#endif // HAVE_PTHREAD_GETNAME_NP
70
71 std::ostringstream buffer;
72 buffer << (exe_name ? exe_name : "") << "-" << getpid() << "/";
73
74 if (thread_name[0] != '\0') {
75 buffer << thread_name << "-";
76 }
77
78 // Prefer platform specific thread ids over the standard C++11 ones because
79 // the former are shorter and are the same as what gdb prints "LWP ...".
80#ifdef __linux__
81 buffer << syscall(SYS_gettid);
82#elif defined(HAVE_PTHREAD_THREADID_NP)
83 uint64_t tid = 0;
84 pthread_threadid_np(NULL, &tid);
85 buffer << tid;
86#elif defined(HAVE_PTHREAD_GETTHREADID_NP)
87 buffer << pthread_getthreadid_np();
88#else
89 buffer << std::this_thread::get_id();
90#endif
91
92 return std::move(buffer).str();
93}
94
95std::string LogEscape(const kj::StringTree& string, size_t max_size)
96{
97 std::string result;
98 string.visit([&](const kj::ArrayPtr<const char>& piece) {
99 if (result.size() > max_size) return;
100 for (const char c : piece) {
101 if (c == '\\') {
102 result.append("\\\\");
103 } else if (c < 0x20 || c > 0x7e) {
104 char escape[4];
105 snprintf(escape, 4, "\\%02x", c);
106 result.append(escape);
107 } else {
108 result.push_back(c);
109 }
110 if (result.size() > max_size) {
111 result += "...";
112 break;
113 }
114 }
115 });
116 return result;
117}
118
119int SpawnProcess(int& pid, FdToArgsFn&& fd_to_args)
120{
121 int fds[2];
122 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
123 throw std::system_error(errno, std::system_category(), "socketpair");
124 }
125
126 // Evaluate the callback and build the argv array before forking.
127 //
128 // The parent process may be multi-threaded and holding internal library
129 // locks at fork time. In that case, running code that allocates memory or
130 // takes locks in the child between fork() and exec() can deadlock
131 // indefinitely. Precomputing arguments in the parent avoids this.
132 const std::vector<std::string> args{fd_to_args(fds[0])};
133 const std::vector<char*> argv{MakeArgv(args)};
134
135 pid = fork();
136 if (pid == -1) {
137 throw std::system_error(errno, std::system_category(), "fork");
138 }
139 // Parent process closes the descriptor for socket 0, child closes the
140 // descriptor for socket 1. On failure, the parent throws, but the child
141 // must _exit(126) (post-fork child must not throw).
142 if (close(fds[pid ? 0 : 1]) != 0) {
143 if (pid) {
144 (void)close(fds[1]);
145 throw std::system_error(errno, std::system_category(), "close");
146 }
147 static constexpr char msg[] = "SpawnProcess(child): close(fds[1]) failed\n";
148 const ssize_t writeResult = ::write(STDERR_FILENO, msg, sizeof(msg) - 1);
149 (void)writeResult;
150 _exit(126);
151 }
152
153 if (!pid) {
154 // Child process must close all potentially open descriptors, except
155 // socket 0. Do not throw, allocate, or do non-fork-safe work here.
156 const int maxFd = MaxFd();
157 for (int fd = 3; fd < maxFd; ++fd) {
158 if (fd != fds[0]) {
159 close(fd);
160 }
161 }
162
163 execvp(argv[0], argv.data());
164 // NOTE: perror() is not async-signal-safe; calling it here in a
165 // post-fork child may deadlock in multithreaded parents.
166 // TODO: Report errors to the parent via a pipe (e.g. write errno)
167 // so callers can get diagnostics without relying on perror().
168 perror("execvp failed");
169 _exit(127);
170 }
171 return fds[1];
172}
173
174void ExecProcess(const std::vector<std::string>& args)
175{
176 const std::vector<char*> argv{MakeArgv(args)};
177 if (execvp(argv[0], argv.data()) != 0) {
178 perror("execvp failed");
179 if (errno == ENOENT && !args.empty()) {
180 std::cerr << "Missing executable: " << fs::weakly_canonical(args.front()) << '\n';
181 }
182 _exit(1);
183 }
184}
185
186int WaitProcess(int pid)
187{
188 int status;
189 if (::waitpid(pid, &status, /*options=*/0) != pid) {
190 throw std::system_error(errno, std::system_category(), "waitpid");
191 }
192 return status;
193}
194
195} // namespace mp
ArgsManager & args
Definition: bitcoind.cpp:277
Functions to serialize / deserialize common bitcoin types.
Definition: common-types.h:57
int WaitProcess(int pid)
Wait for a process to exit and return its exit code.
Definition: util.cpp:186
std::string ThreadName(const char *exe_name)
Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
Definition: util.cpp:64
int SpawnProcess(int &pid, FdToArgsFn &&fd_to_args)
Spawn a new process that communicates with the current process over a socket pair.
Definition: util.cpp:119
std::function< std::vector< std::string >(int fd)> FdToArgsFn
Callback type used by SpawnProcess below.
Definition: util.h:220
void ExecProcess(const std::vector< std::string > &args)
Call execvp with vector args.
Definition: util.cpp:174
std::string LogEscape(const kj::StringTree &string, size_t max_size)
Escape binary string for use in log so it doesn't trigger unicode decode errors in python unit tests.
Definition: util.cpp:95
for(const CTxIn &txin :tx.vin)
Definition: validation.cpp:407