diff --git a/libc-test/build.rs b/libc-test/build.rs index 617d9e93686d7..6d494eadd2e45 100644 --- a/libc-test/build.rs +++ b/libc-test/build.rs @@ -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, @@ -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, @@ -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 @@ -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, @@ -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") || @@ -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" || diff --git a/src/unix/bsd/freebsdlike/freebsd/mod.rs b/src/unix/bsd/freebsdlike/freebsd/mod.rs index e2c315c1a22b7..302688063b617 100644 --- a/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -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 *mut ::c_void>, + //pub _function: *mut ::c_void, // Actually a function pointer + pub _attribute: *mut ::pthread_attr_t, } pub struct jail { @@ -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 { + 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, @@ -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 { @@ -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(&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 { diff --git a/src/unix/linux_like/linux/gnu/mod.rs b/src/unix/linux_like/linux/gnu/mod.rs index 74884cd25005b..8fc197880a5d9 100644 --- a/src/unix/linux_like/linux/gnu/mod.rs +++ b/src/unix/linux_like/linux/gnu/mod.rs @@ -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, @@ -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, + #[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 { diff --git a/src/unix/linux_like/linux/musl/mod.rs b/src/unix/linux_like/linux/musl/mod.rs index 176ab4009e40c..0708ba745c5ab 100644 --- a/src/unix/linux_like/linux/musl/mod.rs +++ b/src/unix/linux_like/linux/musl/mod.rs @@ -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, @@ -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], + } + pub struct sysinfo { pub uptime: ::c_ulong, pub loads: [::c_ulong; 3], diff --git a/src/unix/linux_like/mod.rs b/src/unix/linux_like/mod.rs index 4c2dfb4cee98d..9253f16c5a130 100644 --- a/src/unix/linux_like/mod.rs +++ b/src/unix/linux_like/mod.rs @@ -12,6 +12,11 @@ missing! { } s! { + pub struct __c_anonymous_sigev_thread { + pub _function: Option *mut ::c_void>, + pub _attribute: *mut ::pthread_attr_t, + } + pub struct in_addr { pub s_addr: ::in_addr_t, } @@ -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], @@ -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, } } @@ -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(&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); - } - } } } @@ -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;