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 ;
134use std:: io:: { self , Read , Result , Write } ;
235
336use 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