Skip to content

Instantly share code, notes, and snippets.

@backes
Created June 10, 2021 10:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save backes/5f689f23a5655b4bb2641822931f365d to your computer and use it in GitHub Desktop.
Save backes/5f689f23a5655b4bb2641822931f365d to your computer and use it in GitHub Desktop.
Demonstration of pthread_rwlock_t hangs with signals on Mac
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
#include <atomic>
#include <cstdlib>
#include <vector>
void HandleProfilerSignal(int signal, siginfo_t*, void*) { /* nop */ }
struct sigaction old_signal_handler;
void InstallSignalHandler() {
struct sigaction sa;
sa.sa_sigaction = &HandleProfilerSignal;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
if (sigaction(SIGPROF, &sa, &old_signal_handler) != 0) abort();
}
static void RestoreSignalHandler() {
sigaction(SIGPROF, &old_signal_handler, nullptr);
}
static constexpr int kNumMutexes = 1024;
struct ThreadData {
pthread_rwlock_t *mutexes;
std::atomic<size_t>* remaining_samples;
};
void* MutexThread(void* arg) {
auto* data = static_cast<ThreadData*>(arg);
while (data->remaining_samples->load(std::memory_order_relaxed) > 0) {
for (int idx = 0; idx < kNumMutexes; ++idx) {
int result = pthread_rwlock_wrlock(&data->mutexes[idx]);
if (result != 0) abort();
result = pthread_rwlock_unlock(&data->mutexes[idx]);
if (result != 0) abort();
}
}
return nullptr;
}
int main() {
// 10us * 100000 = 1s
static constexpr int kMicrosSleepBetweenSamples = 10;
static constexpr size_t kNumSignals = 100000;
std::atomic<size_t> remaining_samples{kNumSignals};
pthread_rwlock_t mutexes[kNumMutexes];
for (auto& lock : mutexes) {
pthread_rwlock_init(&lock, nullptr);
}
printf("Installing signal handler.\n");
InstallSignalHandler();
ThreadData thread_data{mutexes, &remaining_samples};
printf("Starting threads.\n");
std::vector<pthread_t> threads(2);
for (auto& thread : threads) {
int result = pthread_create(&thread, nullptr, MutexThread, &thread_data);
if (result != 0) abort();
}
printf("Sending SIGPROFs...\n");
while (remaining_samples.fetch_sub(1, std::memory_order_relaxed) > 1) {
for (pthread_t tid : threads) {
pthread_kill(tid, SIGPROF);
}
usleep(kMicrosSleepBetweenSamples);
}
printf("Waiting for other threads...\n");
for (auto& thread : threads) pthread_join(thread, nullptr);
printf("Restoring signal handler.\n");
RestoreSignalHandler();
printf("Done.\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment