Skip to content

Commit a660e60

Browse files
committed
1 parent 4345b74 commit a660e60

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

ch04/a-epoll/src/main.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! # FIXES:
2+
//! The number is identical to the number in the GitHub issue tracker
23
//!
34
//! ## FIX ISSUE #4:
45
//! See:https://github.com/PacktPublishing/Asynchronous-Programming-in-Rust/issues/4
@@ -38,6 +39,7 @@ fn get_req(path: &str) -> String {
3839
fn handle_events(
3940
events: &[Event],
4041
streams: &mut [TcpStream],
42+
// FIX #4: accepts a set of handled events as argument
4143
handled: &mut HashSet<usize>,
4244
) -> Result<usize> {
4345
let mut handled_events = 0;
@@ -67,7 +69,7 @@ fn handle_events(
6769
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
6870
// this was not in the book example, but it's a error condition
6971
// you probably want to handle in some way (either by breaking
70-
// out of the loop or trying a new read call immidiately)
72+
// out of the loop or trying a new read call immediately)
7173
Err(e) if e.kind() == io::ErrorKind::Interrupted => break,
7274
Err(e) => return Err(e),
7375
}

ch04/b-epoll-mio/src/main.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
1+
//! # FIXES:
2+
//!
3+
//! The number is identical to the number in the GitHub issue tracker
4+
//!
5+
//! ## FIX ISSUE #4:
6+
//!
7+
//! See:https://github.com/PacktPublishing/Asynchronous-Programming-in-Rust/issues/4
8+
//! Some users reported false event notification causing the counter to increase
9+
//! due to the OS reporting a READ event after we already read the TcpStream to EOF.
10+
//! This caused the counter to increment on the same TcpStream twice and thereby
11+
//! exiting the program before all events were handled.
12+
//!
13+
//! The fix for this is to account for false wakeups which is an easy fix but requires
14+
//! a few changes to the example. I've added an explicit comment: "FIX #4", the places
15+
//! I made a change so it's easy to spot the differences to the example code in the book.
16+
//!
17+
//! ## TROUBLESHOOTING (KNOWN POTENTIAL ISSUE)
18+
//!
19+
//! ### EXAMPLE DOESN'T WORK AS EXPECTED - PROBLEM WITH DNS LOOKUP
20+
//! If you first run this example on Linux under WSL and then immediately run it on
21+
//! Windows, I've observed issues with the DNS lookup for "localhost" being so slow
22+
//! that it defeats the purpose of the example. This issue could potentially also
23+
//! happen under other scenarios than the one mentioned here and the fix will be
24+
//! the same regardless.
25+
//!
26+
//! I don't consider this a bug with our code but a surprising behavior of the
27+
//! WSL/Windows network stack. Anyway, if you encounter this, the fix is simple:
28+
//!
29+
//! Change `let addr = "localhost:8080";` to `let addr = "127.0.0.1:8080";`.
30+
//!
31+
32+
// FIX #4 (import `HashSet``)
33+
use std::collections::HashSet;
134
use std::io::{self, Read, Result, Write};
235

336
use mio::event::Event;
@@ -13,7 +46,7 @@ fn get_req(path: &str) -> String {
1346
)
1447
}
1548

16-
fn handle_events(events: &[Event], streams: &mut [TcpStream]) -> Result<usize> {
49+
fn handle_events(events: &[Event], streams: &mut [TcpStream], handled: &mut HashSet<usize>) -> Result<usize> {
1750
let mut handled_events = 0;
1851
for event in events {
1952
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -24,6 +57,13 @@ fn handle_events(events: &[Event], streams: &mut [TcpStream]) -> Result<usize> {
2457
loop {
2558
match streams[index].read(&mut data) {
2659
Ok(n) if n == 0 => {
60+
// FIX #4
61+
// `insert` returns false if the value already existed in the set. We
62+
// handle it here since we must be sure that the TcpStream is fully
63+
// drained due to using edge triggered epoll.
64+
if !handled.insert(index) {
65+
break;
66+
}
2767
handled_events += 1;
2868
break;
2969
}
@@ -34,6 +74,10 @@ fn handle_events(events: &[Event], streams: &mut [TcpStream]) -> Result<usize> {
3474
println!("{txt}\n------\n");
3575
}
3676
Err(e) if e.kind() == io::ErrorKind::WouldBlock => break,
77+
// this was not in the book example, but it's a error condition
78+
// you probably want to handle in some way (either by breaking
79+
// out of the loop or trying a new read call immediately)
80+
Err(e) if e.kind() == io::ErrorKind::Interrupted => break,
3781
Err(e) => return Err(e),
3882
}
3983
}
@@ -73,6 +117,9 @@ fn main() -> Result<()> {
73117

74118
streams.push(stream);
75119
}
120+
121+
// FIX #4: store the handled IDs
122+
let mut handled_ids = HashSet::new();
76123

77124
let mut handled_events = 0;
78125
while handled_events < n_events {
@@ -92,8 +139,9 @@ fn main() -> Result<()> {
92139
// Events collection
93140
let events: Vec<Event> = events.into_iter().map(|e| e.clone()).collect();
94141
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
95-
96-
handled_events += handle_events(&events, &mut streams)?;
142+
143+
// ------------------------------------------------------⌄ FIX #4 (new signature)
144+
handled_events += handle_events(&events, &mut streams, &mut handled_ids)?;
97145
}
98146

99147
println!("FINISHED");

0 commit comments

Comments
 (0)