]> git.tdb.fi Git - libs/core.git/blob - source/io/windows/eventreader.cpp
Close duplicated handles after starting a new process
[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 };
21
22
23 EventReader::EventReader(Handle &h, unsigned size):
24         handle(h),
25         priv(new Private)
26 {
27         priv->overlapped = 0;
28         *priv->event = CreateEvent(0, true, false, 0);
29         priv->buf_size = size;
30         priv->buffer = new char[priv->buf_size];
31         priv->buf_avail = 0;
32         priv->buf_next = priv->buffer;
33 }
34
35 EventReader::~EventReader()
36 {
37         CloseHandle(*priv->event);
38         delete priv->overlapped;
39         delete[] priv->buffer;
40         delete priv;
41 }
42
43 const Handle &EventReader::get_event()
44 {
45         start();
46         return priv->event;
47 }
48
49 void EventReader::start()
50 {
51         if(priv->buf_avail || priv->overlapped)
52                 return;
53
54         priv->overlapped = new OVERLAPPED;
55         memset(priv->overlapped, 0, sizeof(OVERLAPPED));
56         priv->overlapped->hEvent = *priv->event;
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_IO_PENDING)
64                         throw system_error("ReadFile");
65         }
66         else
67         {
68                 priv->buf_avail = ret;
69                 delete priv->overlapped;
70                 priv->overlapped = 0;
71                 SetEvent(*priv->event);
72         }
73 }
74
75 void EventReader::wait()
76 {
77         if(!priv->overlapped)
78                 return;
79
80         DWORD ret;
81         if(!GetOverlappedResult(*handle, priv->overlapped, &ret, true))
82                 throw system_error("GetOverlappedResult");
83         else
84         {
85                 priv->buf_avail = ret;
86                 delete priv->overlapped;
87                 priv->overlapped = 0;
88         }
89 }
90
91 unsigned EventReader::read(char *buf, unsigned len)
92 {
93         if(!priv->buf_avail)
94         {
95                 // No data in buffer, try to get some
96                 start();
97                 wait();
98         }
99
100         len = min(len, priv->buf_avail);
101         memcpy(buf, priv->buf_next, len);
102         priv->buf_next += len;
103         priv->buf_avail -= len;
104
105         if(!priv->buf_avail)
106         {
107                 ResetEvent(*priv->event);
108                 start();
109         }
110
111         return len;
112 }
113
114 } // namespace IO
115 } // namespace Msp