Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign create_thread to avoid dynamic allocation. #94

Merged
merged 1 commit into from
Nov 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions example-crates/basic/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,21 @@ fn main() {
eprintln!("Hello from a main-thread at_thread_exit handler")
}));

let thread = create_thread(
Box::new(|| {
eprintln!("Hello from child thread");
at_thread_exit(Box::new(|| {
eprintln!("Hello from child thread's at_thread_exit handler")
}));
None
}),
default_stack_size(),
default_guard_size(),
)
.unwrap();
let thread = unsafe {
create_thread(
|_args| {
eprintln!("Hello from child thread");
at_thread_exit(Box::new(|| {
eprintln!("Hello from child thread's at_thread_exit handler")
}));
None
},
&[],
default_stack_size(),
default_guard_size(),
)
.unwrap()
};

unsafe {
join_thread(thread);
Expand Down
5 changes: 3 additions & 2 deletions example-crates/external-start/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,14 @@ unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) ->
}));

let thread = create_thread(
Box::new(|| {
|_args| {
eprintln!("Hello from child thread");
at_thread_exit(Box::new(|| {
eprintln!("Hello from child thread's at_thread_exit handler")
}));
None
}),
},
&[],
default_stack_size(),
default_guard_size(),
)
Expand Down
27 changes: 15 additions & 12 deletions example-crates/no-std/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,21 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
eprintln!("Hello from a main-thread at_thread_exit handler")
}));

let thread = create_thread(
Box::new(|| {
eprintln!("Hello from child thread");
at_thread_exit(Box::new(|| {
eprintln!("Hello from child thread's at_thread_exit handler")
}));
None
}),
default_stack_size(),
default_guard_size(),
)
.unwrap();
let thread = unsafe {
create_thread(
|_args| {
eprintln!("Hello from child thread");
at_thread_exit(Box::new(|| {
eprintln!("Hello from child thread's at_thread_exit handler")
}));
None
},
&[],
default_stack_size(),
default_guard_size(),
)
.unwrap()
};

unsafe {
join_thread(thread);
Expand Down
5 changes: 3 additions & 2 deletions example-crates/origin-start-lto/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) ->
}));

let thread = create_thread(
Box::new(|| {
|_args| {
eprintln!("Hello from child thread");
at_thread_exit(Box::new(|| {
eprintln!("Hello from child thread's at_thread_exit handler")
}));
None
}),
},
&[],
default_stack_size(),
default_guard_size(),
)
Expand Down
5 changes: 3 additions & 2 deletions example-crates/origin-start/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,14 @@ unsafe fn origin_main(_argc: usize, _argv: *mut *mut u8, _envp: *mut *mut u8) ->
}));

let thread = create_thread(
Box::new(|| {
|_args| {
eprintln!("Hello from child thread");
at_thread_exit(Box::new(|| {
eprintln!("Hello from child thread's at_thread_exit handler")
}));
None
}),
},
&[],
default_stack_size(),
default_guard_size(),
)
Expand Down
12 changes: 9 additions & 3 deletions src/arch/aarch64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ use linux_raw_sys::general::__NR_rt_sigreturn;
use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
#[cfg(feature = "origin-thread")]
use {
alloc::boxed::Box,
core::any::Any,
core::ffi::c_void,
linux_raw_sys::general::{__NR_clone, __NR_exit, __NR_munmap},
rustix::thread::RawPid,
Expand Down Expand Up @@ -131,6 +129,10 @@ pub(super) unsafe fn relocation_mprotect_readonly(ptr: usize, len: usize) {
assert_eq!(r0, 0);
}

/// The required alignment for the stack pointer.
#[cfg(feature = "origin-thread")]
pub(super) const STACK_ALIGNMENT: usize = 16;

/// A wrapper around the Linux `clone` system call.
///
/// This can't be implemented in `rustix` because the child starts executing at
Expand All @@ -144,7 +146,8 @@ pub(super) unsafe fn clone(
parent_tid: *mut RawPid,
child_tid: *mut RawPid,
newtls: *mut c_void,
fn_: *mut Box<dyn FnOnce() -> Option<Box<dyn Any>> + Send>,
fn_: extern "C" fn(),
num_args: usize,
) -> isize {
let r0;
asm!(
Expand All @@ -153,6 +156,8 @@ pub(super) unsafe fn clone(

// Child thread.
"mov x0, {fn_}", // Pass `fn_` as the first argument.
"mov x1, sp", // Pass the args pointer as the second argument.
"mov x2, {num_args}", // Pass `num_args` as the third argument.
"mov x29, xzr", // Zero the frame address.
"mov x30, xzr", // Zero the return address.
"b {entry}", // Call `entry`.
Expand All @@ -162,6 +167,7 @@ pub(super) unsafe fn clone(

entry = sym super::thread::entry,
fn_ = in(reg) fn_,
num_args = in(reg) num_args,
in("x8") __NR_clone,
inlateout("x0") flags as usize => r0,
in("x1") child_stack,
Expand Down
12 changes: 9 additions & 3 deletions src/arch/arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
use linux_raw_sys::general::{__NR_rt_sigreturn, __NR_sigreturn};
#[cfg(feature = "origin-thread")]
use {
alloc::boxed::Box,
core::any::Any,
core::ffi::c_void,
linux_raw_sys::general::{__NR_clone, __NR_exit, __NR_munmap},
rustix::thread::RawPid,
Expand Down Expand Up @@ -131,6 +129,10 @@ pub(super) unsafe fn relocation_mprotect_readonly(ptr: usize, len: usize) {
assert_eq!(r0, 0);
}

/// The required alignment for the stack pointer.
#[cfg(feature = "origin-thread")]
pub(super) const STACK_ALIGNMENT: usize = 4;

/// A wrapper around the Linux `clone` system call.
///
/// This can't be implemented in `rustix` because the child starts executing at
Expand All @@ -144,7 +146,8 @@ pub(super) unsafe fn clone(
parent_tid: *mut RawPid,
child_tid: *mut RawPid,
newtls: *mut c_void,
fn_: *mut Box<dyn FnOnce() -> Option<Box<dyn Any>> + Send>,
fn_: extern "C" fn(),
num_args: usize,
) -> isize {
let r0;
asm!(
Expand All @@ -154,6 +157,8 @@ pub(super) unsafe fn clone(

// Child thread.
"mov r0, {fn_}", // Pass `fn_` as the first argument.
"mov r1, sp", // Pass the args pointer as the second argument.
"mov r2, {num_args}", // Pass `num_args` as the third argument.
"mov fp, #0", // Zero the frame address.
"mov lr, #0", // Zero the return address.
"b {entry}", // Call `entry`.
Expand All @@ -163,6 +168,7 @@ pub(super) unsafe fn clone(

entry = sym super::thread::entry,
fn_ = in(reg) fn_,
num_args = in(reg) num_args,
in("r7") __NR_clone,
inlateout("r0") flags as usize => r0,
in("r1") child_stack,
Expand Down
12 changes: 9 additions & 3 deletions src/arch/riscv64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ use core::arch::asm;
use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
#[cfg(feature = "origin-thread")]
use {
alloc::boxed::Box,
core::any::Any,
core::ffi::c_void,
linux_raw_sys::general::{__NR_clone, __NR_exit, __NR_munmap},
rustix::thread::RawPid,
Expand Down Expand Up @@ -131,6 +129,10 @@ pub(super) unsafe fn relocation_mprotect_readonly(ptr: usize, len: usize) {
assert_eq!(r0, 0);
}

/// The required alignment for the stack pointer.
#[cfg(feature = "origin-thread")]
pub(super) const STACK_ALIGNMENT: usize = 16;

/// A wrapper around the Linux `clone` system call.
///
/// This can't be implemented in `rustix` because the child starts executing at
Expand All @@ -144,7 +146,8 @@ pub(super) unsafe fn clone(
parent_tid: *mut RawPid,
child_tid: *mut RawPid,
newtls: *mut c_void,
fn_: *mut Box<dyn FnOnce() -> Option<Box<dyn Any>> + Send>,
fn_: extern "C" fn(),
num_args: usize,
) -> isize {
let r0;
asm!(
Expand All @@ -153,6 +156,8 @@ pub(super) unsafe fn clone(

// Child thread.
"mv a0, {fn_}", // Pass `fn_` as the first argument.
"mv a1, sp", // Pass the args pointer as the second argument.
"mv a2, {num_args}", // Pass `num_args` as the third argument.
"mv fp, zero", // Zero the frame address.
"mv ra, zero", // Zero the return address.
"tail {entry}", // Call `entry`.
Expand All @@ -162,6 +167,7 @@ pub(super) unsafe fn clone(

entry = sym super::thread::entry,
fn_ = in(reg) fn_,
num_args = in(reg) num_args,
in("a7") __NR_clone,
inlateout("a0") flags as usize => r0,
in("a1") child_stack,
Expand Down
28 changes: 19 additions & 9 deletions src/arch/x86.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
use linux_raw_sys::general::{__NR_rt_sigreturn, __NR_sigreturn};
#[cfg(feature = "origin-thread")]
use {
alloc::boxed::Box,
core::any::Any,
core::ffi::c_void,
core::ptr::invalid_mut,
linux_raw_sys::general::{__NR_clone, __NR_exit, __NR_munmap},
Expand Down Expand Up @@ -136,6 +134,10 @@ pub(super) unsafe fn relocation_mprotect_readonly(ptr: usize, len: usize) {
assert_eq!(r0, 0);
}

/// The required alignment for the stack pointer.
#[cfg(feature = "origin-thread")]
pub(super) const STACK_ALIGNMENT: usize = 16;

/// A wrapper around the Linux `clone` system call.
///
/// This can't be implemented in `rustix` because the child starts executing at
Expand All @@ -149,7 +151,8 @@ pub(super) unsafe fn clone(
parent_tid: *mut RawPid,
child_tid: *mut RawPid,
newtls: *mut c_void,
fn_: *mut Box<dyn FnOnce() -> Option<Box<dyn Any>> + Send>,
fn_: extern "C" fn(),
num_args: usize,
) -> isize {
let mut gs: u32 = 0;
asm!("mov {0:x}, gs", inout(reg) gs);
Expand All @@ -171,6 +174,11 @@ pub(super) unsafe fn clone(
user_desc.set_useable(1);
let newtls: *const _ = &user_desc;

// Push `fn_` to the child stack, since after all the `clone` args, and
// `num_args` in `ebp`, there are no more free registers.
let child_stack = child_stack.cast::<*mut c_void>().sub(1);
child_stack.write(fn_ as _);

// See the comments for x86's `syscall6` in `rustix`. Inline asm isn't
// allowed to name ebp or esi as operands, so we have to jump through
// extra hoops here.
Expand All @@ -179,7 +187,7 @@ pub(super) unsafe fn clone(
"push esi", // Save incoming register value.
"push ebp", // Save incoming register value.

// Pass `fn_` to the child in ebp.
// Pass `num_args` to the child in `ebp`.
"mov ebp, [eax+8]",

"mov esi, [eax+0]", // Pass `newtls` to the `int 0x80`.
Expand All @@ -193,10 +201,12 @@ pub(super) unsafe fn clone(
"jnz 0f",

// Child thread.
"push eax", // Pad for alignment.
"push eax", // Pad for alignment.
"push eax", // Pad for alignment.
"push ebp", // Pass `fn` as the first argument.
"pop edi", // Load `fn_` from the child stack.
"mov esi, esp", // Snapshot the args pointer.
"push eax", // Pad for stack pointer alignment.
"push ebp", // Pass `num_args` as the third argument.
"push esi", // Pass the args pointer as the second argument.
"push edi", // Pass `fn_` as the first argument.
"xor ebp, ebp", // Zero the frame address.
"push eax", // Zero the return address.
"jmp {entry}", // Call `entry`.
Expand All @@ -210,7 +220,7 @@ pub(super) unsafe fn clone(
inout("eax") &[
newtls.cast::<c_void>().cast_mut(),
invalid_mut(__NR_clone as usize),
fn_.cast::<c_void>()
invalid_mut(num_args)
] => r0,
in("ebx") flags,
in("ecx") child_stack,
Expand Down
14 changes: 10 additions & 4 deletions src/arch/x86_64.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ use linux_raw_sys::general::__NR_rt_sigreturn;
use linux_raw_sys::general::{__NR_mprotect, PROT_READ};
#[cfg(feature = "origin-thread")]
use {
alloc::boxed::Box,
core::any::Any,
linux_raw_sys::general::{__NR_clone, __NR_exit, __NR_munmap},
rustix::thread::RawPid,
};
Expand Down Expand Up @@ -134,6 +132,10 @@ pub(super) unsafe fn relocation_mprotect_readonly(ptr: usize, len: usize) {
assert_eq!(r0, 0);
}

/// The required alignment for the stack pointer.
#[cfg(feature = "origin-thread")]
pub(super) const STACK_ALIGNMENT: usize = 16;

/// A wrapper around the Linux `clone` system call.
///
/// This can't be implemented in `rustix` because the child starts executing at
Expand All @@ -147,7 +149,8 @@ pub(super) unsafe fn clone(
parent_tid: *mut RawPid,
child_tid: *mut RawPid,
newtls: *mut c_void,
fn_: *mut Box<dyn FnOnce() -> Option<Box<dyn Any>> + Send>,
fn_: extern "C" fn(),
num_args: usize,
) -> isize {
let r0;
asm!(
Expand All @@ -156,8 +159,10 @@ pub(super) unsafe fn clone(
"jnz 0f",

// Child thread.
"xor ebp, ebp", // Zero the frame address.
"mov rdi, r9", // Pass `fn_` as the first argument.
"mov rsi, rsp", // Pass the args pointer as the second argument.
"mov rdx, r12", // Pass `num_args` as the third argument.
"xor ebp, ebp", // Zero the frame address.
"push rax", // Zero the return address.
"jmp {entry}", // Call `entry`.

Expand All @@ -172,6 +177,7 @@ pub(super) unsafe fn clone(
in("r10") child_tid,
in("r8") newtls,
in("r9") fn_,
in("r12") num_args,
lateout("rcx") _,
lateout("r11") _,
options(nostack)
Expand Down
Loading