feat: use standard threads (#1019)
This commit is contained in:
parent
645d0a5d5f
commit
0032896711
@ -68,7 +68,6 @@ set (CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
set (CMAKE_VISIBILITY_INLINES_HIDDEN ON)
|
||||
|
||||
set (CMAKE_DEBUG_POSTFIX d)
|
||||
set (CMAKE_THREAD_PREFER_PTHREAD 1)
|
||||
|
||||
find_package (GTest NO_MODULE)
|
||||
|
||||
@ -159,24 +158,6 @@ check_cxx_symbol_exists (backtrace_symbols execinfo.h
|
||||
HAVE_EXECINFO_BACKTRACE_SYMBOLS)
|
||||
check_cxx_symbol_exists (_chsize_s io.h HAVE__CHSIZE_S)
|
||||
|
||||
cmake_push_check_state (RESET)
|
||||
|
||||
set (CMAKE_REQUIRED_DEFINITIONS -D_XOPEN_SOURCE=500)
|
||||
|
||||
if (Threads_FOUND)
|
||||
set (CMAKE_REQUIRED_LIBRARIES Threads::Threads)
|
||||
endif (Threads_FOUND)
|
||||
|
||||
check_cxx_symbol_exists (pthread_threadid_np pthread.h HAVE_PTHREAD_THREADID_NP)
|
||||
|
||||
cmake_pop_check_state ()
|
||||
|
||||
if (HAVE_RWLOCK_INIT AND HAVE_RWLOCK_RDLOCK AND HAVE_RWLOCK_WRLOCK AND
|
||||
HAVE_RWLOCK_UNLOCK AND HAVE_RWLOCK_DESTROY)
|
||||
set (HAVE_RWLOCK TRUE)
|
||||
endif (HAVE_RWLOCK_INIT AND HAVE_RWLOCK_RDLOCK AND HAVE_RWLOCK_WRLOCK AND
|
||||
HAVE_RWLOCK_UNLOCK AND HAVE_RWLOCK_DESTROY)
|
||||
|
||||
cmake_push_check_state (RESET)
|
||||
set (CMAKE_REQUIRED_LIBRARIES dbghelp)
|
||||
check_cxx_symbol_exists (UnDecorateSymbolName "windows.h;dbghelp.h" HAVE_DBGHELP)
|
||||
|
||||
@ -59,8 +59,6 @@ def glog_library(with_gflags = 1, **kwargs):
|
||||
"-Wno-unused-function",
|
||||
"-Wno-unused-local-typedefs",
|
||||
"-Wno-unused-variable",
|
||||
# Allows to include pthread.h.
|
||||
"-DHAVE_PTHREAD",
|
||||
# Allows src/logging.cc to determine the host name.
|
||||
"-DHAVE_SYS_UTSNAME_H",
|
||||
# For src/utilities.cc.
|
||||
@ -98,8 +96,6 @@ def glog_library(with_gflags = 1, **kwargs):
|
||||
darwin_only_copts = [
|
||||
# For stacktrace.
|
||||
"-DHAVE_DLADDR",
|
||||
# Avoid deprecated syscall().
|
||||
"-DHAVE_PTHREAD_THREADID_NP",
|
||||
]
|
||||
|
||||
windows_only_copts = [
|
||||
|
||||
@ -19,9 +19,6 @@
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
#cmakedefine HAVE_GLOB_H
|
||||
|
||||
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||
#cmakedefine HAVE_LIBPTHREAD
|
||||
|
||||
/* define if you have google gmock library */
|
||||
#cmakedefine HAVE_LIB_GMOCK
|
||||
|
||||
@ -37,9 +34,6 @@
|
||||
/* Define if you have the 'pread' function */
|
||||
#cmakedefine HAVE_PREAD
|
||||
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#cmakedefine HAVE_PTHREAD
|
||||
|
||||
/* Define to 1 if you have the <pwd.h> header file. */
|
||||
#cmakedefine HAVE_PWD_H
|
||||
|
||||
@ -115,10 +109,6 @@
|
||||
/* define if we should print file offsets in traces instead of symbolizing. */
|
||||
#cmakedefine PRINT_UNSYMBOLIZED_STACK_TRACES
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
#cmakedefine PTHREAD_CREATE_JOINABLE
|
||||
|
||||
/* The size of `void *', as computed by sizeof. */
|
||||
#cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P}
|
||||
|
||||
@ -128,7 +118,4 @@
|
||||
/* Define if thread-local storage is enabled. */
|
||||
#cmakedefine GLOG_THREAD_LOCAL_STORAGE
|
||||
|
||||
/* Replacement for deprecated syscall(SYS_gettid) on macOS. */
|
||||
#cmakedefine HAVE_PTHREAD_THREADID_NP ${HAVE_PTHREAD_THREADID_NP}
|
||||
|
||||
#endif // GLOG_CONFIG_H
|
||||
|
||||
@ -47,6 +47,7 @@
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@ -130,7 +131,8 @@ struct GLOG_EXPORT LogMessageTime {
|
||||
struct LogMessageInfo {
|
||||
explicit LogMessageInfo(const char* const severity_,
|
||||
const char* const filename_, const int& line_number_,
|
||||
const int& thread_id_, const LogMessageTime& time_)
|
||||
std::thread::id thread_id_,
|
||||
const LogMessageTime& time_)
|
||||
: severity(severity_),
|
||||
filename(filename_),
|
||||
line_number(line_number_),
|
||||
@ -140,7 +142,7 @@ struct LogMessageInfo {
|
||||
const char* const severity;
|
||||
const char* const filename;
|
||||
const int& line_number;
|
||||
const int& thread_id;
|
||||
std::thread::id thread_id;
|
||||
const LogMessageTime& time;
|
||||
};
|
||||
|
||||
|
||||
@ -579,59 +579,6 @@ struct FlagSaver {
|
||||
};
|
||||
#endif
|
||||
|
||||
class Thread {
|
||||
public:
|
||||
virtual ~Thread() = default;
|
||||
|
||||
void SetJoinable(bool) {}
|
||||
#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
|
||||
void Start() {
|
||||
handle_ = CreateThread(nullptr, 0, &Thread::InvokeThreadW, this, 0, &th_);
|
||||
CHECK(handle_) << "CreateThread";
|
||||
}
|
||||
void Join() { WaitForSingleObject(handle_, INFINITE); }
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
void Start() { pthread_create(&th_, nullptr, &Thread::InvokeThread, this); }
|
||||
void Join() { pthread_join(th_, nullptr); }
|
||||
#else
|
||||
void Start() {}
|
||||
void Join() {}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual void Run() = 0;
|
||||
|
||||
private:
|
||||
static void* InvokeThread(void* self) {
|
||||
(static_cast<Thread*>(self))->Run();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
|
||||
static DWORD __stdcall InvokeThreadW(LPVOID self) {
|
||||
InvokeThread(self);
|
||||
return 0;
|
||||
}
|
||||
HANDLE handle_;
|
||||
DWORD th_;
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
pthread_t th_;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline void SleepForMilliseconds(unsigned t) {
|
||||
#ifndef GLOG_OS_WINDOWS
|
||||
# if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
|
||||
const struct timespec req = {0, t * 1000 * 1000};
|
||||
nanosleep(&req, nullptr);
|
||||
# else
|
||||
usleep(t * 1000);
|
||||
# endif
|
||||
#else
|
||||
Sleep(t);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Add hook for operator new to ensure there are no memory allocation.
|
||||
|
||||
void (*g_new_hook)() = nullptr;
|
||||
|
||||
@ -39,6 +39,7 @@
|
||||
#include <mutex>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "base/commandlineflags.h" // to get the program name
|
||||
#include "base/googleinit.h"
|
||||
@ -1685,14 +1686,14 @@ void LogMessage::Init(const char* file, int line, LogSeverity severity,
|
||||
<< logmsgtime_.day() << ' ' << setw(2) << logmsgtime_.hour()
|
||||
<< ':' << setw(2) << logmsgtime_.min() << ':' << setw(2)
|
||||
<< logmsgtime_.sec() << "." << setw(6) << logmsgtime_.usec()
|
||||
<< ' ' << setfill(' ') << setw(5)
|
||||
<< static_cast<unsigned int>(GetTID()) << setfill('0') << ' '
|
||||
<< data_->basename_ << ':' << data_->line_ << "] ";
|
||||
<< ' ' << setfill(' ') << setw(5) << std::this_thread::get_id()
|
||||
<< setfill('0') << ' ' << data_->basename_ << ':' << data_->line_
|
||||
<< "] ";
|
||||
} else {
|
||||
custom_prefix_callback(
|
||||
stream(),
|
||||
LogMessageInfo(LogSeverityNames[severity], data_->basename_,
|
||||
data_->line_, GetTID(), logmsgtime_),
|
||||
data_->line_, std::this_thread::get_id(), logmsgtime_),
|
||||
custom_prefix_callback_data);
|
||||
stream() << " ";
|
||||
}
|
||||
@ -2124,7 +2125,8 @@ string LogSink::ToString(LogSeverity severity, const char* file, int line,
|
||||
<< ' ' << setw(2) << logmsgtime.hour() << ':' << setw(2)
|
||||
<< logmsgtime.min() << ':' << setw(2) << logmsgtime.sec() << '.'
|
||||
<< setw(6) << logmsgtime.usec() << ' ' << setfill(' ') << setw(5)
|
||||
<< GetTID() << setfill('0') << ' ' << file << ':' << line << "] ";
|
||||
<< std::this_thread::get_id() << setfill('0') << ' ' << file << ':'
|
||||
<< line << "] ";
|
||||
|
||||
// A call to `write' is enclosed in parenthneses to prevent possible macro
|
||||
// expansion. On Windows, `write' could be a macro defined for portability.
|
||||
|
||||
@ -44,6 +44,7 @@
|
||||
# include <sys/wait.h>
|
||||
#endif
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
@ -54,6 +55,7 @@
|
||||
#include <queue>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "base/commandlineflags.h"
|
||||
@ -1197,12 +1199,9 @@ static vector<string> global_messages;
|
||||
// helper for TestWaitingLogSink below.
|
||||
// Thread that does the logic of TestWaitingLogSink
|
||||
// It's free to use LOG() itself.
|
||||
class TestLogSinkWriter : public Thread {
|
||||
class TestLogSinkWriter {
|
||||
public:
|
||||
TestLogSinkWriter() {
|
||||
SetJoinable(true);
|
||||
Start();
|
||||
}
|
||||
TestLogSinkWriter() : t_{&TestLogSinkWriter::Run, this} {}
|
||||
|
||||
// Just buffer it (can't use LOG() here).
|
||||
void Buffer(const string& message) {
|
||||
@ -1215,11 +1214,12 @@ class TestLogSinkWriter : public Thread {
|
||||
|
||||
// Wait for the buffer to clear (can't use LOG() here).
|
||||
void Wait() {
|
||||
using namespace std::chrono_literals;
|
||||
RAW_LOG(INFO, "Waiting");
|
||||
mutex_.lock();
|
||||
while (!NoWork()) {
|
||||
mutex_.unlock();
|
||||
SleepForMilliseconds(1);
|
||||
std::this_thread::sleep_for(1ms);
|
||||
mutex_.lock();
|
||||
}
|
||||
RAW_LOG(INFO, "Waited");
|
||||
@ -1232,6 +1232,8 @@ class TestLogSinkWriter : public Thread {
|
||||
should_exit_ = true;
|
||||
}
|
||||
|
||||
void Join() { t_.join(); }
|
||||
|
||||
private:
|
||||
// helpers ---------------
|
||||
|
||||
@ -1240,12 +1242,13 @@ class TestLogSinkWriter : public Thread {
|
||||
bool HaveWork() { return !messages_.empty() || should_exit_; }
|
||||
|
||||
// Thread body; CAN use LOG() here!
|
||||
void Run() override {
|
||||
void Run() {
|
||||
using namespace std::chrono_literals;
|
||||
while (true) {
|
||||
mutex_.lock();
|
||||
while (!HaveWork()) {
|
||||
mutex_.unlock();
|
||||
SleepForMilliseconds(1);
|
||||
std::this_thread::sleep_for(1ms);
|
||||
mutex_.lock();
|
||||
}
|
||||
if (should_exit_ && messages_.empty()) {
|
||||
@ -1255,7 +1258,7 @@ class TestLogSinkWriter : public Thread {
|
||||
// Give the main thread time to log its message,
|
||||
// so that we get a reliable log capture to compare to golden file.
|
||||
// Same for the other sleep below.
|
||||
SleepForMilliseconds(20);
|
||||
std::this_thread::sleep_for(20ms);
|
||||
RAW_LOG(INFO, "Sink got a messages"); // only RAW_LOG under mutex_ here
|
||||
string message = messages_.front();
|
||||
messages_.pop();
|
||||
@ -1264,7 +1267,7 @@ class TestLogSinkWriter : public Thread {
|
||||
// e.g. pushing the message over with an RPC:
|
||||
size_t messages_left = messages_.size();
|
||||
mutex_.unlock();
|
||||
SleepForMilliseconds(20);
|
||||
std::this_thread::sleep_for(20ms);
|
||||
// May not use LOG while holding mutex_, because Buffer()
|
||||
// acquires mutex_, and Buffer is called from LOG(),
|
||||
// which has its own internal mutex:
|
||||
@ -1277,6 +1280,7 @@ class TestLogSinkWriter : public Thread {
|
||||
|
||||
// data ---------------
|
||||
|
||||
std::thread t_;
|
||||
std::mutex mutex_;
|
||||
bool should_exit_{false};
|
||||
queue<string> messages_; // messages to be logged
|
||||
@ -1288,7 +1292,7 @@ class TestLogSinkWriter : public Thread {
|
||||
class TestWaitingLogSink : public LogSink {
|
||||
public:
|
||||
TestWaitingLogSink() {
|
||||
tid_ = pthread_self(); // for thread-specific behavior
|
||||
tid_ = std::this_thread::get_id(); // for thread-specific behavior
|
||||
AddLogSink(this);
|
||||
}
|
||||
~TestWaitingLogSink() override {
|
||||
@ -1306,7 +1310,7 @@ class TestWaitingLogSink : public LogSink {
|
||||
// Push it to Writer thread if we are the original logging thread.
|
||||
// Note: Something like ThreadLocalLogSink is a better choice
|
||||
// to do thread-specific LogSink logic for real.
|
||||
if (pthread_equal(tid_, pthread_self())) {
|
||||
if (tid_ == std::this_thread::get_id()) {
|
||||
writer_.Buffer(ToString(severity, base_filename, line, logmsgtime,
|
||||
message, message_len));
|
||||
}
|
||||
@ -1314,11 +1318,11 @@ class TestWaitingLogSink : public LogSink {
|
||||
|
||||
void WaitTillSent() override {
|
||||
// Wait for Writer thread if we are the original logging thread.
|
||||
if (pthread_equal(tid_, pthread_self())) writer_.Wait();
|
||||
if (tid_ == std::this_thread::get_id()) writer_.Wait();
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_t tid_;
|
||||
std::thread::id tid_;
|
||||
TestLogSinkWriter writer_;
|
||||
};
|
||||
|
||||
@ -1329,15 +1333,16 @@ static void TestLogSinkWaitTillSent() {
|
||||
// reentered
|
||||
global_messages.clear();
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
TestWaitingLogSink sink;
|
||||
// Sleeps give the sink threads time to do all their work,
|
||||
// so that we get a reliable log capture to compare to the golden file.
|
||||
LOG(INFO) << "Message 1";
|
||||
SleepForMilliseconds(60);
|
||||
std::this_thread::sleep_for(60ms);
|
||||
LOG(ERROR) << "Message 2";
|
||||
SleepForMilliseconds(60);
|
||||
std::this_thread::sleep_for(60ms);
|
||||
LOG(WARNING) << "Message 3";
|
||||
SleepForMilliseconds(60);
|
||||
std::this_thread::sleep_for(60ms);
|
||||
}
|
||||
for (auto& global_message : global_messages) {
|
||||
LOG(INFO) << "Sink capture: " << global_message;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2006, Google Inc.
|
||||
// Copyright (c) 2024, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
@ -34,6 +34,10 @@
|
||||
#include <cerrno>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
#include <streambuf>
|
||||
#include <thread>
|
||||
|
||||
#include "utilities.h"
|
||||
#ifdef HAVE_UNISTD_H
|
||||
@ -124,6 +128,26 @@ static bool crashed = false;
|
||||
static CrashReason crash_reason;
|
||||
static char crash_buf[kLogBufSize + 1] = {0}; // Will end in '\0'
|
||||
|
||||
namespace {
|
||||
template <std::size_t N>
|
||||
class StaticStringBuf : public std::streambuf {
|
||||
public:
|
||||
StaticStringBuf() {
|
||||
setp(std::begin(data_), std::end(data_));
|
||||
setg(std::begin(data_), std::begin(data_), std::end(data_));
|
||||
}
|
||||
const char* data() noexcept {
|
||||
if (pptr() != pbase() && pptr() != epptr() && *(pptr() - 1) != '\0') {
|
||||
sputc('\0');
|
||||
}
|
||||
return data_;
|
||||
}
|
||||
|
||||
private:
|
||||
char data_[N];
|
||||
};
|
||||
} // namespace
|
||||
|
||||
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
|
||||
void RawLog__(LogSeverity severity, const char* file, int line,
|
||||
const char* format, ...) {
|
||||
@ -132,14 +156,24 @@ void RawLog__(LogSeverity severity, const char* file, int line,
|
||||
!IsGoogleLoggingInitialized())) {
|
||||
return; // this stderr log message is suppressed
|
||||
}
|
||||
|
||||
// We do not have any any option other that string streams to obtain the
|
||||
// thread identifier as the corresponding value is not convertible to an
|
||||
// integer. Use a statically allocated buffer to avoid dynamic memory
|
||||
// allocations.
|
||||
StaticStringBuf<kLogBufSize> sbuf;
|
||||
std::ostream oss(&sbuf);
|
||||
|
||||
oss << std::setw(5) << std::this_thread::get_id();
|
||||
|
||||
// can't call localtime_r here: it can allocate
|
||||
char buffer[kLogBufSize];
|
||||
char* buf = buffer;
|
||||
size_t size = sizeof(buffer);
|
||||
|
||||
// NOTE: this format should match the specification in base/logging.h
|
||||
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
|
||||
LogSeverityNames[severity][0], static_cast<unsigned int>(GetTID()),
|
||||
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %s %s:%d] RAW: ",
|
||||
LogSeverityNames[severity][0], sbuf.data(),
|
||||
const_basename(const_cast<char*>(file)), line);
|
||||
|
||||
// Record the position and size of the buffer after the prefix
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2023, Google Inc.
|
||||
// Copyright (c) 2024, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
@ -34,6 +34,8 @@
|
||||
#include <algorithm>
|
||||
#include <csignal>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "stacktrace.h"
|
||||
@ -205,14 +207,12 @@ void DumpSignalInfo(int signal_number, siginfo_t* siginfo) {
|
||||
formatter.AppendString(")");
|
||||
formatter.AppendString(" received by PID ");
|
||||
formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
|
||||
formatter.AppendString(" (TID 0x");
|
||||
// We assume pthread_t is an integral number or a pointer, rather
|
||||
// than a complex struct. In some environments, pthread_self()
|
||||
// returns an uint64 but in some other environments pthread_self()
|
||||
// returns a pointer.
|
||||
pthread_t id = pthread_self();
|
||||
formatter.AppendUint64(
|
||||
reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
|
||||
formatter.AppendString(" (TID ");
|
||||
|
||||
std::ostringstream oss;
|
||||
oss << std::showbase << std::hex << std::this_thread::get_id();
|
||||
formatter.AppendString(oss.str().c_str());
|
||||
|
||||
formatter.AppendString(") ");
|
||||
// Only linux has the PID of the signal sender in si_pid.
|
||||
# ifdef GLOG_OS_LINUX
|
||||
@ -270,7 +270,7 @@ void InvokeDefaultSignalHandler(int signal_number) {
|
||||
// dumping stuff while another thread is doing it. Our policy is to let
|
||||
// the first thread dump stuff and let other threads wait.
|
||||
// See also comments in FailureSignalHandler().
|
||||
static pthread_t* g_entered_thread_id_pointer = nullptr;
|
||||
static std::thread::id* g_entered_thread_id_pointer = nullptr;
|
||||
|
||||
// Dumps signal and stack frame information, and invokes the default
|
||||
// signal handler once our job is done.
|
||||
@ -285,21 +285,19 @@ void FailureSignalHandler(int signal_number, siginfo_t* signal_info,
|
||||
// compare and swap operation for platforms that support it. For other
|
||||
// platforms, we use a naive method that could lead to a subtle race.
|
||||
|
||||
// We assume pthread_self() is async signal safe, though it's not
|
||||
// officially guaranteed.
|
||||
pthread_t my_thread_id = pthread_self();
|
||||
// NOTE: We could simply use pthread_t rather than pthread_t* for this,
|
||||
// if pthread_self() is guaranteed to return non-zero value for thread
|
||||
// ids, but there is no such guarantee. We need to distinguish if the
|
||||
std::thread::id my_thread_id = std::this_thread::get_id();
|
||||
// NOTE: We could simply use std::thread::id rather than std::thread::id* for
|
||||
// this, if std::thread::get_id() is guaranteed to return non-zero value for
|
||||
// thread ids, but there is no such guarantee. We need to distinguish if the
|
||||
// old value (value returned from __sync_val_compare_and_swap) is
|
||||
// different from the original value (in this case nullptr).
|
||||
pthread_t* old_thread_id_pointer =
|
||||
std::thread::id* old_thread_id_pointer =
|
||||
glog_internal_namespace_::sync_val_compare_and_swap(
|
||||
&g_entered_thread_id_pointer, static_cast<pthread_t*>(nullptr),
|
||||
&g_entered_thread_id_pointer, static_cast<std::thread::id*>(nullptr),
|
||||
&my_thread_id);
|
||||
if (old_thread_id_pointer != nullptr) {
|
||||
// We've already entered the signal handler. What should we do?
|
||||
if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
|
||||
if (my_thread_id == *g_entered_thread_id_pointer) {
|
||||
// It looks the current thread is reentering the signal handler.
|
||||
// Something must be going wrong (maybe we are reentering by another
|
||||
// type of signal?). Kill ourself by the default signal handler.
|
||||
@ -308,7 +306,8 @@ void FailureSignalHandler(int signal_number, siginfo_t* signal_info,
|
||||
// Another thread is dumping stuff. Let's wait until that thread
|
||||
// finishes the job and kills the process.
|
||||
while (true) {
|
||||
sleep(1);
|
||||
using namespace std::chrono_literals;
|
||||
std::this_thread::sleep_for(1s);
|
||||
}
|
||||
}
|
||||
// This is the first time we enter the signal handler. We are going to
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2008, Google Inc.
|
||||
// Copyright (c) 2024, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
@ -32,17 +32,15 @@
|
||||
// This is a helper binary for testing signalhandler.cc. The actual test
|
||||
// is done in signalhandler_unittest.sh.
|
||||
|
||||
#include "utilities.h"
|
||||
|
||||
#if defined(HAVE_PTHREAD)
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "glog/logging.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#ifdef GLOG_USE_GFLAGS
|
||||
# include <gflags/gflags.h>
|
||||
@ -51,19 +49,13 @@ using namespace GFLAGS_NAMESPACE;
|
||||
|
||||
using namespace google;
|
||||
|
||||
static void* DieInThread(void*) {
|
||||
// We assume pthread_t is an integral number or a pointer, rather
|
||||
// than a complex struct. In some environments, pthread_self()
|
||||
// returns an uint64 but in some other environments pthread_self()
|
||||
// returns a pointer.
|
||||
fprintf(
|
||||
stderr, "0x%px is dying\n",
|
||||
static_cast<const void*>(reinterpret_cast<const char*>(pthread_self())));
|
||||
// Use volatile to prevent from these to be optimized away.
|
||||
volatile int a = 0;
|
||||
volatile int b = 1 / a;
|
||||
static void DieInThread(int* a) {
|
||||
std::ostringstream oss;
|
||||
oss << std::showbase << std::hex << std::this_thread::get_id();
|
||||
|
||||
fprintf(stderr, "%s is dying\n", oss.str().c_str());
|
||||
int b = 1 / *a;
|
||||
fprintf(stderr, "We should have died: b=%d\n", b);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void WriteToStdout(const char* data, size_t size) {
|
||||
@ -92,14 +84,8 @@ int main(int argc, char** argv) {
|
||||
while (true)
|
||||
;
|
||||
} else if (command == "die_in_thread") {
|
||||
# if defined(HAVE_PTHREAD)
|
||||
pthread_t thread;
|
||||
pthread_create(&thread, nullptr, &DieInThread, nullptr);
|
||||
pthread_join(thread, nullptr);
|
||||
# else
|
||||
fprintf(stderr, "no pthread\n");
|
||||
return 1;
|
||||
# endif
|
||||
std::thread t{&DieInThread, nullptr};
|
||||
t.join();
|
||||
} else if (command == "dump_to_stdout") {
|
||||
InstallFailureWriter(WriteToStdout);
|
||||
abort();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2008, Google Inc.
|
||||
// Copyright (c) 2023, Google Inc.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
@ -252,53 +252,6 @@ bool PidHasChanged() {
|
||||
return true;
|
||||
}
|
||||
|
||||
pid_t GetTID() {
|
||||
// On Linux and MacOSX, we try to use gettid().
|
||||
#if defined GLOG_OS_LINUX || defined GLOG_OS_MACOSX
|
||||
# ifndef __NR_gettid
|
||||
# ifdef GLOG_OS_MACOSX
|
||||
# define __NR_gettid SYS_gettid
|
||||
# elif !defined __i386__
|
||||
# error "Must define __NR_gettid for non-x86 platforms"
|
||||
# else
|
||||
# define __NR_gettid 224
|
||||
# endif
|
||||
# endif
|
||||
static bool lacks_gettid = false;
|
||||
if (!lacks_gettid) {
|
||||
# if (defined(GLOG_OS_MACOSX) && defined(HAVE_PTHREAD_THREADID_NP))
|
||||
uint64_t tid64;
|
||||
const int error = pthread_threadid_np(nullptr, &tid64);
|
||||
pid_t tid = error ? -1 : static_cast<pid_t>(tid64);
|
||||
# else
|
||||
auto tid = static_cast<pid_t>(syscall(__NR_gettid));
|
||||
# endif
|
||||
if (tid != -1) {
|
||||
return tid;
|
||||
}
|
||||
// Technically, this variable has to be volatile, but there is a small
|
||||
// performance penalty in accessing volatile variables and there should
|
||||
// not be any serious adverse effect if a thread does not immediately see
|
||||
// the value change to "true".
|
||||
lacks_gettid = true;
|
||||
}
|
||||
#endif // GLOG_OS_LINUX || GLOG_OS_MACOSX
|
||||
|
||||
// If gettid() could not be used, we use one of the following.
|
||||
#if defined GLOG_OS_LINUX
|
||||
return getpid(); // Linux: getpid returns thread ID when gettid is absent
|
||||
#elif defined GLOG_OS_WINDOWS && !defined GLOG_OS_CYGWIN
|
||||
return static_cast<pid_t>(GetCurrentThreadId());
|
||||
#elif defined GLOG_OS_OPENBSD
|
||||
return getthrid();
|
||||
#elif defined(HAVE_PTHREAD)
|
||||
// If none of the techniques above worked, we use pthread_self().
|
||||
return (pid_t)(uintptr_t)pthread_self();
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
const char* const_basename(const char* filepath) {
|
||||
const char* base = strrchr(filepath, '/');
|
||||
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
#define PRIoS __PRIS_PREFIX "o"
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include "glog/logging.h"
|
||||
|
||||
@ -171,8 +172,6 @@ WallTime WallTime_Now();
|
||||
int32 GetMainThreadPid();
|
||||
bool PidHasChanged();
|
||||
|
||||
pid_t GetTID();
|
||||
|
||||
const std::string& MyUserName();
|
||||
|
||||
// Get the part of filepath after the last path separator.
|
||||
|
||||
@ -107,9 +107,6 @@ enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
|
||||
# define hash hash_compare
|
||||
# endif
|
||||
|
||||
/* Sleep is in ms, on windows */
|
||||
# define sleep(secs) Sleep((secs)*1000)
|
||||
|
||||
/* Windows doesn't support specifying the number of buckets as a
|
||||
* hash_map constructor arg, so we leave this blank.
|
||||
*/
|
||||
@ -117,25 +114,8 @@ enum { STDIN_FILENO = 0, STDOUT_FILENO = 1, STDERR_FILENO = 2 };
|
||||
|
||||
# define DEFAULT_TEMPLATE_ROOTDIR ".."
|
||||
|
||||
// ----------------------------------- SYSTEM/PROCESS
|
||||
typedef int pid_t;
|
||||
# define getpid _getpid
|
||||
|
||||
# endif // _MSC_VER
|
||||
|
||||
// ----------------------------------- THREADS
|
||||
# if defined(HAVE_PTHREAD)
|
||||
# include <pthread.h>
|
||||
# else // no PTHREAD
|
||||
typedef DWORD pthread_t;
|
||||
typedef DWORD pthread_key_t;
|
||||
typedef LONG pthread_once_t;
|
||||
enum { PTHREAD_ONCE_INIT = 0 }; // important that this be 0! for SpinLock
|
||||
# define pthread_self GetCurrentThreadId
|
||||
# define pthread_equal(pthread_t_1, pthread_t_2) \
|
||||
((pthread_t_1) == (pthread_t_2))
|
||||
# endif // HAVE_PTHREAD
|
||||
|
||||
# ifndef HAVE_LOCALTIME_R
|
||||
extern GLOG_EXPORT std::tm* localtime_r(const std::time_t* timep,
|
||||
std::tm* result);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user