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 ;
1
34
use std:: io:: { self , Read , Result , Write } ;
2
35
3
36
use mio:: event:: Event ;
@@ -13,7 +46,7 @@ fn get_req(path: &str) -> String {
13
46
)
14
47
}
15
48
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 > {
17
50
let mut handled_events = 0 ;
18
51
for event in events {
19
52
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -24,6 +57,13 @@ fn handle_events(events: &[Event], streams: &mut [TcpStream]) -> Result<usize> {
24
57
loop {
25
58
match streams[ index] . read ( & mut data) {
26
59
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
+ }
27
67
handled_events += 1 ;
28
68
break ;
29
69
}
@@ -34,6 +74,10 @@ fn handle_events(events: &[Event], streams: &mut [TcpStream]) -> Result<usize> {
34
74
println ! ( "{txt}\n ------\n " ) ;
35
75
}
36
76
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 ,
37
81
Err ( e) => return Err ( e) ,
38
82
}
39
83
}
@@ -73,6 +117,9 @@ fn main() -> Result<()> {
73
117
74
118
streams. push ( stream) ;
75
119
}
120
+
121
+ // FIX #4: store the handled IDs
122
+ let mut handled_ids = HashSet :: new ( ) ;
76
123
77
124
let mut handled_events = 0 ;
78
125
while handled_events < n_events {
@@ -92,8 +139,9 @@ fn main() -> Result<()> {
92
139
// Events collection
93
140
let events: Vec < Event > = events. into_iter ( ) . map ( |e| e. clone ( ) ) . collect ( ) ;
94
141
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
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) ?;
97
145
}
98
146
99
147
println ! ( "FINISHED" ) ;
0 commit comments