Skip to content

Commit aca9e32

Browse files
committed
Inline libc::sigevent
Because the PR to libc is stalled for over one year, with no sign of progress.
1 parent 656546b commit aca9e32

File tree

2 files changed

+160
-5
lines changed

2 files changed

+160
-5
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ targets = [
2727
]
2828

2929
[dependencies]
30-
libc = { git = "https://github.com/asomers/libc.git", rev = "d81b318adeae923142c0b5640417cd90509e02ca", features = [ "extra_traits" ] }
30+
libc = { version = "0.2.147", features = ["extra_traits"] }
3131
bitflags = "2.3.1"
3232
cfg-if = "1.0"
3333
pin-utils = { version = "0.1.0", optional = true }

src/sys/signal.rs

Lines changed: 159 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,12 +1096,137 @@ mod sigevent {
10961096
use std::mem;
10971097
use super::SigevNotify;
10981098

1099+
#[cfg(target_os = "freebsd")]
1100+
pub(crate) use ffi::sigevent as libc_sigevent;
1101+
#[cfg(not(target_os = "freebsd"))]
1102+
pub(crate) use libc::sigevent as libc_sigevent;
1103+
1104+
// For FreeBSD only, we define the C structure here. Because the structure
1105+
// defined in libc isn't correct. The real sigevent contains union fields,
1106+
// but libc could not represent those when sigevent was originally added, so
1107+
// instead libc simply defined the most useful field. Now that Rust can
1108+
// represent unions, there's a PR to libc to fix it. However, it's stuck
1109+
// forever due to backwards compatibility concerns. Even though there's a
1110+
// workaround, libc refuses to merge it. I think it's just too complicated
1111+
// for them to want to think about right now, because that project is
1112+
// short-staffed. So we define it here instead, so we won't have to wait on
1113+
// libc.
1114+
// https://github.com/rust-lang/libc/pull/2813
1115+
#[cfg(target_os = "freebsd")]
1116+
mod ffi {
1117+
use std::{fmt, hash};
1118+
1119+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1120+
#[repr(C)]
1121+
pub struct __c_anonymous_sigev_thread {
1122+
pub _function: *mut libc::c_void, // Actually a function pointer
1123+
pub _attribute: *mut libc::pthread_attr_t,
1124+
}
1125+
#[derive(Clone, Copy)]
1126+
// This will never be used on its own, and its parent has a Debug impl,
1127+
// so it doesn't need one.
1128+
#[allow(missing_debug_implementations)]
1129+
#[repr(C)]
1130+
pub union __c_anonymous_sigev_un {
1131+
pub _threadid: libc::__lwpid_t,
1132+
pub _sigev_thread: __c_anonymous_sigev_thread,
1133+
pub _kevent_flags: libc::c_ushort,
1134+
__spare__: [libc::c_long; 8],
1135+
}
1136+
1137+
#[derive(Clone, Copy)]
1138+
#[repr(C)]
1139+
pub struct sigevent {
1140+
pub sigev_notify: libc::c_int,
1141+
pub sigev_signo: libc::c_int,
1142+
pub sigev_value: libc::sigval,
1143+
pub _sigev_un: __c_anonymous_sigev_un,
1144+
}
1145+
1146+
impl fmt::Debug for sigevent {
1147+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1148+
let mut ds = f.debug_struct("sigevent");
1149+
ds.field("sigev_notify", &self.sigev_notify)
1150+
.field("sigev_signo", &self.sigev_signo)
1151+
.field("sigev_value", &self.sigev_value);
1152+
// Safe because we check the sigev_notify discriminant
1153+
unsafe {
1154+
match self.sigev_notify {
1155+
libc::SIGEV_KEVENT => {
1156+
ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags);
1157+
}
1158+
libc::SIGEV_THREAD_ID => {
1159+
ds.field("sigev_notify_thread_id", &self._sigev_un._threadid);
1160+
}
1161+
libc::SIGEV_THREAD => {
1162+
ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function);
1163+
ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute);
1164+
}
1165+
_ => ()
1166+
};
1167+
}
1168+
ds.finish()
1169+
}
1170+
}
1171+
1172+
impl PartialEq for sigevent {
1173+
fn eq(&self, other: &Self) -> bool {
1174+
let mut equals = self.sigev_notify == other.sigev_notify;
1175+
equals &= self.sigev_signo == other.sigev_signo;
1176+
equals &= self.sigev_value == other.sigev_value;
1177+
// Safe because we check the sigev_notify discriminant
1178+
unsafe {
1179+
match self.sigev_notify {
1180+
libc::SIGEV_KEVENT => {
1181+
equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags;
1182+
}
1183+
libc::SIGEV_THREAD_ID => {
1184+
equals &= self._sigev_un._threadid == other._sigev_un._threadid;
1185+
}
1186+
libc::SIGEV_THREAD => {
1187+
equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread;
1188+
}
1189+
_ => /* The union field is don't care */ ()
1190+
}
1191+
}
1192+
equals
1193+
}
1194+
}
1195+
1196+
impl Eq for sigevent {}
1197+
1198+
impl hash::Hash for sigevent {
1199+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1200+
self.sigev_notify.hash(s);
1201+
self.sigev_signo.hash(s);
1202+
self.sigev_value.hash(s);
1203+
// Safe because we check the sigev_notify discriminant
1204+
unsafe {
1205+
match self.sigev_notify {
1206+
libc::SIGEV_KEVENT => {
1207+
self._sigev_un._kevent_flags.hash(s);
1208+
}
1209+
libc::SIGEV_THREAD_ID => {
1210+
self._sigev_un._threadid.hash(s);
1211+
}
1212+
libc::SIGEV_THREAD => {
1213+
self._sigev_un._sigev_thread.hash(s);
1214+
}
1215+
_ => /* The union field is don't care */ ()
1216+
}
1217+
}
1218+
}
1219+
}
1220+
}
1221+
10991222
/// Used to request asynchronous notification of the completion of certain
11001223
/// events, such as POSIX AIO and timers.
11011224
#[repr(C)]
1102-
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1225+
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1226+
// It can't be Copy on all platforms.
1227+
#[allow(missing_copy_implementations)]
11031228
pub struct SigEvent {
1104-
sigevent: libc::sigevent
1229+
sigevent: libc_sigevent
11051230
}
11061231

11071232
impl SigEvent {
@@ -1119,7 +1244,7 @@ mod sigevent {
11191244
/// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
11201245
/// more genuinely useful `sigev_notify_thread_id`
11211246
pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1122-
let mut sev: libc::sigevent = unsafe { mem::zeroed() };
1247+
let mut sev: libc_sigevent = unsafe { mem::zeroed() };
11231248
match sigev_notify {
11241249
SigevNotify::SigevNone => {
11251250
sev.sigev_notify = libc::SIGEV_NONE;
@@ -1155,24 +1280,54 @@ mod sigevent {
11551280
sev.sigev_notify = libc::SIGEV_THREAD_ID;
11561281
sev.sigev_signo = signal as libc::c_int;
11571282
sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
1158-
sev._sigev_un._tid = thread_id;
1283+
sev.sigev_notify_thread_id = thread_id;
11591284
}
11601285
}
11611286
SigEvent{sigevent: sev}
11621287
}
11631288

11641289
/// Return a copy of the inner structure
1290+
#[cfg(target_os = "freebsd")]
1291+
pub fn sigevent(&self) -> libc::sigevent {
1292+
// Safe because they're really the same structure. See
1293+
// https://github.com/rust-lang/libc/pull/2813
1294+
unsafe {
1295+
mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent)
1296+
}
1297+
}
1298+
1299+
/// Return a copy of the inner structure
1300+
#[cfg(not(target_os = "freebsd"))]
11651301
pub fn sigevent(&self) -> libc::sigevent {
11661302
self.sigevent
11671303
}
11681304

11691305
/// Returns a mutable pointer to the `sigevent` wrapped by `self`
1306+
#[cfg(target_os = "freebsd")]
1307+
pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1308+
// Safe because they're really the same structure. See
1309+
// https://github.com/rust-lang/libc/pull/2813
1310+
&mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent
1311+
}
1312+
1313+
/// Returns a mutable pointer to the `sigevent` wrapped by `self`
1314+
#[cfg(not(target_os = "freebsd"))]
11701315
pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
11711316
&mut self.sigevent
11721317
}
11731318
}
11741319

11751320
impl<'a> From<&'a libc::sigevent> for SigEvent {
1321+
#[cfg(target_os = "freebsd")]
1322+
fn from(sigevent: &libc::sigevent) -> Self {
1323+
// Safe because they're really the same structure. See
1324+
// https://github.com/rust-lang/libc/pull/2813
1325+
let sigevent = unsafe {
1326+
mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent)
1327+
};
1328+
SigEvent{ sigevent }
1329+
}
1330+
#[cfg(not(target_os = "freebsd"))]
11761331
fn from(sigevent: &libc::sigevent) -> Self {
11771332
SigEvent{ sigevent: *sigevent }
11781333
}

0 commit comments

Comments
 (0)