From fe68287cb089cbe198d9b83fe7f1d0ed9006c4d9 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Sun, 28 Apr 2019 15:56:49 -0700 Subject: [PATCH] Make miscellaneous variables thread-safe --- src/common.cpp | 18 +++++------------- src/complete.cpp | 4 ++-- src/iothread.cpp | 40 +++++++++++++++++++--------------------- 3 files changed, 26 insertions(+), 36 deletions(-) diff --git a/src/common.cpp b/src/common.cpp index 77332bab1..2c7a3814c 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -94,7 +94,7 @@ int get_debug_stack_frames() { return debug_stack_frames; } /// Be able to restore the term's foreground process group. /// This is set during startup and not modified after. -static pid_t initial_fg_process_group = -1; +static relaxed_atomic_t initial_fg_process_group{-1}; /// This struct maintains the current state of the terminal size. It is updated on demand after /// receiving a SIGWINCH. Do not touch this struct directly, it's managed with a rwlock. Use @@ -2240,18 +2240,10 @@ bool is_forked_child() { } void setup_fork_guards() { - static bool already_initialized = false; - is_forked_proc = false; - if (already_initialized) { - // Just mark this process as main and exit - return; - } - - already_initialized = true; - pthread_atfork(nullptr, nullptr, []() { - is_forked_proc = true; - }); + static std::once_flag fork_guard_flag; + std::call_once(fork_guard_flag, + [] { pthread_atfork(nullptr, nullptr, [] { is_forked_proc = true; }); }); } void save_term_foreground_process_group() { @@ -2497,7 +2489,7 @@ std::string get_path_to_tmp_dir() { // session. We err on the side of assuming it's not a console session. This approach isn't // bullet-proof and that's OK. bool is_console_session() { - static bool console_session = []() { + static const bool console_session = []() { ASSERT_IS_MAIN_THREAD(); const char *tty_name = ttyname(0); diff --git a/src/complete.cpp b/src/complete.cpp index 95dffdc9d..51e9ac33e 100644 --- a/src/complete.cpp +++ b/src/complete.cpp @@ -1261,8 +1261,8 @@ bool completer_t::try_complete_user(const wcstring &str) { bool result = false; size_t name_len = str.length() - 1; - static std::mutex lock; - scoped_lock locker(lock); + static std::mutex s_setpwent_lock; + scoped_lock locker(s_setpwent_lock); setpwent(); // cppcheck-suppress getpwentCalled while (struct passwd *pw = getpwent()) { diff --git a/src/iothread.cpp b/src/iothread.cpp index 5bb6ad665..8034d3183 100644 --- a/src/iothread.cpp +++ b/src/iothread.cpp @@ -15,6 +15,7 @@ #include #include "common.h" +#include "global_safety.h" #include "iothread.h" #include "wutil.h" @@ -81,23 +82,22 @@ static std::condition_variable s_main_thread_performer_cond; // protects the ma /// stack-allocated on the requesting thread. static owning_lock> s_main_thread_request_queue; -// Notifying pipes. -static int s_read_pipe, s_write_pipe; +// Pipes used for notifying. +struct notify_pipes_t { + int read; + int write; +}; -static void iothread_init() { - static bool inited = false; - if (!inited) { - inited = true; - - // Initialize the completion pipes. +/// \return the (immortal) set of pipes used for notifying of completions. +static const notify_pipes_t &get_notify_pipes() { + static const notify_pipes_t s_notify_pipes = [] { int pipes[2] = {0, 0}; assert_with_errno(pipe(pipes) != -1); - s_read_pipe = pipes[0]; - s_write_pipe = pipes[1]; - - set_cloexec(s_read_pipe); - set_cloexec(s_write_pipe); - } + set_cloexec(pipes[0]); + set_cloexec(pipes[1]); + return notify_pipes_t{pipes[0], pipes[1]}; + }(); + return s_notify_pipes; } static bool dequeue_spawn_request(spawn_request_t *result) { @@ -132,7 +132,8 @@ static void *iothread_worker(void *unused) { // Enqueue the result, and tell the main thread about it. enqueue_thread_result(std::move(req)); const char wakeup_byte = IO_SERVICE_RESULT_QUEUE; - assert_with_errno(write_loop(s_write_pipe, &wakeup_byte, sizeof wakeup_byte) != -1); + int notify_fd = get_notify_pipes().write; + assert_with_errno(write_loop(notify_fd, &wakeup_byte, sizeof wakeup_byte) != -1); } } @@ -166,7 +167,6 @@ static void iothread_spawn() { int iothread_perform_impl(void_function_t &&func, void_function_t &&completion) { ASSERT_IS_MAIN_THREAD(); ASSERT_IS_NOT_FORKED_CHILD(); - iothread_init(); struct spawn_request_t req(std::move(func), std::move(completion)); int local_thread_count = -1; @@ -189,10 +189,7 @@ int iothread_perform_impl(void_function_t &&func, void_function_t &&completion) return local_thread_count; } -int iothread_port() { - iothread_init(); - return s_read_pipe; -} +int iothread_port() { return get_notify_pipes().read; } void iothread_service_completion() { ASSERT_IS_MAIN_THREAD(); @@ -316,7 +313,8 @@ void iothread_perform_on_main(void_function_t &&func) { // Tell the pipe. const char wakeup_byte = IO_SERVICE_MAIN_THREAD_REQUEST_QUEUE; - assert_with_errno(write_loop(s_write_pipe, &wakeup_byte, sizeof wakeup_byte) != -1); + int notify_fd = get_notify_pipes().write; + assert_with_errno(write_loop(notify_fd, &wakeup_byte, sizeof wakeup_byte) != -1); // Wait on the condition, until we're done. std::unique_lock perform_lock(s_main_thread_performer_lock);