From 7a65ed908244e674a2a1df75af57befda2722974 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 21 Mar 2024 10:56:14 +0900 Subject: [PATCH] Refactor --- CMakeLists.txt | 2 + common/main.cc | 136 +++-------------------------------------- common/signal-unix.cc | 77 +++++++++++++++++++++++ common/signal-win32.cc | 46 ++++++++++++++ 4 files changed, 133 insertions(+), 128 deletions(-) create mode 100644 common/signal-unix.cc create mode 100644 common/signal-win32.cc diff --git a/CMakeLists.txt b/CMakeLists.txt index 8868eaf7..f479b4c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -381,11 +381,13 @@ if(WIN32) target_sources(mold PRIVATE common/jobs-win32.cc common/mapped-file-win32.cc + common/signal-win32.cc ) else() target_sources(mold PRIVATE common/jobs-unix.cc common/mapped-file-unix.cc + common/signal-unix.cc ) endif() diff --git a/common/main.cc b/common/main.cc index f70ad932..df9ed012 100644 --- a/common/main.cc +++ b/common/main.cc @@ -1,11 +1,7 @@ #include "common.h" #include "config.h" -#include -#include -#include #include -#include #ifdef USE_SYSTEM_MIMALLOC #include @@ -22,21 +18,12 @@ #ifdef _WIN32 # define unlink _unlink -# define write _write #endif namespace mold { std::string mold_version_string = MOLD_VERSION; -namespace elf { -int main(int argc, char **argv); -} - -namespace macho { -int main(int argc, char **argv); -} - static std::string get_mold_version() { if (mold_git_hash.empty()) return "mold "s + MOLD_VERSION + " (compatible with GNU ld)"; @@ -49,31 +36,6 @@ void cleanup() { unlink(output_tmpfile); } -#ifdef _WIN32 -std::string errno_string() { - LPVOID buf; - DWORD dw = GetLastError(); - - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, dw, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&buf, 0, nullptr); - - std::string ret = (char *)buf; - LocalFree(buf); - return ret; -} -#else -std::string errno_string() { - // strerror is not thread-safe, so guard it with a lock. - static std::mutex mu; - std::scoped_lock lock(mu); - return strerror(errno); -} -#endif - // Returns the path of the mold executable itself std::string get_self_path() { #if __APPLE__ @@ -105,96 +67,6 @@ std::string get_self_path() { #endif } -// mold mmap's an output file, and the mmap succeeds even if there's -// no enough space left on the filesystem. The actual disk blocks are -// not allocated on the mmap call but when the program writes to it -// for the first time. -// -// If a disk becomes full as a result of a write to an mmap'ed memory -// region, the failure of the write is reported as a SIGBUS or structured -// exeption with code EXCEPTION_IN_PAGE_ERROR on Windows. This -// signal handler catches that signal and prints out a user-friendly -// error message. Without this, it is very hard to realize that the -// disk might be full. -#ifdef _WIN32 - -static LONG WINAPI vectored_handler(_EXCEPTION_POINTERS *exception_info) { - static std::mutex mu; - std::scoped_lock lock{mu}; - - PEXCEPTION_RECORD exception_record = exception_info->ExceptionRecord; - ULONG_PTR *exception_information = exception_record->ExceptionInformation; - if (exception_record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR && - (ULONG_PTR)output_buffer_start <= exception_information[1] && - exception_information[1] < (ULONG_PTR)output_buffer_end) { - - const char msg[] = "mold: failed to write to an output file. Disk full?\n"; - (void)!write(_fileno(stderr), msg, sizeof(msg) - 1); - } - - cleanup(); - _exit(1); -} - -void install_signal_handler() { - AddVectoredExceptionHandler(0, vectored_handler); -} - -#else - -static std::string sigabrt_msg; - -static void sighandler(int signo, siginfo_t *info, void *ucontext) { - static std::mutex mu; - std::scoped_lock lock{mu}; - - // Handle disk full error - switch (signo) { - case SIGSEGV: - case SIGBUS: - if (output_buffer_start <= info->si_addr && - info->si_addr < output_buffer_end) { - const char msg[] = "mold: failed to write to an output file. Disk full?\n"; - (void)!write(STDERR_FILENO, msg, sizeof(msg) - 1); - } - break; - case SIGABRT: { - (void)!write(STDERR_FILENO, &sigabrt_msg[0], sigabrt_msg.size()); - break; - } - } - - // Re-throw the signal - signal(SIGSEGV, SIG_DFL); - signal(SIGBUS, SIG_DFL); - signal(SIGABRT, SIG_DFL); - - raise(signo); -} - -void install_signal_handler() { - struct sigaction action; - action.sa_sigaction = sighandler; - sigemptyset(&action.sa_mask); - action.sa_flags = SA_SIGINFO; - - sigaction(SIGSEGV, &action, NULL); - sigaction(SIGBUS, &action, NULL); - - // OneTBB 2021.9.0 has the interface version 12090. - if (TBB_runtime_interface_version() < 12090) { - sigabrt_msg = "mold: aborted\n" - "mold: mold with libtbb version 2021.9.0 or older is known to be unstable " - "under heavy load. Your libtbb version is " + - std::string(TBB_runtime_version()) + - ". Please upgrade your libtbb library and try again.\n"; - - sigaction(SIGABRT, &action, NULL); - } -} - -#endif - i64 get_default_thread_count() { // mold doesn't scale well above 32 threads. int n = tbb::global_control::active_value( @@ -204,6 +76,14 @@ i64 get_default_thread_count() { } // namespace mold +namespace mold::elf { +int main(int argc, char **argv); +} + +namespace mold::macho { +int main(int argc, char **argv); +} + int main(int argc, char **argv) { mold::mold_version = mold::get_mold_version(); return mold::elf::main(argc, argv); diff --git a/common/signal-unix.cc b/common/signal-unix.cc new file mode 100644 index 00000000..9bd58543 --- /dev/null +++ b/common/signal-unix.cc @@ -0,0 +1,77 @@ +#include "common.h" + +#include +#include + +namespace mold { + +std::string errno_string() { + // strerror is not thread-safe, so guard it with a lock. + static std::mutex mu; + std::scoped_lock lock(mu); + return strerror(errno); +} + +// mold mmap's an output file, and the mmap succeeds even if there's +// no enough space left on the filesystem. The actual disk blocks are +// not allocated on the mmap call but when the program writes to it +// for the first time. +// +// If a disk becomes full as a result of a write to an mmap'ed memory +// region, the failure of the write is reported as a SIGBUS or structured +// exeption with code EXCEPTION_IN_PAGE_ERROR on Windows. This +// signal handler catches that signal and prints out a user-friendly +// error message. Without this, it is very hard to realize that the +// disk might be full. +static std::string sigabrt_msg; + +static void sighandler(int signo, siginfo_t *info, void *ucontext) { + static std::mutex mu; + std::scoped_lock lock{mu}; + + // Handle disk full error + switch (signo) { + case SIGSEGV: + case SIGBUS: + if (output_buffer_start <= info->si_addr && + info->si_addr < output_buffer_end) { + const char msg[] = "mold: failed to write to an output file. Disk full?\n"; + (void)!write(STDERR_FILENO, msg, sizeof(msg) - 1); + } + break; + case SIGABRT: { + (void)!write(STDERR_FILENO, &sigabrt_msg[0], sigabrt_msg.size()); + break; + } + } + + // Re-throw the signal + signal(SIGSEGV, SIG_DFL); + signal(SIGBUS, SIG_DFL); + signal(SIGABRT, SIG_DFL); + + raise(signo); +} + +void install_signal_handler() { + struct sigaction action; + action.sa_sigaction = sighandler; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO; + + sigaction(SIGSEGV, &action, NULL); + sigaction(SIGBUS, &action, NULL); + + // OneTBB 2021.9.0 has the interface version 12090. + if (TBB_runtime_interface_version() < 12090) { + sigabrt_msg = "mold: aborted\n" + "mold: mold with libtbb version 2021.9.0 or older is known to be unstable " + "under heavy load. Your libtbb version is " + + std::string(TBB_runtime_version()) + + ". Please upgrade your libtbb library and try again.\n"; + + sigaction(SIGABRT, &action, NULL); + } +} + +} // namespace mold diff --git a/common/signal-win32.cc b/common/signal-win32.cc new file mode 100644 index 00000000..9b5a0e48 --- /dev/null +++ b/common/signal-win32.cc @@ -0,0 +1,46 @@ +#include "common.h" + +#include + +namespace mold { + +std::string errno_string() { + LPVOID buf; + DWORD dw = GetLastError(); + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, dw, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&buf, 0, nullptr); + + std::string ret = (char *)buf; + LocalFree(buf); + return ret; +} + +static LONG WINAPI vectored_handler(_EXCEPTION_POINTERS *exception_info) { + static std::mutex mu; + std::scoped_lock lock{mu}; + + PEXCEPTION_RECORD rec = exception_info->ExceptionRecord; + ULONG_PTR *p = rec->ExceptionInformation; + + if (rec->ExceptionCode == EXCEPTION_IN_PAGE_ERROR && + (ULONG_PTR)output_buffer_start <= p[1] && + p[1] < (ULONG_PTR)output_buffer_end) { + static const char msg[] = + "mold: failed to write to an output file. Disk full?\n"; + (void)!_write(_fileno(stderr), msg, sizeof(msg) - 1); + } + + cleanup(); + _exit(1); +} + +void install_signal_handler() { + AddVectoredExceptionHandler(0, vectored_handler); +} + +} // namespace mold