From: Mikko Rasa Date: Sun, 12 Jun 2011 15:02:56 +0000 (+0300) Subject: EventReader class X-Git-Url: http://git.tdb.fi/?a=commitdiff_plain;h=caa2f6ca5d0a803e47d6efb4858c92c505520527;p=libs%2Fcore.git EventReader class --- diff --git a/source/io/eventreader.cpp b/source/io/eventreader.cpp new file mode 100644 index 0000000..a31a384 --- /dev/null +++ b/source/io/eventreader.cpp @@ -0,0 +1,140 @@ +#ifdef WIN32 +#include +#endif +#include +#include +#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 diff --git a/source/io/eventreader.h b/source/io/eventreader.h new file mode 100644 index 0000000..b3acdb9 --- /dev/null +++ b/source/io/eventreader.h @@ -0,0 +1,43 @@ +#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