Skip to content

Commit f97e631

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

File tree

2 files changed

+204
-5
lines changed

2 files changed

+204
-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: 203 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,12 +1096,181 @@ 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+
// Linter false positive: this type actually _can't_ implement Copy.
1126+
// https://github.com/rust-lang/rust/issues/115014
1127+
#[allow(missing_copy_implementations)]
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+
#[repr(C)]
1138+
pub struct sigevent {
1139+
pub sigev_notify: libc::c_int,
1140+
pub sigev_signo: libc::c_int,
1141+
pub sigev_value: libc::sigval,
1142+
pub _sigev_un: __c_anonymous_sigev_un,
1143+
}
1144+
1145+
impl Clone for sigevent {
1146+
fn clone(&self) -> Self {
1147+
let mut sigevent = std::mem::MaybeUninit::<sigevent>::uninit();
1148+
// Safe because sigevent's lifetime outlives this block
1149+
unsafe {
1150+
(*sigevent.as_mut_ptr()).sigev_notify = self.sigev_notify;
1151+
(*sigevent.as_mut_ptr()).sigev_signo = self.sigev_signo;
1152+
(*sigevent.as_mut_ptr()).sigev_value = self.sigev_value;
1153+
match self.sigev_notify {
1154+
libc::SIGEV_KEVENT => {
1155+
(*sigevent.as_mut_ptr())._sigev_un._kevent_flags =
1156+
self._sigev_un._kevent_flags;
1157+
},
1158+
libc::SIGEV_THREAD_ID => {
1159+
(*sigevent.as_mut_ptr())._sigev_un._threadid =
1160+
self._sigev_un._threadid;
1161+
},
1162+
libc::SIGEV_THREAD => {
1163+
(*sigevent.as_mut_ptr())._sigev_un._sigev_thread =
1164+
self._sigev_un._sigev_thread;
1165+
},
1166+
libc::SIGEV_NONE | libc::SIGEV_SIGNAL => {
1167+
// The _sigev_un field is DON'T CARE
1168+
}
1169+
_ => {
1170+
// Maybe the OS returned a sigevent of a type that
1171+
// Nix doesn't know about. Or maybe the structure
1172+
// is just corrupt. In either case, we'll copy the
1173+
// entire union. This isn't UB, because we don't
1174+
// provide a way for the user to initialize such a
1175+
// sigevent, so the structure must've been returned
1176+
// by the kernel, which means it's fully
1177+
// initialized.
1178+
(*sigevent.as_mut_ptr())._sigev_un.__spare__ =
1179+
self._sigev_un.__spare__;
1180+
}
1181+
}
1182+
}
1183+
// Safe because we initialized every field.
1184+
unsafe {
1185+
sigevent.assume_init()
1186+
}
1187+
}
1188+
}
1189+
1190+
impl fmt::Debug for sigevent {
1191+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1192+
let mut ds = f.debug_struct("sigevent");
1193+
ds.field("sigev_notify", &self.sigev_notify)
1194+
.field("sigev_signo", &self.sigev_signo)
1195+
.field("sigev_value", &self.sigev_value);
1196+
// Safe because we check the sigev_notify discriminant
1197+
unsafe {
1198+
match self.sigev_notify {
1199+
libc::SIGEV_KEVENT => {
1200+
ds.field("sigev_notify_kevent_flags", &self._sigev_un._kevent_flags);
1201+
}
1202+
libc::SIGEV_THREAD_ID => {
1203+
ds.field("sigev_notify_thread_id", &self._sigev_un._threadid);
1204+
}
1205+
libc::SIGEV_THREAD => {
1206+
ds.field("sigev_notify_function", &self._sigev_un._sigev_thread._function);
1207+
ds.field("sigev_notify_attributes", &self._sigev_un._sigev_thread._attribute);
1208+
}
1209+
_ => ()
1210+
};
1211+
}
1212+
ds.finish()
1213+
}
1214+
}
1215+
1216+
impl PartialEq for sigevent {
1217+
fn eq(&self, other: &Self) -> bool {
1218+
let mut equals = self.sigev_notify == other.sigev_notify;
1219+
equals &= self.sigev_signo == other.sigev_signo;
1220+
equals &= self.sigev_value == other.sigev_value;
1221+
// Safe because we check the sigev_notify discriminant
1222+
unsafe {
1223+
match self.sigev_notify {
1224+
libc::SIGEV_KEVENT => {
1225+
equals &= self._sigev_un._kevent_flags == other._sigev_un._kevent_flags;
1226+
}
1227+
libc::SIGEV_THREAD_ID => {
1228+
equals &= self._sigev_un._threadid == other._sigev_un._threadid;
1229+
}
1230+
libc::SIGEV_THREAD => {
1231+
equals &= self._sigev_un._sigev_thread == other._sigev_un._sigev_thread;
1232+
}
1233+
_ => /* The union field is don't care */ ()
1234+
}
1235+
}
1236+
equals
1237+
}
1238+
}
1239+
1240+
impl Eq for sigevent {}
1241+
1242+
impl hash::Hash for sigevent {
1243+
fn hash<H: hash::Hasher>(&self, s: &mut H) {
1244+
self.sigev_notify.hash(s);
1245+
self.sigev_signo.hash(s);
1246+
self.sigev_value.hash(s);
1247+
// Safe because we check the sigev_notify discriminant
1248+
unsafe {
1249+
match self.sigev_notify {
1250+
libc::SIGEV_KEVENT => {
1251+
self._sigev_un._kevent_flags.hash(s);
1252+
}
1253+
libc::SIGEV_THREAD_ID => {
1254+
self._sigev_un._threadid.hash(s);
1255+
}
1256+
libc::SIGEV_THREAD => {
1257+
self._sigev_un._sigev_thread.hash(s);
1258+
}
1259+
_ => /* The union field is don't care */ ()
1260+
}
1261+
}
1262+
}
1263+
}
1264+
}
1265+
10991266
/// Used to request asynchronous notification of the completion of certain
11001267
/// events, such as POSIX AIO and timers.
11011268
#[repr(C)]
1102-
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1269+
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
1270+
// It can't be Copy on all platforms.
1271+
#[allow(missing_copy_implementations)]
11031272
pub struct SigEvent {
1104-
sigevent: libc::sigevent
1273+
sigevent: libc_sigevent
11051274
}
11061275

11071276
impl SigEvent {
@@ -1119,7 +1288,7 @@ mod sigevent {
11191288
/// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
11201289
/// more genuinely useful `sigev_notify_thread_id`
11211290
pub fn new(sigev_notify: SigevNotify) -> SigEvent {
1122-
let mut sev: libc::sigevent = unsafe { mem::zeroed() };
1291+
let mut sev: libc_sigevent = unsafe { mem::zeroed() };
11231292
match sigev_notify {
11241293
SigevNotify::SigevNone => {
11251294
sev.sigev_notify = libc::SIGEV_NONE;
@@ -1155,24 +1324,54 @@ mod sigevent {
11551324
sev.sigev_notify = libc::SIGEV_THREAD_ID;
11561325
sev.sigev_signo = signal as libc::c_int;
11571326
sev.sigev_value.sival_ptr = si_value as *mut libc::c_void;
1158-
sev._sigev_un._tid = thread_id;
1327+
sev.sigev_notify_thread_id = thread_id;
11591328
}
11601329
}
11611330
SigEvent{sigevent: sev}
11621331
}
11631332

11641333
/// Return a copy of the inner structure
1334+
#[cfg(target_os = "freebsd")]
1335+
pub fn sigevent(&self) -> libc::sigevent {
1336+
// Safe because they're really the same structure. See
1337+
// https://github.com/rust-lang/libc/pull/2813
1338+
unsafe {
1339+
mem::transmute::<libc_sigevent, libc::sigevent>(self.sigevent.clone())
1340+
}
1341+
}
1342+
1343+
/// Return a copy of the inner structure
1344+
#[cfg(not(target_os = "freebsd"))]
11651345
pub fn sigevent(&self) -> libc::sigevent {
11661346
self.sigevent
11671347
}
11681348

11691349
/// Returns a mutable pointer to the `sigevent` wrapped by `self`
1350+
#[cfg(target_os = "freebsd")]
1351+
pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
1352+
// Safe because they're really the same structure. See
1353+
// https://github.com/rust-lang/libc/pull/2813
1354+
&mut self.sigevent as *mut libc_sigevent as *mut libc::sigevent
1355+
}
1356+
1357+
/// Returns a mutable pointer to the `sigevent` wrapped by `self`
1358+
#[cfg(not(target_os = "freebsd"))]
11701359
pub fn as_mut_ptr(&mut self) -> *mut libc::sigevent {
11711360
&mut self.sigevent
11721361
}
11731362
}
11741363

11751364
impl<'a> From<&'a libc::sigevent> for SigEvent {
1365+
#[cfg(target_os = "freebsd")]
1366+
fn from(sigevent: &libc::sigevent) -> Self {
1367+
// Safe because they're really the same structure. See
1368+
// https://github.com/rust-lang/libc/pull/2813
1369+
let sigevent = unsafe {
1370+
mem::transmute::<libc::sigevent, libc_sigevent>(*sigevent)
1371+
};
1372+
SigEvent{ sigevent }
1373+
}
1374+
#[cfg(not(target_os = "freebsd"))]
11761375
fn from(sigevent: &libc::sigevent) -> Self {
11771376
SigEvent{ sigevent: *sigevent }
11781377
}

0 commit comments

Comments
 (0)