Move thread stuff out of common.rs (#9745)

is_main_thread() and co were previously ported to threads.rs, so remove the
duplicate code and move everything else related to threads there as well. No
need for common.rs to be as long as our old common.cpp!

I left #[deprecated] stubs in common.rs to help redirect anyone porting code
over that we can remove after the port has finished.

Additionally, the fork guards had previously been left as a todo!() item but I
ported that over. They're all called from the now-central threads::init()
function so there isn't a need to call each individual thread-management-fn
manually.

The decision was made a while back to try and embrace/use the native rust thread
functionality and utilities so the manual thread management code has been ripped
out and was replaced with code that marshals the native rust values instead. The
values won't line up with what the C++ code sees, but it never lined up anyway
since each was using a separate counter to keep track of the values.
This commit is contained in:
Mahmoud Al-Qudsi 2023-04-23 12:26:10 -05:00 committed by GitHub
parent 30ae715183
commit ff28f29e8f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 46 deletions

View File

@ -22,7 +22,6 @@ use cxx::{CxxWString, UniquePtr};
use libc::{EINTR, EIO, O_WRONLY, SIGTTOU, SIG_IGN, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO};
use num_traits::ToPrimitive;
use once_cell::sync::Lazy;
use std::cell::RefCell;
use std::env;
use std::ffi::{CString, OsString};
use std::mem::{self, ManuallyDrop};
@ -32,7 +31,7 @@ use std::os::unix::prelude::OsStringExt;
use std::path::PathBuf;
use std::rc::Rc;
use std::str::FromStr;
use std::sync::atomic::{AtomicI32, AtomicU32, AtomicU64, Ordering};
use std::sync::atomic::{AtomicI32, AtomicU32, Ordering};
use std::sync::Mutex;
use std::time;
use widestring_suffix::widestrs;
@ -1201,34 +1200,14 @@ pub fn should_suppress_stderr_for_tests() -> bool {
unsafe { !PROGRAM_NAME.is_empty() && *PROGRAM_NAME != TESTS_PROGRAM_NAME }
}
fn assert_is_main_thread() {
assert!(is_main_thread() || THREAD_ASSERTS_CFG_FOR_TESTING.load());
#[deprecated(note = "Use threads::assert_is_main_thread() instead")]
pub fn assert_is_main_thread() {
crate::threads::assert_is_main_thread()
}
fn assert_is_background_thread() {
assert!(!is_main_thread() || THREAD_ASSERTS_CFG_FOR_TESTING.load());
}
static THREAD_ASSERTS_CFG_FOR_TESTING: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
thread_local! {
static TL_TID: RefCell<u64> = RefCell::new(0);
}
static S_LAST_THREAD_ID: AtomicU64 = AtomicU64::new(0);
fn next_thread_id() -> u64 {
// Note 0 is an invalid thread id.
// Note fetch_add is a CAS which returns the value *before* the modification.
1 + S_LAST_THREAD_ID.fetch_add(1, Ordering::Relaxed)
}
fn thread_id() -> u64 {
TL_TID.with(|tid| {
if *tid.borrow() == 0 {
*tid.borrow_mut() = next_thread_id()
}
*tid.borrow()
})
#[deprecated(note = "Use threads::assert_is_background_thread() instead")]
pub fn assert_is_background_thread() {
crate::threads::assert_is_background_thread()
}
/// Format the specified size (in bytes, kilobytes, etc.) into the specified stringbuffer.
@ -1584,32 +1563,29 @@ pub fn timef() -> Timepoint {
}
}
#[deprecated(note = "Use threads::is_main_thread() instead")]
pub fn is_main_thread() -> bool {
crate::threads::is_main_thread()
}
/// Call the following function early in main to set the main thread. This is our replacement for
/// pthread_main_np().
#[deprecated(note = "This function is no longer called manually!")]
pub fn set_main_thread() {
// Just call thread_id() once to force increment of thread_id.
let tid = thread_id();
assert!(tid == 1, "main thread should have thread ID 1");
}
pub fn is_main_thread() -> bool {
thread_id() == 1
eprintln!("set_main_thread() is removed in favor of `main_thread_id()` and co. in threads.rs!")
}
#[deprecated(note = "Use threads::configure_thread_assertions_for_testing() instead")]
pub fn configure_thread_assertions_for_testing() {
THREAD_ASSERTS_CFG_FOR_TESTING.store(true)
crate::threads::configure_thread_assertions_for_testing();
}
/// This allows us to notice when we've forked.
static IS_FORKED_PROC: RelaxedAtomicBool = RelaxedAtomicBool::new(false);
pub fn setup_fork_guards() {
IS_FORKED_PROC.store(false);
todo!();
}
#[deprecated(note = "This should no longer be called manually")]
pub fn setup_fork_guards() {}
#[deprecated(note = "Use threads::is_forked_child() instead")]
pub fn is_forked_child() -> bool {
IS_FORKED_PROC.load()
crate::threads::is_forked_child()
}
/// Be able to restore the term's foreground process group.

View File

@ -2,6 +2,7 @@
//! ported directly from the cpp code so we can use rust threads instead of using pthreads.
use crate::flog::{FloggableDebug, FLOG};
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread::{self, ThreadId};
impl FloggableDebug for ThreadId {}
@ -16,6 +17,10 @@ impl FloggableDebug for ThreadId {}
/// The thread id of the main thread, as set by [`init()`] at startup.
static mut MAIN_THREAD_ID: Option<ThreadId> = None;
/// Used to bypass thread assertions when testing.
static THREAD_ASSERTS_CFG_FOR_TESTING: AtomicBool = AtomicBool::new(false);
/// This allows us to notice when we've forked.
static IS_FORKED_PROC: AtomicBool = AtomicBool::new(false);
/// Initialize some global static variables. Must be called at startup from the main thread.
pub fn init() {
@ -25,6 +30,14 @@ pub fn init() {
}
MAIN_THREAD_ID = Some(thread::current().id());
}
extern "C" fn child_post_fork() {
IS_FORKED_PROC.store(true, Ordering::Relaxed);
}
unsafe {
let result = libc::pthread_atfork(None, None, Some(child_post_fork));
assert_eq!(result, 0, "pthread_atfork() failure: {}", errno::errno());
}
}
#[inline(always)]
@ -40,6 +53,11 @@ fn main_thread_id() -> ThreadId {
}
}
#[inline(always)]
pub fn is_main_thread() -> bool {
thread::current().id() == main_thread_id()
}
#[inline(always)]
pub fn assert_is_main_thread() {
#[cold]
@ -47,7 +65,7 @@ pub fn assert_is_main_thread() {
panic!("Function is not running on the main thread!");
}
if thread::current().id() != main_thread_id() {
if !is_main_thread() && !THREAD_ASSERTS_CFG_FOR_TESTING.load(Ordering::Relaxed) {
not_main_thread();
}
}
@ -59,11 +77,19 @@ pub fn assert_is_background_thread() {
panic!("Function is not allowed to be called on the main thread!");
}
if thread::current().id() == main_thread_id() {
if is_main_thread() && !THREAD_ASSERTS_CFG_FOR_TESTING.load(Ordering::Relaxed) {
not_background_thread();
}
}
pub fn configure_thread_assertions_for_testing() {
THREAD_ASSERTS_CFG_FOR_TESTING.store(true, Ordering::Relaxed);
}
pub fn is_forked_child() -> bool {
IS_FORKED_PROC.load(Ordering::Relaxed)
}
/// The rusty version of `iothreads::make_detached_pthread()`. We will probably need a
/// `spawn_scoped` version of the same to handle some more advanced borrow cases safely, and maybe
/// an unsafe version that doesn't do any lifetime checking akin to