Skip to content

Commit 22ec7fc

Browse files
authored
Sync up the libc and linux_raw thread APIs. (#143)
* Sync up the libc and linux_raw thread APIs. Reorganize and document things in the libc and linux_raw thread APIs so that they're closer to each other. * Sync up the signal APIs too. * Minor cleanup: rename the naked macro to naked_fn.
1 parent 36fa513 commit 22ec7fc

File tree

10 files changed

+86
-67
lines changed

10 files changed

+86
-67
lines changed

src/arch/aarch64.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use {
1818
};
1919

2020
#[cfg(feature = "origin-start")]
21-
naked!(
21+
naked_fn!(
2222
"
2323
The program entry point.
2424
@@ -273,7 +273,7 @@ pub(super) unsafe fn munmap_and_exit_thread(map_addr: *mut c_void, map_len: usiz
273273
}
274274

275275
#[cfg(feature = "signal")]
276-
naked!(
276+
naked_fn!(
277277
"
278278
Invoke the `__NR_rt_sigreturn` system call to return control from a signal
279279
handler.

src/arch/arm.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use {
1818
};
1919

2020
#[cfg(feature = "origin-start")]
21-
naked!(
21+
naked_fn!(
2222
"
2323
The program entry point.
2424
@@ -287,7 +287,7 @@ pub(super) unsafe fn munmap_and_exit_thread(map_addr: *mut c_void, map_len: usiz
287287
}
288288

289289
#[cfg(feature = "signal")]
290-
naked!(
290+
naked_fn!(
291291
"
292292
Invoke the `__NR_rt_sigreturn` system call to return control from a signal
293293
handler.
@@ -312,7 +312,7 @@ fn test_rt_sigreturn() {
312312
}
313313

314314
#[cfg(feature = "signal")]
315-
naked!(
315+
naked_fn!(
316316
"
317317
Invoke the appropriate system call to return control from a signal
318318
handler that does not use `SA_SIGINFO`.

src/arch/riscv64.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use {
1616
};
1717

1818
#[cfg(feature = "origin-start")]
19-
naked!(
19+
naked_fn!(
2020
"
2121
The program entry point.
2222

src/arch/x86.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ use {
2424
};
2525

2626
#[cfg(feature = "origin-start")]
27-
naked!(
27+
naked_fn!(
2828
"
2929
The program entry point.
3030
@@ -377,7 +377,7 @@ pub(super) unsafe fn munmap_and_exit_thread(map_addr: *mut c_void, map_len: usiz
377377
}
378378

379379
#[cfg(feature = "signal")]
380-
naked!(
380+
naked_fn!(
381381
"
382382
Invoke the `__NR_rt_sigreturn` system call to return control from a signal
383383
handler.
@@ -403,7 +403,7 @@ fn test_rt_sigreturn() {
403403
}
404404

405405
#[cfg(feature = "signal")]
406-
naked!(
406+
naked_fn!(
407407
"
408408
Invoke the appropriate system call to return control from a signal
409409
handler that does not use `SA_SIGINFO`.

src/arch/x86_64.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use {
1919
};
2020

2121
#[cfg(feature = "origin-start")]
22-
naked!(
22+
naked_fn!(
2323
"
2424
The program entry point.
2525
@@ -282,7 +282,7 @@ pub(super) unsafe fn munmap_and_exit_thread(map_addr: *mut c_void, map_len: usiz
282282
}
283283

284284
#[cfg(feature = "signal")]
285-
naked!(
285+
naked_fn!(
286286
"
287287
Invoke the `__NR_rt_sigreturn` system call to return control from a signal
288288
handler.

src/naked.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! # Example
44
//!
55
//! ```no_compile
6-
//! naked!(
6+
//! naked_fn!(
77
//! "
88
//! A documentation comment.
99
//!
@@ -35,7 +35,7 @@
3535
/// `global_asm` otherwise. This macro supports a limited subset of the
3636
/// features of `#[naked]`.
3737
#[cfg(feature = "nightly")]
38-
macro_rules! naked {
38+
macro_rules! naked_fn {
3939
(
4040
$doc:literal;
4141
$vis:vis fn $name:ident $args:tt -> $ret:ty;
@@ -60,7 +60,7 @@ macro_rules! naked {
6060
/// `global_asm` otherwise. This macro supports a limited subset of the
6161
/// features of `#[naked]`.
6262
#[cfg(not(feature = "nightly"))]
63-
macro_rules! naked {
63+
macro_rules! naked_fn {
6464
(
6565
$doc:literal;
6666
$vis:vis fn $name:ident $args:tt -> $ret:ty;

src/signal/libc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub use linux_raw_sys::ctypes::c_int as Sigflags;
2424
///
2525
/// # Safety
2626
///
27-
/// yolo
27+
/// yolo. At least this function handles `sa_restorer` automatically though.
2828
pub unsafe fn sigaction(sig: Signal, action: Option<Sigaction>) -> io::Result<Sigaction> {
2929
let action: *const Sigaction = match action {
3030
Some(action) => &action,

src/signal/linux_raw.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pub unsafe fn sigaction(sig: Signal, action: Option<Sigaction>) -> io::Result<Si
4545

4646
/// Return a special “ignore” signal handler for ignoring signals.
4747
///
48-
/// If you're looking for `sig_dlf`; use [`SigDfl`].
48+
/// If you're looking for `sig_dfl`; use [`SigDfl`].
4949
#[doc(alias = "SIG_IGN")]
5050
#[must_use]
5151
pub const fn sig_ign() -> Sighandler {

src/thread/libc.rs

Lines changed: 65 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
//! Thread startup and shutdown.
2+
//!
3+
//! Why does this api look like `thread::join(t)` instead of `t.join()`? Either
4+
//! way could work, but free functions help emphasize that this API's
5+
//! [`Thread`] differs from `std::thread::Thread`. It does not detach or free
6+
//! its resources on drop, and does not guarantee validity. That gives users
7+
//! more control when creating efficient higher-level abstractions like
8+
//! pthreads or `std::thread::Thread`.
29
310
#[cfg(not(feature = "nightly"))]
411
use crate::ptr::{with_exposed_provenance_mut, without_provenance_mut, Polyfill as _};
@@ -48,6 +55,16 @@ impl Thread {
4855
Self(raw.expose_provenance() as libc::pthread_t)
4956
}
5057

58+
/// Convert to `Self` from a raw non-null pointer.
59+
///
60+
/// # Safety
61+
///
62+
/// `raw` must be a valid non-null thread pointer.
63+
#[inline]
64+
pub unsafe fn from_raw_unchecked(raw: *mut c_void) -> Self {
65+
Self::from_raw(raw)
66+
}
67+
5168
/// Convert to `Self` from a raw non-null pointer that was returned from
5269
/// `Thread::to_raw_non_null`.
5370
#[inline]
@@ -83,29 +100,33 @@ impl Thread {
83100
///
84101
/// # Safety
85102
///
86-
/// `fn_(arg)` on the new thread must have defined behavior, and the return
87-
/// value must be valid to use on the eventual joining thread.
103+
/// The values of `args` must be valid to send to the new thread, `fn_(args)`
104+
/// on the new thread must have defined behavior, and the return value must be
105+
/// valid to send to other threads.
88106
pub unsafe fn create(
89-
fn_: unsafe fn(&mut [*mut c_void]) -> Option<NonNull<c_void>>,
107+
fn_: unsafe fn(&mut [Option<NonNull<c_void>>]) -> Option<NonNull<c_void>>,
90108
args: &[Option<NonNull<c_void>>],
91109
stack_size: usize,
92110
guard_size: usize,
93111
) -> io::Result<Thread> {
94112
extern "C" fn start(thread_arg_ptr: *mut c_void) -> *mut c_void {
95113
unsafe {
96114
// Unpack the thread arguments.
97-
let num_args = thread_arg_ptr.cast::<*mut c_void>().read().addr();
98-
let thread_args =
99-
slice::from_raw_parts_mut(thread_arg_ptr.cast::<*mut c_void>(), num_args + 2);
100-
let fn_: unsafe fn(&mut [*mut c_void]) -> Option<NonNull<c_void>> =
115+
let thread_arg_ptr = thread_arg_ptr.cast::<Option<NonNull<c_void>>>();
116+
let num_args = match thread_arg_ptr.read() {
117+
Some(ptr) => ptr.as_ptr().addr(),
118+
None => 0,
119+
};
120+
let thread_args = slice::from_raw_parts_mut(thread_arg_ptr, num_args + 2);
121+
let fn_: unsafe fn(&mut [Option<NonNull<c_void>>]) -> Option<NonNull<c_void>> =
101122
transmute(thread_args[1]);
102123
let args = &mut thread_args[2..];
103124

104125
// Call the user's function.
105126
let return_value = fn_(args);
106127

107128
// Free the thread argument memory.
108-
libc::free(thread_arg_ptr);
129+
libc::free(thread_arg_ptr.cast::<c_void>());
109130

110131
// Return the return value.
111132
match return_value {
@@ -155,6 +176,40 @@ pub unsafe fn create(
155176
}
156177
}
157178

179+
/// Marks a thread as “detached”.
180+
///
181+
/// Detached threads free their own resources automatically when they
182+
/// exit, rather than when they are joined.
183+
///
184+
/// # Safety
185+
///
186+
/// `thread` must point to a valid thread record that has not yet been detached
187+
/// and will not be joined.
188+
#[inline]
189+
pub unsafe fn detach(thread: Thread) {
190+
let thread = thread.0;
191+
192+
assert_eq!(libc::pthread_detach(thread), 0);
193+
}
194+
195+
/// Waits for a thread to finish.
196+
///
197+
/// The return value is the value returned from the call to the `fn_` passed to
198+
/// `create_thread`.
199+
///
200+
/// # Safety
201+
///
202+
/// `thread` must point to a valid thread record that has not already been
203+
/// detached or joined.
204+
pub unsafe fn join(thread: Thread) -> Option<NonNull<c_void>> {
205+
let thread = thread.0;
206+
207+
let mut return_value: *mut c_void = null_mut();
208+
assert_eq!(libc::pthread_join(thread, &mut return_value), 0);
209+
210+
NonNull::new(return_value)
211+
}
212+
158213
/// Registers a function to call when the current thread exits.
159214
#[cfg(feature = "thread-at-exit")]
160215
pub fn at_exit(func: Box<dyn FnOnce()>) {
@@ -235,7 +290,8 @@ pub fn current_tls_addr(module: usize, offset: usize) -> *mut c_void {
235290
///
236291
/// `thread` must point to a valid thread record.
237292
#[inline]
238-
pub unsafe fn thread_stack(thread: Thread) -> (*mut c_void, usize, usize) {
293+
#[must_use]
294+
pub unsafe fn stack(thread: Thread) -> (*mut c_void, usize, usize) {
239295
let thread = thread.0;
240296

241297
let mut attr: libc::pthread_attr_t = zeroed();
@@ -254,40 +310,6 @@ pub unsafe fn thread_stack(thread: Thread) -> (*mut c_void, usize, usize) {
254310
(stack_addr, stack_size, guard_size)
255311
}
256312

257-
/// Marks a thread as “detached”.
258-
///
259-
/// Detached threads free their own resources automatically when they
260-
/// exit, rather than when they are joined.
261-
///
262-
/// # Safety
263-
///
264-
/// `thread` must point to a valid thread record that has not yet been detached
265-
/// and will not be joined.
266-
#[inline]
267-
pub unsafe fn detach(thread: Thread) {
268-
let thread = thread.0;
269-
270-
assert_eq!(libc::pthread_detach(thread), 0);
271-
}
272-
273-
/// Waits for a thread to finish.
274-
///
275-
/// The return value is the value returned from the call to the `fn_` passed to
276-
/// `create_thread`.
277-
///
278-
/// # Safety
279-
///
280-
/// `thread` must point to a valid thread record that has not already been
281-
/// detached or joined.
282-
pub unsafe fn join(thread: Thread) -> Option<NonNull<c_void>> {
283-
let thread = thread.0;
284-
285-
let mut return_value: *mut c_void = null_mut();
286-
assert_eq!(libc::pthread_join(thread, &mut return_value), 0);
287-
288-
NonNull::new(return_value)
289-
}
290-
291313
/// Return the default stack size for new threads.
292314
#[inline]
293315
#[must_use]

src/thread/linux_raw.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ use rustix::runtime::{exe_phdrs, set_tid_address};
3333
use rustix::runtime::{sigprocmask, How, Sigset};
3434
use rustix::thread::gettid;
3535

36+
pub use rustix::thread::Pid as ThreadId;
37+
3638
/// An opaque pointer to a thread.
3739
///
3840
/// This type does not detach or free resources on drop. It just leaks the
@@ -310,9 +312,6 @@ extern "C" {
310312
// Rust has `extern_weak` but it isn't stable, so use a `global_asm`.
311313
core::arch::global_asm!(".weak _DYNAMIC");
312314

313-
/// A numerical thread identifier.
314-
pub use rustix::thread::Pid as ThreadId;
315-
316315
/// Initialize the main thread.
317316
///
318317
/// This function is similar to `create_thread` except that the OS thread is
@@ -807,8 +806,8 @@ pub(crate) fn call_dtors(current: Thread) {
807806
///
808807
/// # Safety
809808
///
810-
/// `thread` must point to a valid thread record that has not yet been
811-
/// detached and will not be joined.
809+
/// `thread` must point to a valid thread record that has not yet been detached
810+
/// and will not be joined.
812811
#[inline]
813812
pub unsafe fn detach(thread: Thread) {
814813
#[cfg(feature = "log")]
@@ -1053,13 +1052,11 @@ pub fn current_tls_addr(module: usize, offset: usize) -> *mut c_void {
10531052

10541053
/// Return the id of a thread, or `None` if the thread has exited.
10551054
///
1056-
/// This is the same as [`rustix::thread::gettid`], but loads the value from a
1057-
/// field in the runtime rather than making a system call.
1058-
///
10591055
/// # Safety
10601056
///
10611057
/// `thread` must point to a valid thread record.
10621058
#[inline]
1059+
#[cfg_attr(docsrs, doc(cfg(feature = "take-charge")))]
10631060
pub unsafe fn id(thread: Thread) -> Option<ThreadId> {
10641061
let raw = thread.0.as_ref().thread_id.load(SeqCst);
10651062
ThreadId::from_raw(raw)

0 commit comments

Comments
 (0)