Show file:line where panic() was called from

This commit is contained in:
SChernykh 2023-01-14 12:19:25 +01:00
parent 2c4c2b8469
commit d4329ae594
10 changed files with 55 additions and 54 deletions

View file

@ -75,7 +75,7 @@ P2PServer::P2PServer(p2pool* pool)
[this](bool is_v6, const std::string& /*address*/, const std::string& ip, int port) [this](bool is_v6, const std::string& /*address*/, const std::string& ip, int port)
{ {
if (!str_to_ip(is_v6, ip.c_str(), m_socks5ProxyIP)) { if (!str_to_ip(is_v6, ip.c_str(), m_socks5ProxyIP)) {
panic(); PANIC_STOP();
} }
m_socks5ProxyV6 = is_v6; m_socks5ProxyV6 = is_v6;
m_socks5ProxyPort = port; m_socks5ProxyPort = port;
@ -95,7 +95,7 @@ P2PServer::P2PServer(p2pool* pool)
int err = uv_async_init(&m_loop, &m_broadcastAsync, on_broadcast); int err = uv_async_init(&m_loop, &m_broadcastAsync, on_broadcast);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
m_broadcastAsync.data = this; m_broadcastAsync.data = this;
m_broadcastQueue.reserve(2); m_broadcastQueue.reserve(2);
@ -103,21 +103,21 @@ P2PServer::P2PServer(p2pool* pool)
err = uv_async_init(&m_loop, &m_connectToPeersAsync, on_connect_to_peers); err = uv_async_init(&m_loop, &m_connectToPeersAsync, on_connect_to_peers);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
m_connectToPeersAsync.data = this; m_connectToPeersAsync.data = this;
err = uv_async_init(&m_loop, &m_showPeersAsync, on_show_peers); err = uv_async_init(&m_loop, &m_showPeersAsync, on_show_peers);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
m_showPeersAsync.data = this; m_showPeersAsync.data = this;
err = uv_timer_init(&m_loop, &m_timer); err = uv_timer_init(&m_loop, &m_timer);
if (err) { if (err) {
LOGERR(1, "failed to create timer, error " << uv_err_name(err)); LOGERR(1, "failed to create timer, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
if (m_cache) { if (m_cache) {
@ -130,7 +130,7 @@ P2PServer::P2PServer(p2pool* pool)
err = uv_timer_start(&m_timer, on_timer, 1000, m_timerInterval * 1000); err = uv_timer_start(&m_timer, on_timer, 1000, m_timerInterval * 1000);
if (err) { if (err) {
LOGERR(1, "failed to start timer, error " << uv_err_name(err)); LOGERR(1, "failed to start timer, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
load_peer_list(); load_peer_list();

View file

@ -701,14 +701,14 @@ void p2pool::download_block_headers(uint64_t current_height)
} }
else { else {
LOGERR(1, "fatal error: couldn't download block header for seed height " << height); LOGERR(1, "fatal error: couldn't download block header for seed height " << height);
panic(); PANIC_STOP();
} }
}, },
[height](const char* data, size_t size) [height](const char* data, size_t size)
{ {
if (size > 0) { if (size > 0) {
LOGERR(1, "fatal error: couldn't download block header for seed height " << height << ", error " << log::const_buf(data, size)); LOGERR(1, "fatal error: couldn't download block header for seed height " << height << ", error " << log::const_buf(data, size));
panic(); PANIC_STOP();
} }
}); });
} }
@ -729,7 +729,7 @@ void p2pool::download_block_headers(uint64_t current_height)
} }
catch (const std::exception& e) { catch (const std::exception& e) {
LOGERR(1, "Couldn't start ZMQ reader: exception " << e.what()); LOGERR(1, "Couldn't start ZMQ reader: exception " << e.what());
panic(); PANIC_STOP();
} }
m_stratumServer = new StratumServer(this); m_stratumServer = new StratumServer(this);
@ -932,7 +932,7 @@ void p2pool::parse_get_info_rpc(const char* data, size_t size)
if (monero_network != sidechain_network) { if (monero_network != sidechain_network) {
LOGERR(1, "monerod is on " << monero_network << ", but you're mining to a " << sidechain_network << " sidechain"); LOGERR(1, "monerod is on " << monero_network << ", but you're mining to a " << sidechain_network << " sidechain");
panic(); PANIC_STOP();
} }
get_version(); get_version();
@ -1002,7 +1002,7 @@ void p2pool::parse_get_version_rpc(const char* data, size_t size)
const uint64_t required_version_hi = required >> 16; const uint64_t required_version_hi = required >> 16;
const uint64_t required_version_lo = required & 65535; const uint64_t required_version_lo = required & 65535;
LOGERR(1, "monerod RPC v" << version_hi << '.' << version_lo << " is incompatible, update to RPC >= v" << required_version_hi << '.' << required_version_lo << " (Monero v0.18.0.0 or newer)"); LOGERR(1, "monerod RPC v" << version_hi << '.' << version_lo << " is incompatible, update to RPC >= v" << required_version_hi << '.' << required_version_lo << " (Monero v0.18.0.0 or newer)");
panic(); PANIC_STOP();
} }
get_miner_data(); get_miner_data();
@ -1577,7 +1577,7 @@ int p2pool::run()
catch (const std::exception& e) { catch (const std::exception& e) {
const char* s = e.what(); const char* s = e.what();
LOGERR(1, "exception " << s); LOGERR(1, "exception " << s);
panic(); PANIC_STOP();
} }
m_stopped = true; m_stopped = true;

View file

@ -34,7 +34,7 @@ p2pool_api::p2pool_api(const std::string& api_path, const bool local_stats)
{ {
if (m_apiPath.empty()) { if (m_apiPath.empty()) {
LOGERR(1, "api path is empty"); LOGERR(1, "api path is empty");
panic(); PANIC_STOP();
} }
if ((m_apiPath.back() != '/') if ((m_apiPath.back() != '/')
@ -48,13 +48,13 @@ p2pool_api::p2pool_api(const std::string& api_path, const bool local_stats)
struct stat buf; struct stat buf;
if (stat(m_apiPath.c_str(), &buf) != 0) { if (stat(m_apiPath.c_str(), &buf) != 0) {
LOGERR(1, "path " << m_apiPath << " doesn't exist"); LOGERR(1, "path " << m_apiPath << " doesn't exist");
panic(); PANIC_STOP();
} }
int result = uv_async_init(uv_default_loop_checked(), &m_dumpToFileAsync, on_dump_to_file); int result = uv_async_init(uv_default_loop_checked(), &m_dumpToFileAsync, on_dump_to_file);
if (result) { if (result) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(result)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(result));
panic(); PANIC_STOP();
} }
m_dumpToFileAsync.data = this; m_dumpToFileAsync.data = this;
@ -93,7 +93,7 @@ void p2pool_api::create_dir(const std::string& path)
result = errno; result = errno;
if (result != EEXIST) { if (result != EEXIST) {
LOGERR(1, "mkdir(" << path << ") failed, error " << result); LOGERR(1, "mkdir(" << path << ") failed, error " << result);
panic(); PANIC_STOP();
} }
} }
} }

View file

@ -226,7 +226,7 @@ std::vector<uint8_t> PoolBlock::serialize_mainchain_data_nolock(size_t* header_s
#if POOL_BLOCK_DEBUG #if POOL_BLOCK_DEBUG
if (!nonce && !extra_nonce && !m_mainChainDataDebug.empty() && (data != m_mainChainDataDebug)) { if (!nonce && !extra_nonce && !m_mainChainDataDebug.empty() && (data != m_mainChainDataDebug)) {
LOGERR(1, "serialize_mainchain_data() has a bug, fix it!"); LOGERR(1, "serialize_mainchain_data() has a bug, fix it!");
panic(); PANIC_STOP();
} }
#endif #endif
@ -280,7 +280,7 @@ std::vector<uint8_t> PoolBlock::serialize_sidechain_data() const
#if POOL_BLOCK_DEBUG #if POOL_BLOCK_DEBUG
if (!m_sideChainDataDebug.empty() && (data != m_sideChainDataDebug)) { if (!m_sideChainDataDebug.empty() && (data != m_sideChainDataDebug)) {
LOGERR(1, "serialize_sidechain_data() has a bug, fix it!"); LOGERR(1, "serialize_sidechain_data() has a bug, fix it!");
panic(); PANIC_STOP();
} }
#endif #endif

View file

@ -68,7 +68,7 @@ RandomX_Hasher::RandomX_Hasher(p2pool* pool)
m_cache[i] = randomx_alloc_cache(flags); m_cache[i] = randomx_alloc_cache(flags);
if (!m_cache[i]) { if (!m_cache[i]) {
LOGERR(1, "couldn't allocate RandomX cache, aborting"); LOGERR(1, "couldn't allocate RandomX cache, aborting");
panic(); PANIC_STOP();
} }
} }
memory_allocated += RANDOMX_ARGON_MEMORY * 1024; memory_allocated += RANDOMX_ARGON_MEMORY * 1024;
@ -206,7 +206,7 @@ void RandomX_Hasher::set_seed(const hash& seed)
m_vm[m_index].vm = randomx_create_vm(flags, m_cache[m_index], nullptr); m_vm[m_index].vm = randomx_create_vm(flags, m_cache[m_index], nullptr);
if (!m_vm[m_index].vm) { if (!m_vm[m_index].vm) {
LOGERR(1, "couldn't allocate RandomX light VM, aborting"); LOGERR(1, "couldn't allocate RandomX light VM, aborting");
panic(); PANIC_STOP();
} }
} }
} }
@ -308,7 +308,7 @@ void RandomX_Hasher::set_old_seed(const hash& seed)
m_vm[old_index].vm = randomx_create_vm(flags, m_cache[old_index], nullptr); m_vm[old_index].vm = randomx_create_vm(flags, m_cache[old_index], nullptr);
if (!m_vm[old_index].vm) { if (!m_vm[old_index].vm) {
LOGERR(1, "couldn't allocate RandomX light VM, aborting"); LOGERR(1, "couldn't allocate RandomX light VM, aborting");
panic(); PANIC_STOP();
} }
} }
} }
@ -376,7 +376,7 @@ RandomX_Hasher_RPC::RandomX_Hasher_RPC(p2pool* pool)
int err = uv_loop_init(&m_loop); int err = uv_loop_init(&m_loop);
if (err) { if (err) {
LOGERR(1, "failed to create event loop, error " << uv_err_name(err)); LOGERR(1, "failed to create event loop, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
// Init loop user data before running it // Init loop user data before running it
@ -394,7 +394,7 @@ RandomX_Hasher_RPC::RandomX_Hasher_RPC(p2pool* pool)
err = uv_thread_create(&m_loopThread, loop, this); err = uv_thread_create(&m_loopThread, loop, this);
if (err) { if (err) {
LOGERR(1, "failed to start event loop thread, error " << uv_err_name(err)); LOGERR(1, "failed to start event loop thread, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
} }

View file

@ -70,11 +70,11 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
LOGINFO(1, log::LightCyan() << "network type = " << m_networkType); LOGINFO(1, log::LightCyan() << "network type = " << m_networkType);
if (m_pool && !load_config(m_pool->params().m_config)) { if (m_pool && !load_config(m_pool->params().m_config)) {
panic(); PANIC_STOP();
} }
if (!check_config()) { if (!check_config()) {
panic(); PANIC_STOP();
} }
uv_rwlock_init_checked(&m_sidechainLock); uv_rwlock_init_checked(&m_sidechainLock);
@ -117,7 +117,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
cache = randomx_alloc_cache(flags); cache = randomx_alloc_cache(flags);
if (!cache) { if (!cache) {
LOGERR(1, "couldn't allocate RandomX cache, aborting"); LOGERR(1, "couldn't allocate RandomX cache, aborting");
panic(); PANIC_STOP();
} }
} }
@ -146,7 +146,7 @@ SideChain::SideChain(p2pool* pool, NetworkType type, const char* pool_name)
m_consensusId.assign(id.h, id.h + HASH_SIZE); m_consensusId.assign(id.h, id.h + HASH_SIZE);
#else #else
LOGERR(1, "Can't calculate consensus ID without RandomX library"); LOGERR(1, "Can't calculate consensus ID without RandomX library");
panic(); PANIC_STOP();
#endif #endif
} }

View file

@ -76,7 +76,7 @@ StratumServer::StratumServer(p2pool* pool)
const int err = uv_async_init(&m_loop, &m_blobsAsync, on_blobs_ready); const int err = uv_async_init(&m_loop, &m_blobsAsync, on_blobs_ready);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
m_blobsAsync.data = this; m_blobsAsync.data = this;
m_blobsQueue.reserve(2); m_blobsQueue.reserve(2);

View file

@ -41,7 +41,7 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
int err = uv_loop_init(&m_loop); int err = uv_loop_init(&m_loop);
if (err) { if (err) {
LOGERR(1, "failed to create event loop, error " << uv_err_name(err)); LOGERR(1, "failed to create event loop, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
// Init loop user data before running it // Init loop user data before running it
@ -50,14 +50,14 @@ TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::TCPServer(allocate_client_callback all
err = uv_async_init(&m_loop, &m_dropConnectionsAsync, on_drop_connections); err = uv_async_init(&m_loop, &m_dropConnectionsAsync, on_drop_connections);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
m_dropConnectionsAsync.data = this; m_dropConnectionsAsync.data = this;
err = uv_async_init(&m_loop, &m_shutdownAsync, on_shutdown); err = uv_async_init(&m_loop, &m_shutdownAsync, on_shutdown);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
m_shutdownAsync.data = this; m_shutdownAsync.data = this;
@ -133,7 +133,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::start_listening(const std::string
{ {
if (listen_addresses.empty()) { if (listen_addresses.empty()) {
LOGERR(1, "listen address not set"); LOGERR(1, "listen address not set");
panic(); PANIC_STOP();
} }
parse_address_list(listen_addresses, parse_address_list(listen_addresses,
@ -144,7 +144,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::start_listening(const std::string
} }
else if (m_listenPort != port) { else if (m_listenPort != port) {
LOGERR(1, "all sockets must be listening on the same port number, fix the command line"); LOGERR(1, "all sockets must be listening on the same port number, fix the command line");
panic(); PANIC_STOP();
} }
uv_tcp_t* socket = new uv_tcp_t(); uv_tcp_t* socket = new uv_tcp_t();
@ -159,14 +159,14 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::start_listening(const std::string
int err = uv_tcp_init(&m_loop, socket); int err = uv_tcp_init(&m_loop, socket);
if (err) { if (err) {
LOGERR(1, "failed to create tcp server handle, error " << uv_err_name(err)); LOGERR(1, "failed to create tcp server handle, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
socket->data = this; socket->data = this;
err = uv_tcp_nodelay(socket, 1); err = uv_tcp_nodelay(socket, 1);
if (err) { if (err) {
LOGERR(1, "failed to set tcp_nodelay on tcp server handle, error " << uv_err_name(err)); LOGERR(1, "failed to set tcp_nodelay on tcp server handle, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
if (is_v6) { if (is_v6) {
@ -174,13 +174,13 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::start_listening(const std::string
err = uv_ip6_addr(ip.c_str(), port, &addr6); err = uv_ip6_addr(ip.c_str(), port, &addr6);
if (err) { if (err) {
LOGERR(1, "failed to parse IPv6 address " << ip << ", error " << uv_err_name(err)); LOGERR(1, "failed to parse IPv6 address " << ip << ", error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
err = uv_tcp_bind(socket, reinterpret_cast<sockaddr*>(&addr6), UV_TCP_IPV6ONLY); err = uv_tcp_bind(socket, reinterpret_cast<sockaddr*>(&addr6), UV_TCP_IPV6ONLY);
if (err) { if (err) {
LOGERR(1, "failed to bind tcp server IPv6 socket " << address << ", error " << uv_err_name(err)); LOGERR(1, "failed to bind tcp server IPv6 socket " << address << ", error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
} }
else { else {
@ -188,20 +188,20 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::start_listening(const std::string
err = uv_ip4_addr(ip.c_str(), port, &addr); err = uv_ip4_addr(ip.c_str(), port, &addr);
if (err) { if (err) {
LOGERR(1, "failed to parse IPv4 address " << ip << ", error " << uv_err_name(err)); LOGERR(1, "failed to parse IPv4 address " << ip << ", error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
err = uv_tcp_bind(socket, reinterpret_cast<sockaddr*>(&addr), 0); err = uv_tcp_bind(socket, reinterpret_cast<sockaddr*>(&addr), 0);
if (err) { if (err) {
LOGERR(1, "failed to bind tcp server IPv4 socket " << address << ", error " << uv_err_name(err)); LOGERR(1, "failed to bind tcp server IPv4 socket " << address << ", error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
} }
err = uv_listen(reinterpret_cast<uv_stream_t*>(socket), DEFAULT_BACKLOG, on_new_connection); err = uv_listen(reinterpret_cast<uv_stream_t*>(socket), DEFAULT_BACKLOG, on_new_connection);
if (err) { if (err) {
LOGERR(1, "failed to listen on tcp server socket " << address << ", error " << uv_err_name(err)); LOGERR(1, "failed to listen on tcp server socket " << address << ", error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
LOGINFO(1, "listening on " << log::Gray() << address); LOGINFO(1, "listening on " << log::Gray() << address);
@ -210,7 +210,7 @@ void TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::start_listening(const std::string
const int err = uv_thread_create(&m_loopThread, loop, this); const int err = uv_thread_create(&m_loopThread, loop, this);
if (err) { if (err) {
LOGERR(1, "failed to start event loop thread, error " << uv_err_name(err)); LOGERR(1, "failed to start event loop thread, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
} }
@ -509,7 +509,7 @@ bool TCPServer<READ_BUF_SIZE, WRITE_BUF_SIZE>::send_internal(Client* client, Sen
if (bytes_written > WRITE_BUF_SIZE) { if (bytes_written > WRITE_BUF_SIZE) {
LOGERR(0, "send callback wrote " << bytes_written << " bytes, expected no more than " << WRITE_BUF_SIZE << " bytes"); LOGERR(0, "send callback wrote " << bytes_written << " bytes, expected no more than " << WRITE_BUF_SIZE << " bytes");
panic(); PANIC_STOP();
} }
if (bytes_written == 0) { if (bytes_written == 0) {

View file

@ -29,9 +29,6 @@ static constexpr char log_category_prefix[] = "Util ";
namespace p2pool { namespace p2pool {
#define STR2(X) STR(X)
#define STR(X) #X
const char* VERSION = "v" STR2(P2POOL_VERSION_MAJOR) "." STR2(P2POOL_VERSION_MINOR) " (built" const char* VERSION = "v" STR2(P2POOL_VERSION_MAJOR) "." STR2(P2POOL_VERSION_MINOR) " (built"
#if defined(__clang__) #if defined(__clang__)
" with clang/" __clang_version__ " with clang/" __clang_version__
@ -42,13 +39,12 @@ const char* VERSION = "v" STR2(P2POOL_VERSION_MAJOR) "." STR2(P2POOL_VERSION_MIN
#endif #endif
" on " __DATE__ ")"; " on " __DATE__ ")";
#undef STR2
#undef STR
MinerCallbackHandler::~MinerCallbackHandler() {} MinerCallbackHandler::~MinerCallbackHandler() {}
void panic() void panic_stop(const char* message)
{ {
fprintf(stderr, "P2Pool can't continue execution: panic at %s\n", message);
p2pool::log::stop(); p2pool::log::stop();
do { do {
#ifdef _WIN32 #ifdef _WIN32
@ -254,7 +250,7 @@ void uv_cond_init_checked(uv_cond_t* cond)
const int result = uv_cond_init(cond); const int result = uv_cond_init(cond);
if (result) { if (result) {
LOGERR(1, "failed to create conditional variable, error " << uv_err_name(result)); LOGERR(1, "failed to create conditional variable, error " << uv_err_name(result));
panic(); PANIC_STOP();
} }
} }
@ -263,7 +259,7 @@ void uv_mutex_init_checked(uv_mutex_t* mutex)
const int result = uv_mutex_init(mutex); const int result = uv_mutex_init(mutex);
if (result) { if (result) {
LOGERR(1, "failed to create mutex, error " << uv_err_name(result)); LOGERR(1, "failed to create mutex, error " << uv_err_name(result));
panic(); PANIC_STOP();
} }
} }
@ -272,7 +268,7 @@ void uv_rwlock_init_checked(uv_rwlock_t* lock)
const int result = uv_rwlock_init(lock); const int result = uv_rwlock_init(lock);
if (result) { if (result) {
LOGERR(1, "failed to create rwlock, error " << uv_err_name(result)); LOGERR(1, "failed to create rwlock, error " << uv_err_name(result));
panic(); PANIC_STOP();
} }
} }
@ -281,7 +277,7 @@ void uv_async_init_checked(uv_loop_t* loop, uv_async_t* async, uv_async_cb async
const int err = uv_async_init(loop, async, async_cb); const int err = uv_async_init(loop, async, async_cb);
if (err) { if (err) {
LOGERR(1, "uv_async_init failed, error " << uv_err_name(err)); LOGERR(1, "uv_async_init failed, error " << uv_err_name(err));
panic(); PANIC_STOP();
} }
} }

View file

@ -149,7 +149,12 @@ FORCEINLINE T read_unaligned(const T* p)
template<typename T, size_t N> FORCEINLINE constexpr size_t array_size(T(&)[N]) { return N; } template<typename T, size_t N> FORCEINLINE constexpr size_t array_size(T(&)[N]) { return N; }
template<typename T, typename U, size_t N> FORCEINLINE constexpr size_t array_size(T(U::*)[N]) { return N; } template<typename T, typename U, size_t N> FORCEINLINE constexpr size_t array_size(T(U::*)[N]) { return N; }
[[noreturn]] void panic(); [[noreturn]] void panic_stop(const char* message);
#define STR(X) #X
#define STR2(X) STR(X)
#define PANIC_STOP(...) panic_stop(__FILE__ ":" STR2(__LINE__))
void make_thread_background(); void make_thread_background();