Treat ERROR_BROKEN_PIPE as end-of-file instead of an error
[libs/core.git] / source / io / windows / eventreader.cpp
1 #include <windows.h>
2 #include <algorithm>
3 #include <msp/core/systemerror.h>
4 #include "eventreader.h"
5 #include "handle_private.h"
6
7 using namespace std;
8
9 namespace Msp {
10 namespace IO {
11
12 struct EventReader::Private
13 {
14         OVERLAPPED overlapped;
15         Handle event;
16         unsigned buf_size;
17         char *buffer;
18         unsigned buf_avail;
19         char *buf_next;
20         bool pending;
21         bool eof;
22 };
23
24
25 EventReader::EventReader(Handle &h, unsigned size):
26         handle(h),
27         priv(new Private)
28 {
29         memset(&priv->overlapped, 0, sizeof(OVERLAPPED));
30         *priv->event = CreateEvent(0, true, false, 0);
31         priv->overlapped.hEvent = *priv->event;
32         priv->buf_size = size;
33         priv->buffer = new char[priv->buf_size];
34         priv->buf_avail = 0;
35         priv->buf_next = priv->buffer;
36         priv->pending = false;
37         priv->eof = false;
38 }
39
40 EventReader::~EventReader()
41 {
42         CloseHandle(*priv->event);
43         delete[] priv->buffer;
44         delete priv;
45 }
46
47 const Handle &EventReader::get_event()
48 {
49         start();
50         return priv->event;
51 }
52
53 void EventReader::start()
54 {
55         if(priv->buf_avail || priv->pending)
56                 return;
57
58         DWORD ret;
59         priv->buf_next = priv->buffer;
60         if(!ReadFile(*handle, priv->buffer, priv->buf_size, &ret, &priv->overlapped))
61         {
62                 unsigned err = GetLastError();
63                 if(err==ERROR_BROKEN_PIPE)
64                         priv->eof = true;
65                 else if(err==ERROR_IO_PENDING)
66                         priv->pending = true;
67                 else
68                         throw system_error("ReadFile");
69         }
70         else
71         {
72                 priv->buf_avail = ret;
73                 SetEvent(*priv->event);
74         }
75 }
76
77 void EventReader::wait()
78 {
79         if(!priv->pending)
80                 return;
81
82         DWORD ret;
83         if(!GetOverlappedResult(*handle, &priv->overlapped, &ret, true))
84         {
85                 DWORD err = GetLastError();
86                 if(err==ERROR_BROKEN_PIPE)
87                         priv->eof = true;
88                 else
89                         throw system_error("GetOverlappedResult");
90         }
91         else
92         {
93                 priv->buf_avail = ret;
94                 priv->pending = false;
95         }
96 }
97
98 unsigned EventReader::read(char *buf, unsigned len)
99 {
100         if(!priv->buf_avail)
101         {
102                 if(priv->eof)
103                         return 0;
104
105                 // No data in buffer, try to get some
106                 start();
107                 wait();
108         }
109
110         len = min(len, priv->buf_avail);
111         memcpy(buf, priv->buf_next, len);
112         priv->buf_next += len;
113         priv->buf_avail -= len;
114
115         if(!priv->buf_avail)
116         {
117                 ResetEvent(*priv->event);
118                 start();
119         }
120
121         return len;
122 }
123
124 } // namespace IO
125 } // namespace Msp