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/resource.h>
18#include <sys/socket.h>
19#include <sys/wait.h>
20#include <system_error>
21#include <thread> // NOLINT(misc-include-cleaner) // IWYU pragma: keep
22#include <unistd.h>
23#include <utility>
24#include <vector>
25
26#ifdef __linux__
27#include <sys/syscall.h>
28#endif
29
30#ifdef HAVE_PTHREAD_GETTHREADID_NP
31#include <pthread_np.h>
32#endif // HAVE_PTHREAD_GETTHREADID_NP
33
34namespace fs = std::filesystem;
35
36namespace mp {
37namespace {
38
40size_t MaxFd()
41{
42 struct rlimit nofile;
43 if (getrlimit(RLIMIT_NOFILE, &nofile) == 0) {
44 return nofile.rlim_cur - 1;
45 } else {
46 return 1023;
47 }
48}
49
50} // namespace
51
52std::string ThreadName(const char* exe_name)
53{
54 char thread_name[16] = {0};
55#ifdef HAVE_PTHREAD_GETNAME_NP
56 pthread_getname_np(pthread_self(), thread_name, sizeof(thread_name));
57#endif // HAVE_PTHREAD_GETNAME_NP
58
59 std::ostringstream buffer;
60 buffer << (exe_name ? exe_name : "") << "-" << getpid() << "/";
61
62 if (thread_name[0] != '\0') {
63 buffer << thread_name << "-";
64 }
65
66 // Prefer platform specific thread ids over the standard C++11 ones because
67 // the former are shorter and are the same as what gdb prints "LWP ...".
68#ifdef __linux__
69 buffer << syscall(SYS_gettid);
70#elif defined(HAVE_PTHREAD_THREADID_NP)
71 uint64_t tid = 0;
72 pthread_threadid_np(NULL, &tid);
73 buffer << tid;
74#elif defined(HAVE_PTHREAD_GETTHREADID_NP)
75 buffer << pthread_getthreadid_np();
76#else
77 buffer << std::this_thread::get_id();
78#endif
79
80 return std::move(buffer).str();
81}
82
83std::string LogEscape(const kj::StringTree& string, size_t max_size)
84{
85 std::string result;
86 string.visit([&](const kj::ArrayPtr<const char>& piece) {
87 if (result.size() > max_size) return;
88 for (const char c : piece) {
89 if (c == '\\') {
90 result.append("\\\\");
91 } else if (c < 0x20 || c > 0x7e) {
92 char escape[4];
93 snprintf(escape, 4, "\\%02x", c);
94 result.append(escape);
95 } else {
96 result.push_back(c);
97 }
98 if (result.size() > max_size) {
99 result += "...";
100 break;
101 }
102 }
103 });
104 return result;
105}
106
107int SpawnProcess(int& pid, FdToArgsFn&& fd_to_args)
108{
109 int fds[2];
110 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
111 throw std::system_error(errno, std::system_category(), "socketpair");
112 }
113
114 pid = fork();
115 if (pid == -1) {
116 throw std::system_error(errno, std::system_category(), "fork");
117 }
118 // Parent process closes the descriptor for socket 0, child closes the descriptor for socket 1.
119 if (close(fds[pid ? 0 : 1]) != 0) {
120 throw std::system_error(errno, std::system_category(), "close");
121 }
122 if (!pid) {
123 // Child process must close all potentially open descriptors, except socket 0.
124 const int maxFd = MaxFd();
125 for (int fd = 3; fd < maxFd; ++fd) {
126 if (fd != fds[0]) {
127 close(fd);
128 }
129 }
130 ExecProcess(fd_to_args(fds[0]));
131 }
132 return fds[1];
133}
134
135void ExecProcess(const std::vector<std::string>& args)
136{
137 std::vector<char*> argv;
138 argv.reserve(args.size());
139 for (const auto& arg : args) {
140 argv.push_back(const_cast<char*>(arg.c_str()));
141 }
142 argv.push_back(nullptr);
143 if (execvp(argv[0], argv.data()) != 0) {
144 perror("execvp failed");
145 if (errno == ENOENT && !args.empty()) {
146 std::cerr << "Missing executable: " << fs::weakly_canonical(args.front()) << '\n';
147 }
148 _exit(1);
149 }
150}
151
152int WaitProcess(int pid)
153{
154 int status;
155 if (::waitpid(pid, &status, 0 /* options */) != pid) {
156 throw std::system_error(errno, std::system_category(), "waitpid");
157 }
158 return status;
159}
160
161} // namespace mp
ArgsManager & args
Definition: bitcoind.cpp:282
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:152
std::string ThreadName(const char *exe_name)
Format current thread name as "{exe_name}-{$pid}/{thread_name}-{$tid}".
Definition: util.cpp:52
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:107
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:135
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:83
for(const CTxIn &txin :tx.vin)
Definition: validation.cpp:406