[Threading] Signal handler / self-suspension improvements
This commit is contained in:
@@ -111,19 +111,25 @@ SignalType GetSystemSignalType(int num) {
|
|||||||
return static_cast<SignalType>(num - SIGRTMIN);
|
return static_cast<SignalType>(num - SIGRTMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_local std::array<bool, static_cast<size_t>(SignalType::k_Count)>
|
std::array<std::atomic<bool>, static_cast<size_t>(SignalType::k_Count)>
|
||||||
signal_handler_installed = {};
|
signal_handler_installed = {};
|
||||||
|
|
||||||
static void signal_handler(int signal, siginfo_t* info, void* context);
|
static void signal_handler(int signal, siginfo_t* info, void* context);
|
||||||
|
|
||||||
void install_signal_handler(SignalType type) {
|
void install_signal_handler(SignalType type) {
|
||||||
if (signal_handler_installed[static_cast<size_t>(type)]) return;
|
bool expected = false;
|
||||||
|
if (!signal_handler_installed[static_cast<size_t>(type)]
|
||||||
|
.compare_exchange_strong(expected, true)) {
|
||||||
|
return; // Already installed
|
||||||
|
}
|
||||||
struct sigaction action{};
|
struct sigaction action{};
|
||||||
action.sa_flags = SA_SIGINFO;
|
action.sa_flags = SA_SIGINFO | SA_RESTART;
|
||||||
action.sa_sigaction = signal_handler;
|
action.sa_sigaction = signal_handler;
|
||||||
sigemptyset(&action.sa_mask);
|
sigemptyset(&action.sa_mask);
|
||||||
if (sigaction(GetSystemSignal(type), &action, nullptr) == -1)
|
if (sigaction(GetSystemSignal(type), &action, nullptr) != 0) {
|
||||||
signal_handler_installed[static_cast<size_t>(type)] = true;
|
// Failed to install, reset the flag
|
||||||
|
signal_handler_installed[static_cast<size_t>(type)] = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(dougvj)
|
// TODO(dougvj)
|
||||||
@@ -705,7 +711,9 @@ class PosixCondition<Thread> final : public PosixConditionBase {
|
|||||||
std::unique_lock lock(state_mutex_);
|
std::unique_lock lock(state_mutex_);
|
||||||
// Check if thread has any suspend count (Windows allows resume even if
|
// Check if thread has any suspend count (Windows allows resume even if
|
||||||
// running)
|
// running)
|
||||||
if (suspend_count_ == 0) return false;
|
if (suspend_count_ == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (out_previous_suspend_count) {
|
if (out_previous_suspend_count) {
|
||||||
*out_previous_suspend_count = suspend_count_;
|
*out_previous_suspend_count = suspend_count_;
|
||||||
}
|
}
|
||||||
@@ -723,6 +731,10 @@ class PosixCondition<Thread> final : public PosixConditionBase {
|
|||||||
*out_previous_suspend_count = 0;
|
*out_previous_suspend_count = 0;
|
||||||
}
|
}
|
||||||
WaitStarted();
|
WaitStarted();
|
||||||
|
|
||||||
|
// Check if we're trying to suspend ourselves
|
||||||
|
bool is_current_thread = pthread_self() == thread_;
|
||||||
|
|
||||||
{
|
{
|
||||||
if (out_previous_suspend_count) {
|
if (out_previous_suspend_count) {
|
||||||
*out_previous_suspend_count = suspend_count_;
|
*out_previous_suspend_count = suspend_count_;
|
||||||
@@ -730,6 +742,15 @@ class PosixCondition<Thread> final : public PosixConditionBase {
|
|||||||
state_ = State::kSuspended;
|
state_ = State::kSuspended;
|
||||||
++suspend_count_;
|
++suspend_count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_current_thread) {
|
||||||
|
// Self-suspension: Instead of sending a signal, directly call
|
||||||
|
// WaitSuspended This avoids the signal handler complexity for the
|
||||||
|
// self-suspend case
|
||||||
|
WaitSuspended();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int result =
|
int result =
|
||||||
pthread_kill(thread_, GetSystemSignal(SignalType::kThreadSuspend));
|
pthread_kill(thread_, GetSystemSignal(SignalType::kThreadSuspend));
|
||||||
return result == 0;
|
return result == 0;
|
||||||
@@ -1191,10 +1212,14 @@ void set_name(const std::string_view name) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void signal_handler(int signal, siginfo_t* info, void* /*context*/) {
|
static void signal_handler(int signal, siginfo_t* info, void* context) {
|
||||||
switch (GetSystemSignalType(signal)) {
|
switch (GetSystemSignalType(signal)) {
|
||||||
case SignalType::kThreadSuspend: {
|
case SignalType::kThreadSuspend: {
|
||||||
assert_not_null(current_thread_);
|
if (!current_thread_) {
|
||||||
|
// current_thread_ is NULL - this can happen if the signal arrives
|
||||||
|
// before the thread has initialized or after it has exited
|
||||||
|
return;
|
||||||
|
}
|
||||||
current_thread_->WaitSuspended();
|
current_thread_->WaitSuspended();
|
||||||
} break;
|
} break;
|
||||||
case SignalType::kThreadUserCallback: {
|
case SignalType::kThreadUserCallback: {
|
||||||
|
|||||||
Reference in New Issue
Block a user