diff --git a/redox-rt/src/arch/x86_64.rs b/redox-rt/src/arch/x86_64.rs index b5e921f8cf..ef8a99c0c3 100644 --- a/redox-rt/src/arch/x86_64.rs +++ b/redox-rt/src/arch/x86_64.rs @@ -12,7 +12,7 @@ use syscall::{ use crate::{ proc::{fork_inner, FdGuard}, signal::{inner_c, tmp_disable_signals, RtSigarea, SigStack, PROC_CONTROL_STRUCT}, - Tcb, + RtTcb, Tcb, }; // Setup a stack starting from the very end of the address space, and then growing downwards. @@ -93,7 +93,11 @@ unsafe extern "sysv64" fn fork_impl(initial_rsp: *mut usize) -> usize { unsafe extern "sysv64" fn child_hook(cur_filetable_fd: usize, new_pid_fd: usize) { let _ = syscall::close(cur_filetable_fd); - let _ = syscall::close(new_pid_fd); + // TODO: Currently equivalent, but this will not be the case later. + RtTcb::current() + .thr_fd + .get() + .write(Some(FdGuard::new(new_pid_fd))); } asmfunction!(__relibc_internal_fork_wrapper -> usize: [" diff --git a/redox-rt/src/lib.rs b/redox-rt/src/lib.rs index addc576dcf..cb14dd398a 100644 --- a/redox-rt/src/lib.rs +++ b/redox-rt/src/lib.rs @@ -9,9 +9,12 @@ )] #![forbid(unreachable_patterns)] -use generic_rt::{ExpectTlsFree, GenericTcb}; +use core::cell::UnsafeCell; -use self::signal::RtSigarea; +use generic_rt::{ExpectTlsFree, GenericTcb}; +use syscall::{Sigcontrol, O_CLOEXEC}; + +use self::proc::FdGuard; extern crate alloc; @@ -46,11 +49,33 @@ pub mod sync; pub mod sys; pub mod thread; -pub type Tcb = GenericTcb; +#[derive(Debug, Default)] +pub struct RtTcb { + pub control: Sigcontrol, + pub arch: UnsafeCell, + pub thr_fd: UnsafeCell>, +} +impl RtTcb { + pub fn current() -> &'static Self { + unsafe { &Tcb::current().unwrap().os_specific } + } + pub fn thread_fd(&self) -> &FdGuard { + unsafe { + if (&*self.thr_fd.get()).is_none() { + self.thr_fd.get().write(Some(FdGuard::new( + syscall::open("thisproc:current/open_via_dup", O_CLOEXEC).unwrap(), + ))); + } + (&*self.thr_fd.get()).as_ref().unwrap() + } + } +} + +pub type Tcb = GenericTcb; /// OS and architecture specific code to activate TLS - Redox aarch64 #[cfg(target_arch = "aarch64")] -pub unsafe fn tcb_activate(tls_end: usize, tls_len: usize) { +pub unsafe fn tcb_activate(_tcb: &RtTcb, tls_end: usize, tls_len: usize) { // Uses ABI page let abi_ptr = tls_end - tls_len - 16; core::ptr::write(abi_ptr as *mut usize, tls_end); @@ -62,42 +87,36 @@ pub unsafe fn tcb_activate(tls_end: usize, tls_len: usize) { /// OS and architecture specific code to activate TLS - Redox x86 #[cfg(target_arch = "x86")] -pub unsafe fn tcb_activate(tls_end: usize, _tls_len: usize) { +pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end: usize, _tls_len: usize) { let mut env = syscall::EnvRegisters::default(); - let file = syscall::open( - "thisproc:current/regs/env", - syscall::O_CLOEXEC | syscall::O_RDWR, - ) - .expect_notls("failed to open handle for process registers"); + let file = FdGuard::new( + syscall::dup(**tcb.thread_fd(), b"regs/env") + .expect_notls("failed to open handle for process registers"), + ); - let _ = syscall::read(file, &mut env).expect_notls("failed to read gsbase"); + let _ = syscall::read(*file, &mut env).expect_notls("failed to read gsbase"); env.gsbase = tls_end as u32; - let _ = syscall::write(file, &env).expect_notls("failed to write gsbase"); - - let _ = syscall::close(file); + let _ = syscall::write(*file, &env).expect_notls("failed to write gsbase"); } /// OS and architecture specific code to activate TLS - Redox x86_64 #[cfg(target_arch = "x86_64")] -pub unsafe fn tcb_activate(tls_end_and_tcb_start: usize, _tls_len: usize) { +pub unsafe fn tcb_activate(tcb: &RtTcb, tls_end_and_tcb_start: usize, _tls_len: usize) { let mut env = syscall::EnvRegisters::default(); - let file = syscall::open( - "thisproc:current/regs/env", - syscall::O_CLOEXEC | syscall::O_RDWR, - ) - .expect_notls("failed to open handle for process registers"); + let file = FdGuard::new( + syscall::dup(**tcb.thread_fd(), b"regs/env") + .expect_notls("failed to open handle for process registers"), + ); - let _ = syscall::read(file, &mut env).expect_notls("failed to read fsbase"); + let _ = syscall::read(*file, &mut env).expect_notls("failed to read fsbase"); env.fsbase = tls_end_and_tcb_start as u64; - let _ = syscall::write(file, &env).expect_notls("failed to write fsbase"); - - let _ = syscall::close(file); + let _ = syscall::write(*file, &env).expect_notls("failed to write fsbase"); } /// Initialize redox-rt in situations where relibc is not used @@ -127,7 +146,8 @@ pub fn initialize_freestanding() { #[cfg(not(target_arch = "aarch64"))] unsafe { - tcb_activate(page as *mut Tcb as usize, 0) + let tcb_addr = page as *mut Tcb as usize; + tcb_activate(&page.os_specific, tcb_addr, 0) } #[cfg(target_arch = "aarch64")] unsafe { diff --git a/redox-rt/src/proc.rs b/redox-rt/src/proc.rs index ff8ce24360..c4aea31fd9 100644 --- a/redox-rt/src/proc.rs +++ b/redox-rt/src/proc.rs @@ -1,5 +1,6 @@ +use core::{fmt::Debug, mem::size_of}; + use crate::{arch::*, auxv_defs::*}; -use core::mem::size_of; use alloc::{boxed::Box, collections::BTreeMap, vec}; @@ -697,6 +698,11 @@ impl Drop for FdGuard { } } } +impl Debug for FdGuard { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "[fd {}]", self.fd) + } +} pub fn create_set_addr_space_buf( space: usize, ip: usize, @@ -714,7 +720,7 @@ pub fn create_set_addr_space_buf( /// descriptors from other schemes are reobtained with `dup`, and grants referencing such file /// descriptors are reobtained through `fmap`. Other mappings are kept but duplicated using CoW. pub fn fork_impl() -> Result { - let mut old_mask = crate::signal::get_sigmask()?; + let old_mask = crate::signal::get_sigmask()?; let pid = unsafe { Error::demux(__relibc_internal_fork_wrapper())? }; if pid == 0 { @@ -728,7 +734,7 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result { { let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?); - (new_pid_fd, new_pid) = new_context()?; + (new_pid_fd, new_pid) = new_child_process()?; copy_str(*cur_pid_fd, *new_pid_fd, "name")?; @@ -853,7 +859,7 @@ pub fn fork_inner(initial_rsp: *mut usize) -> Result { Ok(new_pid) } -pub fn new_context() -> Result<(FdGuard, usize)> { +pub fn new_child_process() -> Result<(FdGuard, usize)> { // Create a new context (fields such as uid/gid will be inherited from the current context). let fd = FdGuard::new(syscall::open("thisproc:new/open_via_dup", O_CLOEXEC)?); diff --git a/redox-rt/src/signal.rs b/redox-rt/src/signal.rs index 9e77763660..66bf23f1e9 100644 --- a/redox-rt/src/signal.rs +++ b/redox-rt/src/signal.rs @@ -11,7 +11,7 @@ use syscall::{ SIGWINCH, SIGXCPU, SIGXFSZ, }; -use crate::{arch::*, sync::Mutex, Tcb}; +use crate::{arch::*, proc::FdGuard, sync::Mutex, RtTcb, Tcb}; #[cfg(target_arch = "x86_64")] static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); @@ -450,9 +450,9 @@ const fn sig_bit(sig: usize) -> u64 { 1 << (sig - 1) } -pub fn setup_sighandler(area: &RtSigarea) { +pub fn setup_sighandler(tcb: &RtTcb) { { - let mut sigactions = SIGACTIONS_LOCK.lock(); + let _guard = SIGACTIONS_LOCK.lock(); for (sig_idx, action) in PROC_CONTROL_STRUCT.actions.iter().enumerate() { let sig = sig_idx + 1; let bits = if matches!(sig, SIGTSTP | SIGTTIN | SIGTTOU) { @@ -468,7 +468,7 @@ pub fn setup_sighandler(area: &RtSigarea) { ); } } - let arch = unsafe { &mut *area.arch.get() }; + let arch = unsafe { &mut *tcb.arch.get() }; { // The asm decides whether to use the altstack, based on whether the saved stack pointer // was already on that stack. Thus, setting the altstack to the entire address space, is @@ -489,22 +489,15 @@ pub fn setup_sighandler(area: &RtSigarea) { let data = current_setsighandler_struct(); - let fd = syscall::open( - "thisproc:current/sighandler", - syscall::O_WRONLY | syscall::O_CLOEXEC, - ) - .expect("failed to open thisproc:current/sighandler"); - syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler"); - let _ = syscall::close(fd); + let fd = FdGuard::new( + syscall::dup(**tcb.thread_fd(), b"sighandler").expect("failed to open sighandler fd"), + ); + let _ = syscall::write(*fd, &data).expect("failed to write to sighandler fd"); // TODO: Inherited set of ignored signals set_sigmask(Some(0), None); } -#[derive(Debug, Default)] -pub struct RtSigarea { - pub control: Sigcontrol, - pub arch: UnsafeCell, -} +pub type RtSigarea = RtTcb; // TODO pub fn current_setsighandler_struct() -> SetSighandlerData { SetSighandlerData { user_handler: sighandler_function(), diff --git a/redox-rt/src/sys.rs b/redox-rt/src/sys.rs index 6e8b1d823a..77750a6a2a 100644 --- a/redox-rt/src/sys.rs +++ b/redox-rt/src/sys.rs @@ -81,8 +81,7 @@ pub fn sys_waitpid(pid: usize, status: &mut usize, flags: usize) -> Result Result { - let cur_pid_fd = FdGuard::new(syscall::open("thisproc:current/open_via_dup", O_CLOEXEC)?); - let (new_pid_fd, new_pid) = new_context()?; +pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result { + let cur_thr_fd = RtTcb::current().thread_fd(); + let new_thr_fd = FdGuard::new(syscall::open( + "thisproc:new-thread/open_via_dup", + O_CLOEXEC, + )?); - copy_str(*cur_pid_fd, *new_pid_fd, "name")?; + copy_str(**cur_thr_fd, *new_thr_fd, "name")?; // Inherit existing address space { - let cur_addr_space_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"addrspace")?); - let new_addr_space_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-addrspace")?); + let cur_addr_space_fd = FdGuard::new(syscall::dup(**cur_thr_fd, b"addrspace")?); + let new_addr_space_sel_fd = FdGuard::new(syscall::dup(*new_thr_fd, b"current-addrspace")?); let buf = create_set_addr_space_buf( *cur_addr_space_fd, @@ -24,8 +27,8 @@ pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result { // Inherit reference to file table { - let cur_filetable_fd = FdGuard::new(syscall::dup(*cur_pid_fd, b"filetable")?); - let new_filetable_sel_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"current-filetable")?); + let cur_filetable_fd = FdGuard::new(syscall::dup(**cur_thr_fd, b"filetable")?); + let new_filetable_sel_fd = FdGuard::new(syscall::dup(*new_thr_fd, b"current-filetable")?); let _ = syscall::write( *new_filetable_sel_fd, @@ -39,8 +42,8 @@ pub unsafe fn rlct_clone_impl(stack: *mut usize) -> Result { // until it has initialized its own signal handler. // Unblock context. - let start_fd = FdGuard::new(syscall::dup(*new_pid_fd, b"start")?); + let start_fd = FdGuard::new(syscall::dup(*new_thr_fd, b"start")?); let _ = syscall::write(*start_fd, &[0])?; - Ok(new_pid) + Ok(new_thr_fd) } diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index efee9ce9ab..1e05657660 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -195,7 +195,7 @@ impl Tcb { /// Activate TLS pub unsafe fn activate(&mut self) { - Self::os_arch_activate(self.tls_end as usize, self.tls_len); + Self::os_arch_activate(&self.os_specific, self.tls_end as usize, self.tls_len); } /// Mapping with correct flags for TCB and TLS @@ -231,14 +231,14 @@ impl Tcb { /// OS and architecture specific code to activate TLS - Linux x86_64 #[cfg(all(target_os = "linux", target_arch = "x86_64"))] - unsafe fn os_arch_activate(tls_end: usize, _tls_len: usize) { + unsafe fn os_arch_activate(os: &(), tls_end: usize, _tls_len: usize) { const ARCH_SET_FS: usize = 0x1002; syscall!(ARCH_PRCTL, ARCH_SET_FS, tls_end); } #[cfg(target_os = "redox")] - unsafe fn os_arch_activate(tls_end: usize, tls_len: usize) { - redox_rt::tcb_activate(tls_end, tls_len) + unsafe fn os_arch_activate(os: &OsSpecific, tls_end: usize, tls_len: usize) { + redox_rt::tcb_activate(os, tls_end, tls_len) } } diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index 3986842193..81b0d3345b 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -1,4 +1,5 @@ use core::{convert::TryFrom, mem, ptr, slice, str}; +use redox_rt::RtTcb; use syscall::{ self, data::{Map, Stat as redox_stat, StatVfs as redox_statvfs, TimeSpec as redox_timespec}, @@ -792,21 +793,23 @@ impl Pal for Sys { let _guard = clone::rdlock(); let res = clone::rlct_clone_impl(stack); - res.map(|context_id| crate::pthread::OsTid { context_id }) - .map_err(|error| crate::pthread::Errno(error.errno)) + res.map(|mut fd| crate::pthread::OsTid { + thread_fd: fd.take(), + }) + .map_err(|error| crate::pthread::Errno(error.errno)) } unsafe fn rlct_kill( os_tid: crate::pthread::OsTid, signal: usize, ) -> Result<(), crate::pthread::Errno> { - syscall::kill(os_tid.context_id, signal) - .map_err(|error| crate::pthread::Errno(error.errno))?; + todo!(); + /*syscall::kill(os_tid.context_id, signal) + .map_err(|error| crate::pthread::Errno(error.errno))?;*/ Ok(()) } fn current_os_tid() -> crate::pthread::OsTid { - // TODO crate::pthread::OsTid { - context_id: Self::getpid() as _, + thread_fd: **RtTcb::current().thread_fd(), } } diff --git a/src/pthread/mod.rs b/src/pthread/mod.rs index cfc56dd485..32fb2b4394 100644 --- a/src/pthread/mod.rs +++ b/src/pthread/mod.rs @@ -2,7 +2,8 @@ use core::{ cell::{Cell, UnsafeCell}, - ptr::NonNull, + mem::MaybeUninit, + ptr::{addr_of, NonNull}, sync::atomic::{AtomicBool, AtomicUsize, Ordering}, }; @@ -67,13 +68,13 @@ pub struct Pthread { pub(crate) stack_base: *mut c_void, pub(crate) stack_size: usize, - pub(crate) os_tid: UnsafeCell, + pub os_tid: UnsafeCell, } #[derive(Clone, Copy, Debug, Default, Ord, Eq, PartialOrd, PartialEq)] pub struct OsTid { #[cfg(target_os = "redox")] - pub context_id: usize, + pub thread_fd: usize, #[cfg(target_os = "linux")] pub thread_id: usize, } @@ -147,6 +148,9 @@ pub(crate) unsafe fn create( let synchronization_mutex = Mutex::locked(current_sigmask); let synchronization_mutex = &synchronization_mutex; + let tid_mutex = Mutex::>::new(MaybeUninit::uninit()); + let mut tid_guard = tid_mutex.lock(); + let stack_size = attrs.stacksize.next_multiple_of(Sys::getpagesize()); let stack_base = if attrs.stack != 0 { @@ -208,7 +212,7 @@ pub(crate) unsafe fn create( } push(0); push(synchronization_mutex as *const _ as usize); - push(0); + push(addr_of!(tid_mutex) as usize); push(new_tcb as *mut _ as usize); push(arg as usize); @@ -222,6 +226,8 @@ pub(crate) unsafe fn create( }; core::mem::forget(stack_raii); + tid_guard.write(os_tid); + drop(tid_guard); let _ = synchronization_mutex.lock(); OS_TID_TO_PTHREAD @@ -235,10 +241,18 @@ unsafe extern "C" fn new_thread_shim( entry_point: unsafe extern "C" fn(*mut c_void) -> *mut c_void, arg: *mut c_void, tcb: *mut Tcb, - _pthread: *mut Pthread, - mutex: *const Mutex, + mutex1: *const Mutex>, + mutex2: *const Mutex, ) -> ! { - let procmask = (*mutex).as_ptr().read(); + let procmask = (&*mutex2).as_ptr().read(); + let tid = (*(&*mutex1).lock()).assume_init(); + + #[cfg(target_os = "redox")] + (*tcb) + .os_specific + .thr_fd + .get() + .write(Some(redox_rt::proc::FdGuard::new(tid.thread_fd))); if let Some(tcb) = tcb.as_mut() { tcb.copy_masters().unwrap(); @@ -247,7 +261,7 @@ unsafe extern "C" fn new_thread_shim( (*tcb).pthread.os_tid.get().write(Sys::current_os_tid()); - (&*mutex).manual_unlock(); + (&*mutex2).manual_unlock(); #[cfg(target_os = "redox")] {