@@ -1022,7 +1022,7 @@ feature! {
1022
1022
#[ cfg( target_os = "freebsd" ) ]
1023
1023
pub type type_of_thread_id = libc:: lwpid_t;
1024
1024
/// Identifies a thread for [`SigevNotify::SigevThreadId`]
1025
- #[ cfg( target_os = "linux" ) ]
1025
+ #[ cfg( any ( target_env = "gnu" , target_env = "uclibc" ) ) ]
1026
1026
pub type type_of_thread_id = libc:: pid_t;
1027
1027
1028
1028
/// Specifies the notification method used by a [`SigEvent`]
@@ -1042,8 +1042,7 @@ pub enum SigevNotify {
1042
1042
/// structure of the queued signal.
1043
1043
si_value: libc:: intptr_t
1044
1044
} ,
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.
1047
1046
/// Notify by delivering an event to a kqueue.
1048
1047
#[ cfg( any( target_os = "dragonfly" , target_os = "freebsd" ) ) ]
1049
1048
#[ cfg_attr( docsrs, doc( cfg( all( ) ) ) ) ]
@@ -1053,8 +1052,24 @@ pub enum SigevNotify {
1053
1052
/// Will be contained in the kevent's `udata` field.
1054
1053
udata: libc:: intptr_t
1055
1054
} ,
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
+ } ,
1056
1067
/// 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
+ ) ) ]
1058
1073
#[ cfg_attr( docsrs, doc( cfg( all( ) ) ) ) ]
1059
1074
SigevThreadId {
1060
1075
/// Signal to send
@@ -1079,17 +1094,139 @@ mod sigevent {
1079
1094
#![ any( feature = "aio" , feature = "signal" ) ]
1080
1095
1081
1096
use std:: mem;
1082
- use std:: ptr;
1083
1097
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
+ }
1086
1221
1087
1222
/// Used to request asynchronous notification of the completion of certain
1088
1223
/// events, such as POSIX AIO and timers.
1089
1224
#[ 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) ]
1091
1228
pub struct SigEvent {
1092
- sigevent: libc :: sigevent
1229
+ sigevent: libc_sigevent
1093
1230
}
1094
1231
1095
1232
impl SigEvent {
@@ -1107,65 +1244,90 @@ mod sigevent {
1107
1244
/// `SIGEV_SIGNAL`. That field is part of a union that shares space with the
1108
1245
/// more genuinely useful `sigev_notify_thread_id`
1109
1246
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
+ } ,
1114
1257
#[ 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
+ } ,
1116
1263
#[ 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
+ }
1142
1286
SigEvent { sigevent: sev}
1143
1287
}
1144
1288
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
+ }
1155
1297
}
1156
1298
1157
1299
/// Return a copy of the inner structure
1300
+ #[ cfg( not( target_os = "freebsd" ) ) ]
1158
1301
pub fn sigevent( & self ) -> libc:: sigevent {
1159
1302
self . sigevent
1160
1303
}
1161
1304
1162
1305
/// 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" ) ) ]
1163
1315
pub fn as_mut_ptr( & mut self ) -> * mut libc:: sigevent {
1164
1316
& mut self . sigevent
1165
1317
}
1166
1318
}
1167
1319
1168
1320
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" ) ) ]
1169
1331
fn from( sigevent: & libc:: sigevent) -> Self {
1170
1332
SigEvent { sigevent: * sigevent }
1171
1333
}
0 commit comments