Skip to content

Commit 8c0b1ff

Browse files
hulxvThomasdezeeuw
andauthored
Make Event thread safe for platforms using kqueue (#1906)
Co-authored-by: Thomas de Zeeuw <[email protected]>
1 parent 51f41f0 commit 8c0b1ff

File tree

2 files changed

+54
-24
lines changed

2 files changed

+54
-24
lines changed

src/sys/unix/selector/kqueue.rs

Lines changed: 42 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl Selector {
114114
self.kq.as_raw_fd(),
115115
ptr::null(),
116116
0,
117-
events.as_mut_ptr(),
117+
events.as_mut_ptr().cast(),
118118
events.capacity() as Count,
119119
timeout,
120120
))
@@ -330,17 +330,31 @@ impl AsRawFd for Selector {
330330
}
331331
}
332332

333-
pub type Event = libc::kevent;
334-
pub struct Events(Vec<libc::kevent>);
333+
#[repr(transparent)]
334+
#[derive(Clone)]
335+
pub struct Event(libc::kevent);
335336

336-
impl Events {
337-
pub fn with_capacity(capacity: usize) -> Events {
338-
Events(Vec::with_capacity(capacity))
337+
unsafe impl Send for Event {}
338+
unsafe impl Sync for Event {}
339+
340+
impl Deref for Event {
341+
type Target = libc::kevent;
342+
343+
fn deref(&self) -> &Self::Target {
344+
&self.0
339345
}
340346
}
341347

348+
impl DerefMut for Event {
349+
fn deref_mut(&mut self) -> &mut Self::Target {
350+
&mut self.0
351+
}
352+
}
353+
354+
pub struct Events(Vec<Event>);
355+
342356
impl Deref for Events {
343-
type Target = Vec<libc::kevent>;
357+
type Target = Vec<Event>;
344358

345359
fn deref(&self) -> &Self::Target {
346360
&self.0
@@ -353,6 +367,12 @@ impl DerefMut for Events {
353367
}
354368
}
355369

370+
impl Events {
371+
pub fn with_capacity(capacity: usize) -> Events {
372+
Events(Vec::with_capacity(capacity))
373+
}
374+
}
375+
356376
// `Events` cannot derive `Send` or `Sync` because of the
357377
// `udata: *mut ::c_void` field in `libc::kevent`. However, `Events`'s public
358378
// API treats the `udata` field as a `uintptr_t` which is `Send`. `Sync` is
@@ -370,11 +390,11 @@ pub mod event {
370390
use super::{Filter, Flags};
371391

372392
pub fn token(event: &Event) -> Token {
373-
Token(event.udata as usize)
393+
Token(event.0.udata as usize)
374394
}
375395

376396
pub fn is_readable(event: &Event) -> bool {
377-
event.filter == libc::EVFILT_READ || {
397+
event.0.filter == libc::EVFILT_READ || {
378398
#[cfg(any(
379399
target_os = "freebsd",
380400
target_os = "ios",
@@ -404,22 +424,22 @@ pub mod event {
404424
}
405425

406426
pub fn is_writable(event: &Event) -> bool {
407-
event.filter == libc::EVFILT_WRITE
427+
event.0.filter == libc::EVFILT_WRITE
408428
}
409429

410430
pub fn is_error(event: &Event) -> bool {
411-
(event.flags & libc::EV_ERROR) != 0 ||
431+
(event.0.flags & libc::EV_ERROR) != 0 ||
412432
// When the read end of the socket is closed, EV_EOF is set on
413433
// flags, and fflags contains the error if there is one.
414-
(event.flags & libc::EV_EOF) != 0 && event.fflags != 0
434+
(event.0.flags & libc::EV_EOF) != 0 && event.0.fflags != 0
415435
}
416436

417437
pub fn is_read_closed(event: &Event) -> bool {
418-
event.filter == libc::EVFILT_READ && event.flags & libc::EV_EOF != 0
438+
event.0.filter == libc::EVFILT_READ && event.0.flags & libc::EV_EOF != 0
419439
}
420440

421441
pub fn is_write_closed(event: &Event) -> bool {
422-
event.filter == libc::EVFILT_WRITE && event.flags & libc::EV_EOF != 0
442+
event.0.filter == libc::EVFILT_WRITE && event.0.flags & libc::EV_EOF != 0
423443
}
424444

425445
pub fn is_priority(_: &Event) -> bool {
@@ -439,7 +459,7 @@ pub mod event {
439459
target_os = "watchos",
440460
))]
441461
{
442-
event.filter == libc::EVFILT_AIO
462+
event.0.filter == libc::EVFILT_AIO
443463
}
444464
#[cfg(not(any(
445465
target_os = "dragonfly",
@@ -459,7 +479,7 @@ pub mod event {
459479
pub fn is_lio(event: &Event) -> bool {
460480
#[cfg(target_os = "freebsd")]
461481
{
462-
event.filter == libc::EVFILT_LIO
482+
event.0.filter == libc::EVFILT_LIO
463483
}
464484
#[cfg(not(target_os = "freebsd"))]
465485
{
@@ -861,14 +881,14 @@ pub mod event {
861881
);
862882

863883
// Can't reference fields in packed structures.
864-
let ident = event.ident;
865-
let data = event.data;
866-
let udata = event.udata;
884+
let ident = event.0.ident;
885+
let data = event.0.data;
886+
let udata = event.0.udata;
867887
f.debug_struct("kevent")
868888
.field("ident", &ident)
869-
.field("filter", &FilterDetails(event.filter))
870-
.field("flags", &FlagsDetails(event.flags))
871-
.field("fflags", &FflagsDetails(event.fflags))
889+
.field("filter", &FilterDetails(event.0.filter))
890+
.field("flags", &FlagsDetails(event.0.flags))
891+
.field("fflags", &FflagsDetails(event.0.fflags))
872892
.field("data", &data)
873893
.field("udata", &udata)
874894
.finish()

tests/events.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33

44
use std::time::Duration;
55

6+
use mio::event::{self, Event, Events};
67
use mio::net::TcpStream;
7-
use mio::{event, Token, Waker};
8+
use mio::{Token, Waker};
89

910
mod util;
10-
use util::init_with_poll;
11+
use util::{assert_send, assert_sync, init_with_poll};
1112

1213
const WAKE_TOKEN: Token = Token(10);
1314

@@ -41,3 +42,12 @@ fn events_all() {
4142
events.clear();
4243
assert!(events.is_empty());
4344
}
45+
46+
#[test]
47+
fn is_event_send_sync() {
48+
assert_send::<Event>();
49+
assert_sync::<Event>();
50+
51+
assert_send::<Events>();
52+
assert_sync::<Events>();
53+
}

0 commit comments

Comments
 (0)