--- /dev/null
+#ifdef WIN32
+#include <windows.h>
+#endif
+#include <algorithm>
+#include <msp/core/systemerror.h>
+#include "eventreader.h"
+#include "handle_private.h"
+
+using namespace std;
+
+namespace Msp {
+namespace IO {
+
+struct EventReader::Private
+{
+#ifdef WIN32
+ OVERLAPPED *overlapped;
+ Handle event;
+ unsigned buf_size;
+ char *buffer;
+ unsigned buf_avail;
+ char *buf_next;
+#endif
+};
+
+
+EventReader::EventReader(Handle &h, unsigned size):
+ handle(h),
+ priv(0)
+{
+#ifdef WIN32
+ priv = new Private;
+
+ priv->overlapped = 0;
+ *priv->event = CreateEvent(0, true, false, 0);
+ priv->buf_size = size;
+ priv->buffer = new char[priv->buf_size];
+ priv->buf_avail = 0;
+ priv->buf_next = priv->buffer;
+
+ start();
+#else
+ (void)size;
+#endif
+}
+
+EventReader::~EventReader()
+{
+#ifdef WIN32
+ CloseHandle(*priv->event);
+ delete priv->overlapped;
+ delete[] priv->buffer;
+#endif
+ delete priv;
+}
+
+const Handle &EventReader::get_event() const
+{
+#ifdef WIN32
+ return priv->event;
+#else
+ return handle;
+#endif
+}
+
+void EventReader::start()
+{
+#ifdef WIN32
+ if(priv->buf_avail || priv->overlapped)
+ return;
+
+ priv->overlapped = new OVERLAPPED;
+ memset(priv->overlapped, 0, sizeof(OVERLAPPED));
+ priv->overlapped->hEvent = *priv->event;
+
+ DWORD ret;
+ priv->buf_next = priv->buffer;
+ if(!ReadFile(*handle, priv->buffer, priv->buf_size, &ret, priv->overlapped))
+ {
+ unsigned err = GetLastError();
+ if(err!=ERROR_IO_PENDING)
+ throw system_error("ReadFile");
+ }
+ else
+ {
+ priv->buf_avail = ret;
+ delete priv->overlapped;
+ priv->overlapped = 0;
+ SetEvent(*priv->event);
+ }
+#endif
+}
+
+void EventReader::wait()
+{
+#ifdef WIN32
+ if(!priv->overlapped)
+ return;
+
+ DWORD ret;
+ if(!GetOverlappedResult(*handle, priv->overlapped, &ret, true))
+ throw system_error("GetOverlappedResult");
+ else
+ {
+ priv->buf_avail = ret;
+ delete priv->overlapped;
+ priv->overlapped = 0;
+ }
+#endif
+}
+
+unsigned EventReader::read(char *buf, unsigned len)
+{
+#ifdef WIN32
+ if(!priv->buf_avail)
+ {
+ // No data in buffer, try to get some
+ start();
+ wait();
+ }
+
+ len = min(len, priv->buf_avail);
+ memcpy(buf, priv->buf_next, len);
+ priv->buf_next += len;
+ priv->buf_avail -= len;
+
+ if(!priv->buf_avail)
+ {
+ ResetEvent(*priv->event);
+ start();
+ }
+
+ return len;
+#else
+ return sys_read(handle, buf, len);
+#endif
+}
+
+} // namespace IO
+} // namespace Msp
--- /dev/null
+#ifndef MSP_IO_EVENTREADER_H_
+#define MSP_IO_EVENTREADER_H_
+
+#include "handle.h"
+
+namespace Msp {
+namespace IO {
+
+/**
+Helper class for reading data in a way that supports events. For internal use
+only.
+
+On Windows, overlapped reads are used. Data is read to an internal buffer and
+handed out from there. An event object is kept synchronized with the buffer
+state to get level-triggered semantics for poll. Whenever the buffer becomes
+empty, a new overlapped read is started.
+
+Unix-based systems can poll the fd directly, so this class reduces to a simple
+passthrough to sys_read.
+*/
+class EventReader
+{
+private:
+ struct Private;
+
+ Handle &handle;
+ Private *priv;
+
+public:
+ EventReader(Handle &, unsigned);
+ ~EventReader();
+
+ const Handle &get_event() const;
+
+ void start();
+ void wait();
+ unsigned read(char *, unsigned);
+};
+
+} // namespace IO
+} // namespace Msp
+
+#endif