diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9ed1ebf..4d36522 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,6 +24,11 @@ on: schedule: - cron: '44 11 * * 0' +permissions: + actions: read + contents: read + security-events: write + jobs: analyze: name: Analyze diff --git a/docs/COMMAND_LINE.MD b/docs/COMMAND_LINE.MD index d0694d1..7b3ac4e 100644 --- a/docs/COMMAND_LINE.MD +++ b/docs/COMMAND_LINE.MD @@ -14,6 +14,9 @@ --loglevel Verbosity of the log, integer number between 0 and 6 --data-dir Path to store general p2pool files (log, cache, peer data, etc.), default is current directory --log-file Path to the log file, default is "p2pool.log" in p2pool's working directory +--no-console-log Disable logging to the console +--no-log-file Disable logging to the file +--disable-log Equivalent to --no-console-log --no-log-file, disables logging entirely and saves ~8 MB of memory --sidechain-config Name of the p2pool sidechain parameters file (only use it if you run your own sidechain) --data-api Path to the p2pool JSON data (use it in tandem with an external web-server). Not affected by --data-dir setting! --local-api Enable /local/ path in api path for Stratum Server and built-in miner statistics diff --git a/src/log.cpp b/src/log.cpp index 2295355..430bfd8 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -124,6 +124,8 @@ public: , m_readPos(0) , m_stopped(false) , m_needReopen(false) + , m_consoleLogEnabled(p.m_consoleLogEnabled) + , m_logFileEnabled(p.m_logFileEnabled) , m_logFileLastStatTime(0) , m_workerWaiting(false) { @@ -131,8 +133,6 @@ public: SetUnhandledExceptionFilter(UnhandledExceptionFilter); #endif - set_main_thread(); - std::setlocale(LC_ALL, "C"); m_logFilePath = p.m_logFilePath.empty() ? (p.m_dataDir + log_file_name) : p.m_logFilePath; @@ -165,8 +165,6 @@ public: CONSOLE_COLORS = false; } - init_uv_threadpool(); - err = uv_thread_create(&m_worker, run_wrapper, this); if (err) { fprintf(stderr, "failed to start logger thread (%s), aborting\n", uv_err_name(err)); @@ -199,7 +197,9 @@ public: uv_cond_destroy(&m_cond); uv_mutex_destroy(&m_mutex); - m_logFile.close(); + if (m_logFileEnabled) { + m_logFile.close(); + } } FORCEINLINE void write(const char* buf, uint32_t size) @@ -209,7 +209,7 @@ public: do { if (writePos - m_readPos.load(std::memory_order_relaxed) > BUF_SIZE - SLOT_SIZE) { // Buffer is full, can't log normally - if (size > 3) { + if ((size > 3) && m_consoleLogEnabled) { fwrite(buf + 3, 1, size - 3, stderr); } return; @@ -243,33 +243,12 @@ public: } private: - static void init_uv_threadpool() - { -#ifdef _MSC_VER -#define putenv _putenv -#endif - - const uint32_t N = std::min(std::max(std::thread::hardware_concurrency(), 4U), 8U); - - static char buf[40] = {}; - log::Stream s(buf); - s << "UV_THREADPOOL_SIZE=" << N << '\0'; - - int err = putenv(buf); - if (err != 0) { - err = errno; - fprintf(stderr, "Couldn't set UV thread pool size to %u threads, putenv returned error %d\n", N, err); - } - - static uv_work_t dummy; - err = uv_queue_work(uv_default_loop_checked(), &dummy, [](uv_work_t*) {}, nullptr); - if (err) { - fprintf(stderr, "init_uv_threadpool: uv_queue_work failed, error %s\n", uv_err_name(err)); - } - } - bool reopen(struct stat& st) { + if (!m_logFileEnabled) { + return true; + } + st = {}; if (m_logFile.is_open()) { @@ -290,7 +269,6 @@ private: return true; } -private: static void run_wrapper(void* arg) { reinterpret_cast(arg)->run(); } NOINLINE void run() @@ -299,7 +277,7 @@ private: struct stat log_file_st; - if (!reopen(log_file_st)) { + if (!reopen(log_file_st) && m_consoleLogEnabled) { fprintf(stderr, "failed to open %s: error %d\n", m_logFilePath.c_str(), errno); } @@ -354,9 +332,11 @@ private: strip_colors(p, size); } - fwrite(p, 1, size, (severity == 1) ? stdout : stderr); + if (m_consoleLogEnabled) { + fwrite(p, 1, size, (severity == 1) ? stdout : stderr); + } - if (m_logFile.is_open()) { + if (m_logFileEnabled && m_logFile.is_open()) { if (c) { strip_colors(p, size); } @@ -378,12 +358,12 @@ private: // Mark this log slot empty severity_ptr->store('\0', std::memory_order_relaxed); - m_readPos.fetch_add(SLOT_SIZE, std::memory_order_relaxed); - } while (m_readPos.load(std::memory_order_relaxed) != writePos); + // fetch_add returns the pre-increment value; "+ SLOT_SIZE" gives us the new m_readPos + } while (m_readPos.fetch_add(SLOT_SIZE, std::memory_order_relaxed) + SLOT_SIZE != writePos); } // Flush the log file only after all pending log lines have been written - if (m_logFile.is_open()) { + if (m_logFileEnabled && m_logFile.is_open()) { m_logFile.flush(); // Automatically reopen the file if either it @@ -455,6 +435,8 @@ private: std::ofstream m_logFile; std::string m_logFilePath; + bool m_consoleLogEnabled; + bool m_logFileEnabled; uint64_t m_logFileLastStatTime; std::atomic m_workerWaiting; @@ -510,9 +492,6 @@ NOINLINE Writer::~Writer() if (worker) { worker->write(m_buf, size); } - else { - fwrite(m_buf + 3, 1, size - 3, (m_buf[0] == 1) ? stdout : stderr); - } #endif } diff --git a/src/main.cpp b/src/main.cpp index 0e450cc..7411704 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -72,6 +72,9 @@ void p2pool_usage() "--loglevel Verbosity of the log, integer number between 0 and %d\n" "--data-dir Path to store general p2pool files (log, cache, peer data, etc.), default is current directory\n" "--log-file Path to the log file, default is \"p2pool.log\" in p2pool's working directory\n" + "--no-console-log Disable logging to the console\n" + "--no-log-file Disable logging to the file\n" + "--disable-log Equivalent to --no-console-log --no-log-file, disables logging entirely and saves ~8 MB of memory\n" "--sidechain-config Name of the p2pool sidechain parameters file (only use it if you run your own sidechain)\n" "--data-api Path to the p2pool JSON data (use it in tandem with an external web-server). Not affected by --data-dir setting!\n" "--local-api Enable /local/ path in api path for Stratum Server and built-in miner statistics\n" @@ -311,6 +314,8 @@ int main(int argc, char* argv[]) return 1; } + p2pool::set_main_thread(); + #if defined(_WIN32) && defined(_MSC_VER) && !defined(NDEBUG) SymInitialize(GetCurrentProcess(), NULL, TRUE); #endif @@ -325,7 +330,7 @@ int main(int argc, char* argv[]) // Create the default libuv loop and initialize libuv here // It will call the important stuff like WSAStartup and many other things // Some P2Pool code will not work without libuv initialized, so the code above this line must be minimal - uv_default_loop(); + p2pool::init_uv(); const p2pool::Params params = params_file.empty() ? get_params(argc, argv) : get_params(params_file); @@ -337,7 +342,12 @@ int main(int argc, char* argv[]) std::filesystem::create_directories(params.m_dataDir, err); } - p2pool::log::start(params); + if (params.m_consoleLogEnabled || params.m_logFileEnabled) { + p2pool::log::start(params); + } + else { + p2pool::log::GLOBAL_LOG_LEVEL = -1; + } p2pool::init_crypto_cache(); @@ -381,7 +391,9 @@ int main(int argc, char* argv[]) p2pool::indexed_hash::cleanup_storage(); #endif - p2pool::log::stop(); + if (params.m_consoleLogEnabled || params.m_logFileEnabled) { + p2pool::log::stop(); + } uv_loop_close(uv_default_loop()); diff --git a/src/params.cpp b/src/params.cpp index 8b3057e..2200c69 100644 --- a/src/params.cpp +++ b/src/params.cpp @@ -304,6 +304,22 @@ bool Params::process_arg(const std::vector& arg) return true; } + if ((arg[0] == "no-console-log")) { + m_consoleLogEnabled = false; + return true; + } + + if ((arg[0] == "no-log-file")) { + m_logFileEnabled = false; + return true; + } + + if ((arg[0] == "disable-log")) { + m_consoleLogEnabled = false; + m_logFileEnabled = false; + return true; + } + if ((arg[0] == "sidechain-config") && has1(arg)) { m_sidechainConfig = arg[1]; return true; diff --git a/src/params.h b/src/params.h index 21ca526..a49caf1 100644 --- a/src/params.h +++ b/src/params.h @@ -92,6 +92,8 @@ struct Params std::string m_p2pPeerList; std::string m_dataDir; std::string m_logFilePath; + bool m_consoleLogEnabled = true; + bool m_logFileEnabled = true; std::string m_sidechainConfig; std::string m_apiPath; uint64_t m_stratumBanTime = DEFAULT_STRATUM_BAN_TIME; diff --git a/src/util.cpp b/src/util.cpp index 3834e7c..a096edd 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -950,6 +950,34 @@ void set_thread_name(const char* name) #endif } +void init_uv() +{ + // Creates the default loop if it doesn't exist yet + uv_default_loop(); + +#ifdef _MSC_VER +#define putenv _putenv +#endif + + const uint32_t N = std::min(std::max(std::thread::hardware_concurrency(), 4U), 8U); + + static char buf[40] = {}; + log::Stream s(buf); + s << "UV_THREADPOOL_SIZE=" << N << '\0'; + + int err = putenv(buf); + if (err != 0) { + err = errno; + fprintf(stderr, "Couldn't set UV thread pool size to %u threads, putenv returned error %d\n", N, err); + } + + static uv_work_t dummy; + err = uv_queue_work(uv_default_loop_checked(), &dummy, [](uv_work_t*) {}, nullptr); + if (err) { + fprintf(stderr, "init_uv_threadpool: uv_queue_work failed, error %s\n", uv_err_name(err)); + } +} + std::string to_onion_v3(const hash& pubkey) { static constexpr uint8_t prefix[] = ".onion checksum"; diff --git a/src/uv_util.h b/src/uv_util.h index b05ab31..a32282a 100644 --- a/src/uv_util.h +++ b/src/uv_util.h @@ -233,5 +233,6 @@ void parallel_run(uv_loop_t* loop, T&& callback, bool wait = false) } void set_thread_name(const char* name); +void init_uv(); } // namespace p2pool