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

Fix the definition of sigevent on FreeBSD and Linux #3630

Merged
merged 1 commit into from
Nov 25, 2024
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
17 changes: 14 additions & 3 deletions libc-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2080,6 +2080,9 @@ fn test_android(target: &str) {
("Elf32_Phdr", "p_type") => true,
("Elf64_Phdr", "p_type") => true,

// _sigev_un is an anonymous union
("sigevent", "_sigev_un") => true,

// this is actually a union on linux, so we can't represent it well and
// just insert some padding.
("siginfo_t", "_pad") => true,
Expand Down Expand Up @@ -2671,7 +2674,7 @@ fn test_freebsd(target: &str) {
cfg.volatile_item(|i| {
use ctest::VolatileItemKind::*;
match i {
// aio_buf is a volatile void** but since we cannot express that in
// aio_buf is a volatile void* but since we cannot express that in
// Rust types, we have to explicitly tell the checker about it here:
StructField(ref n, ref f) if n == "aiocb" && f == "aio_buf" => true,
_ => false,
Expand All @@ -2691,6 +2694,9 @@ fn test_freebsd(target: &str) {
// not available until FreeBSD 12, and is an anonymous union there.
("xucred", "cr_pid__c_anonymous_union") => true,

// Anonymous union
("sigevent", "_sigev_un") => true,

// m_owner field is a volatile __lwpid_t
("umutex", "m_owner") => true,
// c_has_waiters field is a volatile int32_t
Expand Down Expand Up @@ -2883,6 +2889,9 @@ fn test_emscripten(target: &str) {
});

cfg.skip_struct(move |ty| {
if ty.starts_with("__c_anonymous_") {
return true;
}
match ty {
// This is actually a union, not a struct
"sigval" => true,
Expand Down Expand Up @@ -2968,6 +2977,8 @@ fn test_emscripten(target: &str) {
});

cfg.skip_field(move |struct_, field| {
// _sigev_un is an anonymous union
(struct_ == "sigevent" && field == "_sigev_un") ||
// this is actually a union on linux, so we can't represent it well and
// just insert some padding.
(struct_ == "siginfo_t" && field == "_pad") ||
Expand Down Expand Up @@ -4359,8 +4370,8 @@ fn test_linux(target: &str) {
(musl && struct_ == "glob_t" && field == "gl_flags") ||
// musl seems to define this as an *anonymous* bitfield
(musl && struct_ == "statvfs" && field == "__f_unused") ||
// sigev_notify_thread_id is actually part of a sigev_un union
(struct_ == "sigevent" && field == "sigev_notify_thread_id") ||
// _sigev_un is an anonymous union
(struct_ == "sigevent" && field == "_sigev_un") ||
// signalfd had SIGSYS fields added in Linux 4.18, but no libc release
// has them yet.
(struct_ == "signalfd_siginfo" && (field == "ssi_addr_lsb" ||
Expand Down
75 changes: 37 additions & 38 deletions src/unix/bsd/freebsdlike/freebsd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,20 +236,10 @@ impl ::Clone for devstat_select_mode {
}

s! {
pub struct aiocb {
pub aio_fildes: ::c_int,
pub aio_offset: ::off_t,
pub aio_buf: *mut ::c_void,
pub aio_nbytes: ::size_t,
__unused1: [::c_int; 2],
__unused2: *mut ::c_void,
pub aio_lio_opcode: ::c_int,
pub aio_reqprio: ::c_int,
// unused 3 through 5 are the __aiocb_private structure
__unused3: ::c_long,
__unused4: ::c_long,
__unused5: *mut ::c_void,
pub aio_sigevent: sigevent,
pub struct __c_anonymous_sigev_thread {
pub _function: Option<extern "C" fn(::sigval) -> *mut ::c_void>,
//pub _function: *mut ::c_void, // Actually a function pointer
pub _attribute: *mut ::pthread_attr_t,
}

pub struct jail {
Expand Down Expand Up @@ -1351,6 +1341,36 @@ s! {
}

s_no_extra_traits! {
#[cfg_attr(feature = "extra_traits", derive(Debug))]
pub struct __aiocb_private {
status: ::c_long,
error: ::c_long,
spare: *mut ::c_void,
}

#[cfg_attr(feature = "extra_traits", derive(Debug))]
pub struct aiocb {
pub aio_fildes: ::c_int,
pub aio_offset: ::off_t,
pub aio_buf: *mut ::c_void,
pub aio_nbytes: ::size_t,
__spare__: [::c_int; 2],
__spare2__: *mut ::c_void,
pub aio_lio_opcode: ::c_int,
pub aio_reqprio: ::c_int,
_aiocb_private: __aiocb_private,
pub aio_sigevent: sigevent,
}

// Can't correctly impl Debug for unions
#[allow(missing_debug_implementations)]
pub union __c_anonymous_sigev_un {
tgross35 marked this conversation as resolved.
Show resolved Hide resolved
pub _threadid: ::__lwpid_t,
pub _sigev_thread: __c_anonymous_sigev_thread,
pub _kevent_flags: ::c_ushort,
__spare__: [::c_long; 8],
}

pub struct utmpx {
pub ut_type: ::c_short,
pub ut_tv: ::timeval,
Expand Down Expand Up @@ -1398,12 +1418,7 @@ s_no_extra_traits! {
pub sigev_notify: ::c_int,
pub sigev_signo: ::c_int,
pub sigev_value: ::sigval,
//The rest of the structure is actually a union. We expose only
//sigev_notify_thread_id because it's the most useful union member.
pub sigev_notify_thread_id: ::lwpid_t,
#[cfg(target_pointer_width = "64")]
__unused1: ::c_int,
__unused2: [::c_long; 7],
pub _sigev_un: __c_anonymous_sigev_un,
}

pub struct ptsstat {
Expand Down Expand Up @@ -1819,33 +1834,17 @@ cfg_if! {
}
}

impl PartialEq for sigevent {
fn eq(&self, other: &sigevent) -> bool {
self.sigev_notify == other.sigev_notify
&& self.sigev_signo == other.sigev_signo
&& self.sigev_value == other.sigev_value
&& self.sigev_notify_thread_id == other.sigev_notify_thread_id
}
}
impl Eq for sigevent {}
impl ::fmt::Debug for sigevent {
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
f.debug_struct("sigevent")
.field("sigev_notify", &self.sigev_notify)
.field("sigev_signo", &self.sigev_signo)
.field("sigev_value", &self.sigev_value)
.field("sigev_notify_thread_id", &self.sigev_notify_thread_id)
// Skip _sigev_un, since we can't guarantee that it will be
// properly initialized.
.finish()
}
}
impl ::hash::Hash for sigevent {
fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
self.sigev_notify.hash(state);
self.sigev_signo.hash(state);
self.sigev_value.hash(state);
self.sigev_notify_thread_id.hash(state);
}
}

impl PartialEq for ptsstat {
fn eq(&self, other: &ptsstat) -> bool {
Expand Down
40 changes: 22 additions & 18 deletions src/unix/linux_like/linux/gnu/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,6 @@ cfg_if! {
}

s! {
pub struct aiocb {
pub aio_fildes: ::c_int,
pub aio_lio_opcode: ::c_int,
pub aio_reqprio: ::c_int,
pub aio_buf: *mut ::c_void,
pub aio_nbytes: ::size_t,
pub aio_sigevent: ::sigevent,
__next_prio: *mut aiocb,
__abs_prio: ::c_int,
__policy: ::c_int,
__error_code: ::c_int,
__return_value: ::ssize_t,
pub aio_offset: off_t,
#[cfg(all(not(target_arch = "x86_64"), target_pointer_width = "32"))]
__unused1: [::c_char; 4],
__glibc_reserved: [::c_char; 32],
}

pub struct __exit_status {
pub e_termination: ::c_short,
pub e_exit: ::c_short,
Expand Down Expand Up @@ -510,6 +492,28 @@ impl siginfo_t {
}
}

s_no_extra_traits! {
#[cfg_attr(feature = "extra_traits", derive(Debug))]
pub struct aiocb {
pub aio_fildes: ::c_int,
pub aio_lio_opcode: ::c_int,
pub aio_reqprio: ::c_int,
pub aio_buf: *mut ::c_void,
pub aio_nbytes: ::size_t,
pub aio_sigevent: ::sigevent,
__next_prio: *mut aiocb,
__abs_prio: ::c_int,
__policy: ::c_int,
__error_code: ::c_int,
__return_value: ::ssize_t,
// FIXME(off64): visible fields depend on __USE_FILE_OFFSET64
pub aio_offset: off_t,
asomers marked this conversation as resolved.
Show resolved Hide resolved
#[cfg(all(not(target_arch = "x86_64"), target_pointer_width = "32"))]
__pad: [::c_char; 4],
__glibc_reserved: [::c_char; 32],
}
}

// Internal, for casts to access union fields
#[repr(C)]
struct sifields_sigchld {
Expand Down
42 changes: 22 additions & 20 deletions src/unix/linux_like/linux/musl/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,26 +119,6 @@ impl siginfo_t {
}

s! {
pub struct aiocb {
pub aio_fildes: ::c_int,
pub aio_lio_opcode: ::c_int,
pub aio_reqprio: ::c_int,
pub aio_buf: *mut ::c_void,
pub aio_nbytes: ::size_t,
pub aio_sigevent: ::sigevent,
__td: *mut ::c_void,
__lock: [::c_int; 2],
__err: ::c_int,
__ret: ::ssize_t,
pub aio_offset: off_t,
__next: *mut ::c_void,
__prev: *mut ::c_void,
#[cfg(target_pointer_width = "32")]
__dummy4: [::c_char; 24],
#[cfg(target_pointer_width = "64")]
__dummy4: [::c_char; 16],
}

pub struct sigaction {
pub sa_sigaction: ::sighandler_t,
pub sa_mask: ::sigset_t,
Expand Down Expand Up @@ -496,6 +476,28 @@ s! {
}

s_no_extra_traits! {
#[cfg_attr(feature = "extra_traits", derive(Debug))]
pub struct aiocb {
pub aio_fildes: ::c_int,
pub aio_lio_opcode: ::c_int,
pub aio_reqprio: ::c_int,
pub aio_buf: *mut ::c_void,
pub aio_nbytes: ::size_t,
pub aio_sigevent: ::sigevent,
__td: *mut ::c_void,
__lock: [::c_int; 2],
__err: ::c_int,
__ret: ::ssize_t,
pub aio_offset: off_t,
__next: *mut ::c_void,
__prev: *mut ::c_void,
// FIXME(ctest): length should be `32 - 2 * core::mem::size_of::<*const ()>()`
#[cfg(target_pointer_width = "32")]
__dummy4: [::c_char; 24],
#[cfg(target_pointer_width = "64")]
__dummy4: [::c_char; 16],
asomers marked this conversation as resolved.
Show resolved Hide resolved
}

pub struct sysinfo {
pub uptime: ::c_ulong,
pub loads: [::c_ulong; 3],
Expand Down
51 changes: 26 additions & 25 deletions src/unix/linux_like/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ missing! {
}

s! {
pub struct __c_anonymous_sigev_thread {
pub _function: Option<extern "C" fn(::sigval) -> *mut ::c_void>,
pub _attribute: *mut ::pthread_attr_t,
}

pub struct in_addr {
pub s_addr: ::in_addr_t,
}
Expand Down Expand Up @@ -261,6 +266,14 @@ s_no_extra_traits! {
pub u64: u64,
}

// Can't correctly impl Debug for unions
#[allow(missing_debug_implementations)]
pub union __c_anonymous_sigev_un {
_pad: [::c_int; SIGEV_PAD_SIZE],
pub _tid: ::c_int,
pub _sigev_thread: __c_anonymous_sigev_thread,
}

pub struct sockaddr_un {
pub sun_family: sa_family_t,
pub sun_path: [::c_char; 108],
Expand Down Expand Up @@ -288,13 +301,7 @@ s_no_extra_traits! {
pub sigev_value: ::sigval,
pub sigev_signo: ::c_int,
pub sigev_notify: ::c_int,
// Actually a union. We only expose sigev_notify_thread_id because it's
// the most useful member
pub sigev_notify_thread_id: ::c_int,
#[cfg(target_pointer_width = "64")]
__unused1: [::c_int; 11],
#[cfg(target_pointer_width = "32")]
__unused1: [::c_int; 12],
pub _sigev_un: __c_anonymous_sigev_un,
}
}

Expand Down Expand Up @@ -441,33 +448,17 @@ cfg_if! {
}
}

impl PartialEq for sigevent {
fn eq(&self, other: &sigevent) -> bool {
self.sigev_value == other.sigev_value
&& self.sigev_signo == other.sigev_signo
&& self.sigev_notify == other.sigev_notify
&& self.sigev_notify_thread_id == other.sigev_notify_thread_id
}
}
impl Eq for sigevent {}
impl ::fmt::Debug for sigevent {
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
f.debug_struct("sigevent")
.field("sigev_value", &self.sigev_value)
.field("sigev_signo", &self.sigev_signo)
.field("sigev_notify", &self.sigev_notify)
.field("sigev_notify_thread_id", &self.sigev_notify_thread_id)
// Skip _sigev_un, since we can't guarantee that it will be
// properly initialized.
.finish()
}
}
impl ::hash::Hash for sigevent {
fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
self.sigev_value.hash(state);
self.sigev_signo.hash(state);
self.sigev_notify.hash(state);
self.sigev_notify_thread_id.hash(state);
}
}
}
}

Expand Down Expand Up @@ -582,6 +573,16 @@ pub const SIGPIPE: ::c_int = 13;
pub const SIGALRM: ::c_int = 14;
pub const SIGTERM: ::c_int = 15;

const SIGEV_MAX_SIZE: usize = 64;
cfg_if! {
if #[cfg(target_pointer_width = "64")] {
const __ARCH_SIGEV_PREAMBLE_SIZE: usize = 4 * 2 + 8;
} else {
const __ARCH_SIGEV_PREAMBLE_SIZE: usize = 4 * 2 + 4;
}
}
const SIGEV_PAD_SIZE: usize = (SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE) / 4;

pub const PROT_NONE: ::c_int = 0;
pub const PROT_READ: ::c_int = 1;
pub const PROT_WRITE: ::c_int = 2;
Expand Down