25
25
//!
26
26
//! // Create an epoll object. Using `Owning` here means the epoll object will
27
27
//! // take ownership of the file descriptors registered with it.
28
- //! let epoll = epoll::epoll_create (epoll::CreateFlags::CLOEXEC)?;
28
+ //! let epoll = epoll::create (epoll::CreateFlags::CLOEXEC)?;
29
29
//!
30
30
//! // Register the socket with the epoll object.
31
- //! epoll::epoll_add(&epoll, &listen_sock, 1, epoll::EventFlags::IN)?;
31
+ //! epoll::add(
32
+ //! &epoll,
33
+ //! &listen_sock,
34
+ //! epoll::EventData::new_u64(1),
35
+ //! epoll::EventFlags::IN,
36
+ //! )?;
32
37
//!
33
38
//! // Keep track of the sockets we've opened.
34
- //! let mut next_id = 2 ;
39
+ //! let mut next_id = epoll::EventData::new_u64(2) ;
35
40
//! let mut sockets = HashMap::new();
36
41
//!
37
42
//! // Process events.
38
43
//! let mut event_list = epoll::EventVec::with_capacity(4);
39
44
//! loop {
40
- //! epoll::epoll_wait (&epoll, &mut event_list, -1)?;
45
+ //! epoll::wait (&epoll, &mut event_list, -1)?;
41
46
//! for event in &event_list {
42
47
//! let target = event.data;
43
- //! if target == 1 {
48
+ //! if target.u64() == 1 {
44
49
//! // Accept a new connection, set it to non-blocking, and
45
50
//! // register to be notified when it's ready to write to.
46
51
//! let conn_sock = accept(&listen_sock)?;
47
52
//! ioctl_fionbio(&conn_sock, true)?;
48
- //! epoll::epoll_add (
53
+ //! epoll::add (
49
54
//! &epoll,
50
55
//! &conn_sock,
51
56
//! next_id,
54
59
//!
55
60
//! // Keep track of the socket.
56
61
//! sockets.insert(next_id, conn_sock);
57
- //! next_id += 1 ;
62
+ //! next_id = epoll::EventData::new_u64(next_id.u64() + 1) ;
58
63
//! } else {
59
64
//! // Write a message to the stream and then unregister it.
60
65
//! let target = sockets.remove(&target).unwrap();
61
66
//! write(&target, b"hello\n")?;
62
- //! let _ = epoll::epoll_del (&epoll, &target)?;
67
+ //! let _ = epoll::delete (&epoll, &target)?;
63
68
//! }
64
69
//! }
65
70
//! }
@@ -72,12 +77,16 @@ use crate::backend::c;
72
77
use crate :: backend:: conv:: { ret, ret_owned_fd, ret_u32} ;
73
78
use crate :: fd:: { AsFd , AsRawFd , OwnedFd } ;
74
79
use crate :: io;
80
+ use crate :: utils:: as_mut_ptr;
75
81
use alloc:: vec:: Vec ;
76
82
use bitflags:: bitflags;
83
+ use core:: ffi:: c_void;
84
+ use core:: hash:: { Hash , Hasher } ;
77
85
use core:: ptr:: null_mut;
86
+ use core:: slice;
78
87
79
88
bitflags ! {
80
- /// `EPOLL_*` for use with [`Epoll:: new`].
89
+ /// `EPOLL_*` for use with [`new`].
81
90
#[ derive( Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
82
91
pub struct CreateFlags : c:: c_int {
83
92
/// `EPOLL_CLOEXEC`
@@ -86,7 +95,7 @@ bitflags! {
86
95
}
87
96
88
97
bitflags ! {
89
- /// `EPOLL*` for use with [`Epoll:: add`].
98
+ /// `EPOLL*` for use with [`add`].
90
99
#[ derive( Default , Copy , Clone , Eq , PartialEq , Hash , Debug ) ]
91
100
pub struct EventFlags : u32 {
92
101
/// `EPOLLIN`
@@ -137,82 +146,91 @@ bitflags! {
137
146
}
138
147
}
139
148
140
- /// `epoll_create1(flags)`—Creates a new `Epoll` .
149
+ /// `epoll_create1(flags)`—Creates a new epoll object .
141
150
///
142
151
/// Use the [`CreateFlags::CLOEXEC`] flag to prevent the resulting file
143
152
/// descriptor from being implicitly passed across `exec` boundaries.
144
153
#[ inline]
145
154
#[ doc( alias = "epoll_create1" ) ]
146
- pub fn epoll_create ( flags : CreateFlags ) -> io:: Result < OwnedFd > {
155
+ pub fn create ( flags : CreateFlags ) -> io:: Result < OwnedFd > {
147
156
// SAFETY: We're calling `epoll_create1` via FFI and we know how it
148
157
// behaves.
149
158
unsafe { ret_owned_fd ( c:: epoll_create1 ( flags. bits ( ) ) ) }
150
159
}
151
160
152
161
/// `epoll_ctl(self, EPOLL_CTL_ADD, data, event)`—Adds an element to an
153
- /// `Epoll` .
162
+ /// epoll object .
154
163
///
155
- /// If `epoll_del` is not called on the I/O source passed into this function
164
+ /// This registers interest in any of the events set in `events` occurring
165
+ /// on the file descriptor associated with `data`.
166
+ ///
167
+ /// If [`delete`] is not called on the I/O source passed into this function
156
168
/// before the I/O source is `close`d, then the `epoll` will act as if the I/O
157
169
/// source is still registered with it. This can lead to spurious events being
158
- /// returned from `epoll_wait` . If a file descriptor is an
170
+ /// returned from [`wait`] . If a file descriptor is an
159
171
/// `Arc<dyn SystemResource>`, then `epoll` can be thought to maintain a
160
172
/// `Weak<dyn SystemResource>` to the file descriptor.
161
173
#[ doc( alias = "epoll_ctl" ) ]
162
- pub fn epoll_add (
174
+ pub fn add (
163
175
epoll : impl AsFd ,
164
176
source : impl AsFd ,
165
- data : u64 ,
177
+ data : EventData ,
166
178
event_flags : EventFlags ,
167
179
) -> io:: Result < ( ) > {
168
180
// SAFETY: We're calling `epoll_ctl` via FFI and we know how it
169
- // behaves.
181
+ // behaves. We use our own `Event` struct instead of libc's because
182
+ // ours preserves pointer provenance instead of just using a `u64`,
183
+ // and we have tests elsehwere for layout equivalence.
170
184
unsafe {
171
185
let raw_fd = source. as_fd ( ) . as_raw_fd ( ) ;
172
186
ret ( c:: epoll_ctl (
173
187
epoll. as_fd ( ) . as_raw_fd ( ) ,
174
188
c:: EPOLL_CTL_ADD ,
175
189
raw_fd,
176
- & mut c:: epoll_event {
177
- events : event_flags. bits ( ) ,
178
- r#u64 : data,
179
- } ,
190
+ as_mut_ptr ( & mut Event {
191
+ flags : event_flags,
192
+ data,
193
+ } )
194
+ . cast ( ) ,
180
195
) )
181
196
}
182
197
}
183
198
184
199
/// `epoll_ctl(self, EPOLL_CTL_MOD, target, event)`—Modifies an element in
185
- /// this `Epoll` .
200
+ /// a given epoll object .
186
201
///
187
202
/// This sets the events of interest with `target` to `events`.
188
203
#[ doc( alias = "epoll_ctl" ) ]
189
- pub fn epoll_mod (
204
+ pub fn modify (
190
205
epoll : impl AsFd ,
191
206
source : impl AsFd ,
192
- data : u64 ,
207
+ data : EventData ,
193
208
event_flags : EventFlags ,
194
209
) -> io:: Result < ( ) > {
195
210
let raw_fd = source. as_fd ( ) . as_raw_fd ( ) ;
196
211
197
212
// SAFETY: We're calling `epoll_ctl` via FFI and we know how it
198
- // behaves.
213
+ // behaves. We use our own `Event` struct instead of libc's because
214
+ // ours preserves pointer provenance instead of just using a `u64`,
215
+ // and we have tests elsehwere for layout equivalence.
199
216
unsafe {
200
217
ret ( c:: epoll_ctl (
201
218
epoll. as_fd ( ) . as_raw_fd ( ) ,
202
219
c:: EPOLL_CTL_MOD ,
203
220
raw_fd,
204
- & mut c:: epoll_event {
205
- events : event_flags. bits ( ) ,
206
- r#u64 : data,
207
- } ,
221
+ as_mut_ptr ( & mut Event {
222
+ flags : event_flags,
223
+ data,
224
+ } )
225
+ . cast ( ) ,
208
226
) )
209
227
}
210
228
}
211
229
212
230
/// `epoll_ctl(self, EPOLL_CTL_DEL, target, NULL)`—Removes an element in
213
- /// this `Epoll` .
231
+ /// a given epoll object .
214
232
#[ doc( alias = "epoll_ctl" ) ]
215
- pub fn epoll_del ( epoll : impl AsFd , source : impl AsFd ) -> io:: Result < ( ) > {
233
+ pub fn delete ( epoll : impl AsFd , source : impl AsFd ) -> io:: Result < ( ) > {
216
234
// SAFETY: We're calling `epoll_ctl` via FFI and we know how it
217
235
// behaves.
218
236
unsafe {
@@ -231,11 +249,7 @@ pub fn epoll_del(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> {
231
249
///
232
250
/// For each event of interest, an element is written to `events`. On
233
251
/// success, this returns the number of written elements.
234
- pub fn epoll_wait (
235
- epoll : impl AsFd ,
236
- event_list : & mut EventVec ,
237
- timeout : c:: c_int ,
238
- ) -> io:: Result < ( ) > {
252
+ pub fn wait ( epoll : impl AsFd , event_list : & mut EventVec , timeout : c:: c_int ) -> io:: Result < ( ) > {
239
253
// SAFETY: We're calling `epoll_wait` via FFI and we know how it
240
254
// behaves.
241
255
unsafe {
@@ -254,12 +268,13 @@ pub fn epoll_wait(
254
268
255
269
/// An iterator over the `Event`s in an `EventVec`.
256
270
pub struct Iter < ' a > {
257
- iter : core :: slice:: Iter < ' a , Event > ,
271
+ iter : slice:: Iter < ' a , Event > ,
258
272
}
259
273
260
274
impl < ' a > Iterator for Iter < ' a > {
261
275
type Item = & ' a Event ;
262
276
277
+ #[ inline]
263
278
fn next ( & mut self ) -> Option < Self :: Item > {
264
279
self . iter . next ( )
265
280
}
@@ -280,11 +295,91 @@ impl<'a> Iterator for Iter<'a> {
280
295
) ]
281
296
pub struct Event {
282
297
/// Which specific event(s) occurred.
283
- // Match the layout of `c::epoll_event`. We just use a `u64` instead of
284
- // the full union.
285
- pub event_flags : EventFlags ,
298
+ pub flags : EventFlags ,
286
299
/// User data.
287
- pub data : u64 ,
300
+ pub data : EventData ,
301
+ }
302
+
303
+ /// Data assocated with an [`Event`]. This can either be a 64-bit integer value
304
+ /// or a pointer which preserves pointer provenance.
305
+ #[ repr( C ) ]
306
+ #[ derive( Copy , Clone ) ]
307
+ pub union EventData {
308
+ /// A 64-bit integer value.
309
+ as_u64 : u64 ,
310
+
311
+ /// A `*mut c_void` which preserves pointer provenance, extended to be
312
+ /// 64-bit so that if we read the value as a `u64` union field, we don't
313
+ /// get uninitialized memory.
314
+ sixty_four_bit_pointer : SixtyFourBitPointer ,
315
+ }
316
+
317
+ impl EventData {
318
+ /// Construct a new value containing a `u64`.
319
+ #[ inline]
320
+ pub fn new_u64 ( value : u64 ) -> Self {
321
+ Self { as_u64 : value }
322
+ }
323
+
324
+ /// Construct a new value containing a `*mut c_void`.
325
+ #[ inline]
326
+ pub fn new_ptr ( value : * mut c_void ) -> Self {
327
+ Self {
328
+ sixty_four_bit_pointer : SixtyFourBitPointer {
329
+ pointer : value,
330
+ #[ cfg( target_pointer_width = "32" ) ]
331
+ _padding : 0 ,
332
+ } ,
333
+ }
334
+ }
335
+
336
+ /// Return the value as a `u64`.
337
+ ///
338
+ /// If the stored value was a pointer, the pointer is zero-extended to
339
+ /// a `u64`.
340
+ #[ inline]
341
+ pub fn u64 ( self ) -> u64 {
342
+ unsafe { self . as_u64 }
343
+ }
344
+
345
+ /// Return the value as a `*mut c_void`.
346
+ ///
347
+ /// If the stored value was a `u64`, the least-significant bits of the
348
+ /// `u64` are returned as a pointer value.
349
+ #[ inline]
350
+ pub fn ptr ( self ) -> * mut c_void {
351
+ unsafe { self . sixty_four_bit_pointer . pointer }
352
+ }
353
+ }
354
+
355
+ impl PartialEq for EventData {
356
+ #[ inline]
357
+ fn eq ( & self , other : & EventData ) -> bool {
358
+ self . u64 ( ) == other. u64 ( )
359
+ }
360
+ }
361
+
362
+ impl Eq for EventData { }
363
+
364
+ impl Hash for EventData {
365
+ #[ inline]
366
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
367
+ self . u64 ( ) . hash ( state)
368
+ }
369
+ }
370
+
371
+ #[ repr( C ) ]
372
+ #[ derive( Copy , Clone ) ]
373
+ struct SixtyFourBitPointer {
374
+ #[ cfg( target_endian = "big" ) ]
375
+ #[ cfg( target_pointer_width = "32" ) ]
376
+ _padding : u32 ,
377
+
378
+ pointer : * mut c_void ,
379
+
380
+ #[ cfg( target_endian = "little" ) ]
381
+ #[ cfg( target_pointer_width = "32" ) ]
382
+ _padding : u32 ,
288
383
}
289
384
290
385
/// A vector of `Event`s, plus context for interpreting them.
@@ -375,3 +470,11 @@ impl<'a> IntoIterator for &'a EventVec {
375
470
self . iter ( )
376
471
}
377
472
}
473
+
474
+ #[ test]
475
+ fn test_epoll_layouts ( ) {
476
+ check_renamed_type ! ( Event , epoll_event) ;
477
+ check_renamed_type ! ( Event , epoll_event) ;
478
+ check_renamed_struct_renamed_field ! ( Event , epoll_event, flags, events) ;
479
+ check_renamed_struct_renamed_field ! ( Event , epoll_event, data, u64 ) ;
480
+ }
0 commit comments