@@ -1022,7 +1022,7 @@ feature! {
10221022 #[ cfg( target_os = "freebsd" ) ]
10231023pub type type_of_thread_id = libc:: lwpid_t;
10241024/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1025- #[ cfg( target_os = "linux" ) ]
1025+ #[ cfg( any ( target_env = "gnu" , target_env = "uclibc" ) ) ]
10261026pub type type_of_thread_id = libc:: pid_t;
10271027
10281028/// Specifies the notification method used by a [`SigEvent`]
@@ -1042,8 +1042,7 @@ pub enum SigevNotify {
10421042 /// structure of the queued signal.
10431043 si_value: libc:: intptr_t
10441044 } ,
1045- // Note: SIGEV_THREAD is not implemented because libc::sigevent does not
1046- // expose a way to set the union members needed by SIGEV_THREAD.
1045+ // Note: SIGEV_THREAD is not implemented, but could be if desired.
10471046 /// Notify by delivering an event to a kqueue.
10481047 #[ cfg( any( target_os = "dragonfly" , target_os = "freebsd" ) ) ]
10491048 #[ cfg_attr( docsrs, doc( cfg( all( ) ) ) ) ]
@@ -1053,8 +1052,24 @@ pub enum SigevNotify {
10531052 /// Will be contained in the kevent's `udata` field.
10541053 udata: libc:: intptr_t
10551054 } ,
1055+ /// Notify by delivering an event to a kqueue, with optional event flags set
1056+ #[ cfg( target_os = "freebsd" ) ]
1057+ #[ cfg_attr( docsrs, doc( cfg( all( ) ) ) ) ]
1058+ #[ cfg( feature = "event" ) ]
1059+ SigevKeventFlags {
1060+ /// File descriptor of the kqueue to notify.
1061+ kq: RawFd ,
1062+ /// Will be contained in the kevent's `udata` field.
1063+ udata: libc:: intptr_t,
1064+ /// Flags that will be set on the delivered event. See `kevent(2)`.
1065+ flags: crate :: sys:: event:: EventFlag
1066+ } ,
10561067 /// Notify by delivering a signal to a thread.
1057- #[ cfg( any( target_os = "freebsd" , target_os = "linux" ) ) ]
1068+ #[ cfg( any(
1069+ target_os = "freebsd" ,
1070+ target_env = "gnu" ,
1071+ target_env = "uclibc" ,
1072+ ) ) ]
10581073 #[ cfg_attr( docsrs, doc( cfg( all( ) ) ) ) ]
10591074 SigevThreadId {
10601075 /// Signal to send
@@ -1079,17 +1094,139 @@ mod sigevent {
10791094 #![ any( feature = "aio" , feature = "signal" ) ]
10801095
10811096 use std:: mem;
1082- use std:: ptr;
10831097 use super :: SigevNotify ;
1084- #[ cfg( any( target_os = "freebsd" , target_os = "linux" ) ) ]
1085- use super :: type_of_thread_id;
1098+
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+ }
10861221
10871222 /// Used to request asynchronous notification of the completion of certain
10881223 /// events, such as POSIX AIO and timers.
10891224 #[ repr( C ) ]
1090- #[ 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) ]
10911228 pub struct SigEvent {
1092- sigevent: libc :: sigevent
1229+ sigevent: libc_sigevent
10931230 }
10941231
10951232 impl SigEvent {
@@ -1107,65 +1244,90 @@ mod sigevent {
11071244 /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
11081245 /// more genuinely useful `sigev_notify_thread_id`
11091246 pub fn new( sigev_notify: SigevNotify ) -> SigEvent {
1110- let mut sev = unsafe { mem:: MaybeUninit :: <libc:: sigevent>:: zeroed( ) . assume_init( ) } ;
1111- sev. sigev_notify = match sigev_notify {
1112- SigevNotify :: SigevNone => libc:: SIGEV_NONE ,
1113- SigevNotify :: SigevSignal { ..} => libc:: SIGEV_SIGNAL ,
1247+ let mut sev: libc_sigevent = unsafe { mem:: zeroed( ) } ;
1248+ match sigev_notify {
1249+ SigevNotify :: SigevNone => {
1250+ sev. sigev_notify = libc:: SIGEV_NONE ;
1251+ } ,
1252+ SigevNotify :: SigevSignal { signal, si_value} => {
1253+ sev. sigev_notify = libc:: SIGEV_SIGNAL ;
1254+ sev. sigev_signo = signal as libc:: c_int;
1255+ sev. sigev_value. sival_ptr = si_value as * mut libc:: c_void
1256+ } ,
11141257 #[ cfg( any( target_os = "dragonfly" , target_os = "freebsd" ) ) ]
1115- SigevNotify :: SigevKevent { ..} => libc:: SIGEV_KEVENT ,
1258+ SigevNotify :: SigevKevent { kq, udata} => {
1259+ sev. sigev_notify = libc:: SIGEV_KEVENT ;
1260+ sev. sigev_signo = kq;
1261+ sev. sigev_value. sival_ptr = udata as * mut libc:: c_void;
1262+ } ,
11161263 #[ cfg( target_os = "freebsd" ) ]
1117- SigevNotify :: SigevThreadId { ..} => libc:: SIGEV_THREAD_ID ,
1118- #[ cfg( all( target_os = "linux" , target_env = "gnu" , not( target_arch = "mips" ) ) ) ]
1119- SigevNotify :: SigevThreadId { ..} => libc:: SIGEV_THREAD_ID ,
1120- #[ cfg( all( target_os = "linux" , target_env = "uclibc" , not( target_arch = "mips" ) ) ) ]
1121- SigevNotify :: SigevThreadId { ..} => libc:: SIGEV_THREAD_ID ,
1122- #[ cfg( any( all( target_os = "linux" , target_env = "musl" ) , target_arch = "mips" ) ) ]
1123- SigevNotify :: SigevThreadId { ..} => 4 // No SIGEV_THREAD_ID defined
1124- } ;
1125- sev. sigev_signo = match sigev_notify {
1126- SigevNotify :: SigevSignal { signal, .. } => signal as libc:: c_int,
1127- #[ cfg( any( target_os = "dragonfly" , target_os = "freebsd" ) ) ]
1128- SigevNotify :: SigevKevent { kq, ..} => kq,
1129- #[ cfg( any( target_os = "linux" , target_os = "freebsd" ) ) ]
1130- SigevNotify :: SigevThreadId { signal, .. } => signal as libc:: c_int,
1131- _ => 0
1132- } ;
1133- sev. sigev_value. sival_ptr = match sigev_notify {
1134- SigevNotify :: SigevNone => ptr:: null_mut:: <libc:: c_void>( ) ,
1135- SigevNotify :: SigevSignal { si_value, .. } => si_value as * mut libc:: c_void,
1136- #[ cfg( any( target_os = "dragonfly" , target_os = "freebsd" ) ) ]
1137- SigevNotify :: SigevKevent { udata, .. } => udata as * mut libc:: c_void,
1138- #[ cfg( any( target_os = "freebsd" , target_os = "linux" ) ) ]
1139- SigevNotify :: SigevThreadId { si_value, .. } => si_value as * mut libc:: c_void,
1140- } ;
1141- SigEvent :: set_tid( & mut sev, & sigev_notify) ;
1264+ #[ cfg( feature = "event" ) ]
1265+ SigevNotify :: SigevKeventFlags { kq, udata, flags} => {
1266+ sev. sigev_notify = libc:: SIGEV_KEVENT ;
1267+ sev. sigev_signo = kq;
1268+ sev. sigev_value. sival_ptr = udata as * mut libc:: c_void;
1269+ sev. _sigev_un. _kevent_flags = flags. bits( ) ;
1270+ } ,
1271+ #[ cfg( target_os = "freebsd" ) ]
1272+ SigevNotify :: SigevThreadId { signal, thread_id, si_value} => {
1273+ sev. sigev_notify = libc:: SIGEV_THREAD_ID ;
1274+ sev. sigev_signo = signal as libc:: c_int;
1275+ sev. sigev_value. sival_ptr = si_value as * mut libc:: c_void;
1276+ sev. _sigev_un. _threadid = thread_id;
1277+ }
1278+ #[ cfg( any( target_env = "gnu" , target_env = "uclibc" ) ) ]
1279+ SigevNotify :: SigevThreadId { signal, thread_id, si_value} => {
1280+ sev. sigev_notify = libc:: SIGEV_THREAD_ID ;
1281+ sev. sigev_signo = signal as libc:: c_int;
1282+ sev. sigev_value. sival_ptr = si_value as * mut libc:: c_void;
1283+ sev. sigev_notify_thread_id = thread_id;
1284+ }
1285+ }
11421286 SigEvent { sigevent: sev}
11431287 }
11441288
1145- #[ cfg( any( target_os = "freebsd" , target_os = "linux" ) ) ]
1146- fn set_tid( sev: & mut libc:: sigevent, sigev_notify: & SigevNotify ) {
1147- sev. sigev_notify_thread_id = match * sigev_notify {
1148- SigevNotify :: SigevThreadId { thread_id, .. } => thread_id,
1149- _ => 0 as type_of_thread_id
1150- } ;
1151- }
1152-
1153- #[ cfg( not( any( target_os = "freebsd" , target_os = "linux" ) ) ) ]
1154- fn set_tid( _sev: & mut libc:: sigevent, _sigev_notify: & SigevNotify ) {
1289+ /// 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+ }
11551297 }
11561298
11571299 /// Return a copy of the inner structure
1300+ #[ cfg( not( target_os = "freebsd" ) ) ]
11581301 pub fn sigevent( & self ) -> libc:: sigevent {
11591302 self . sigevent
11601303 }
11611304
11621305 /// 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" ) ) ]
11631315 pub fn as_mut_ptr( & mut self ) -> * mut libc:: sigevent {
11641316 & mut self . sigevent
11651317 }
11661318 }
11671319
11681320 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" ) ) ]
11691331 fn from( sigevent: & libc:: sigevent) -> Self {
11701332 SigEvent { sigevent: * sigevent }
11711333 }
0 commit comments