Skip to content

Commit 525eca9

Browse files
committed
Implement safe bindings around pthread_sigqueue, and test.
1 parent 227b45f commit 525eca9

File tree

2 files changed

+67
-1
lines changed

2 files changed

+67
-1
lines changed

src/sys/pthread.rs

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
//! Low level threading primitives
22
3+
use std::convert::From;
4+
5+
use libc::{self, pthread_t};
6+
37
#[cfg(not(target_os = "redox"))]
48
use crate::errno::Errno;
59
#[cfg(not(target_os = "redox"))]
610
use crate::Result;
7-
use libc::{self, pthread_t};
811

912
/// Identifies an individual thread.
1013
pub type Pthread = pthread_t;
@@ -39,4 +42,55 @@ pub fn pthread_kill<T>(thread: Pthread, signal: T) -> Result<()>
3942
let res = unsafe { libc::pthread_kill(thread, sig) };
4043
Errno::result(res).map(drop)
4144
}
45+
46+
/// Value to pass with a signal. Can be either integer or pointer.
47+
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
48+
pub enum SigVal {
49+
/// Use this variant to pass a integer to the sigval union
50+
Int(libc::c_int),
51+
/// Use this variant to pass a pointer to the sigval union
52+
Ptr(*mut libc::c_void),
53+
}
54+
55+
// Because of macro/trait machinery in libc, libc doesn't provide this union.
56+
// Only used to ensure that union type conversion is done exactly as C would.
57+
#[repr(C)]
58+
union sigval_union {
59+
ptr: *mut libc::c_void,
60+
int: libc::c_int,
61+
}
62+
63+
impl From<SigVal> for libc::sigval {
64+
fn from(sigval: SigVal) -> Self {
65+
match sigval {
66+
SigVal::Int(int) => {
67+
let as_ptr = unsafe { sigval_union { int }.ptr };
68+
libc::sigval { sival_ptr: as_ptr }
69+
}
70+
SigVal::Ptr(ptr) => {
71+
libc::sigval { sival_ptr: ptr }
72+
}
73+
}
74+
}
75+
}
76+
77+
/// Queue a signal and data to a thread (see [`pthread_sigqueue(3)`]).
78+
///
79+
/// If `signal` is `None`, `pthread_sigqueue` will only preform error checking and
80+
/// won't send any signal.
81+
///
82+
/// `pthread_sigqueue` is a GNU extension and is not available on other libcs
83+
///
84+
/// [`pthread_sigqueue(3)`]: https://man7.org/linux/man-pages/man3/pthread_sigqueue.3.html
85+
#[cfg(all(any(target_os = "linux", target_os = "android"), target_env = "gnu"))]
86+
pub fn pthread_sigqueue<T>(thread: Pthread, signal: T, sigval: SigVal) -> Result<()>
87+
where T: Into<Option<crate::sys::signal::Signal>>
88+
{
89+
let sig = match signal.into() {
90+
Some(s) => s as libc::c_int,
91+
None => 0,
92+
};
93+
let res = unsafe { libc::pthread_sigqueue(thread, sig, sigval.into()) };
94+
Errno::result(res).map(drop)
95+
}
4296
}

test/sys/test_pthread.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,15 @@ fn test_pthread_kill_none() {
2020
pthread_kill(pthread_self(), None)
2121
.expect("Should be able to send signal to my thread.");
2222
}
23+
24+
#[test]
25+
#[cfg(any(target_os = "linux", target_os = "android"))]
26+
fn test_pthread_sigqueue_none() {
27+
use std::ptr::null_mut;
28+
pthread_sigqueue(pthread_self(), None, SigVal::Int(0)).expect(
29+
"Should be able to send signal to my thread, with an integer sigval.",
30+
);
31+
pthread_sigqueue(pthread_self(), None, SigVal::Ptr(null_mut())).expect(
32+
"Should be able to send signal to my thread, with an ptr sigval.",
33+
);
34+
}

0 commit comments

Comments
 (0)