topic_monitor_t::topic_monitor_t() { // Set up our pipes. Assert it succeeds. auto pipes = make_autoclose_pipes({}); assert(pipes.has_value() && "Failed to make pubsub pipes"); pipes_ = pipes.acquire(); // Make sure that our write side doesn't block, else we risk hanging in a signal handler. // The read end must block to avoid spinning in await. DIE_ON_FAILURE(make_fd_nonblocking(pipes_.write.fd())); #if TOPIC_MONITOR_TSAN_WORKAROUND DIE_ON_FAILURE(make_fd_nonblocking(pipes_.read.fd())); #endif }
void io_buffer_t::complete_background_fillthread() { ASSERT_IS_MAIN_THREAD(); assert(fillthread_ && "Should have a fillthread"); shutdown_fillthread_.store(true, std::memory_order_relaxed); void *ignored = nullptr; int err = pthread_join(*fillthread_, &ignored); DIE_ON_FAILURE(err); fillthread_.reset(); }
/// Spawn another thread. No lock is held when this is called. static void iothread_spawn() { // The spawned thread inherits our signal mask. We don't want the thread to ever receive signals // on the spawned thread, so temporarily block all signals, spawn the thread, and then restore // it. sigset_t new_set, saved_set; sigfillset(&new_set); DIE_ON_FAILURE(pthread_sigmask(SIG_BLOCK, &new_set, &saved_set)); // Spawn a thread. If this fails, it means there's already a bunch of threads; it is very // unlikely that they are all on the verge of exiting, so one is likely to be ready to handle // extant requests. So we can ignore failure with some confidence. pthread_t thread = 0; pthread_create(&thread, NULL, iothread_worker, NULL); // We will never join this thread. DIE_ON_FAILURE(pthread_detach(thread)); debug(5, "pthread %p spawned", (void *)(intptr_t)thread); // Restore our sigmask. DIE_ON_FAILURE(pthread_sigmask(SIG_SETMASK, &saved_set, NULL)); }