-#include <cerrno>
-#include <stdexcept>
-#ifndef WIN32
-#include <poll.h>
-#endif
-#include <msp/core/systemerror.h>
-#include <msp/strings/format.h>
-#include <msp/time/units.h>
-#include "base.h"
-#include "handle.h"
-#include "handle_private.h"
+#include <msp/core/except.h>
+#include <msp/core/algorithm.h>
+#include "eventobject.h"
#include "poll.h"
+#include "poll_platform.h"
using namespace std;
-namespace {
-
-using namespace Msp;
-using namespace Msp::IO;
-
-inline int sys_poll_event(PollEvent event)
-{
- int result = 0;
-
- if(event&~(P_INPUT|P_PRIO|P_OUTPUT))
- throw invalid_argument("sys_poll_event");
-
-#ifndef WIN32
- if(event&P_INPUT)
- result |= POLLIN;
- if(event&P_PRIO)
- result |= POLLPRI;
- if(event&P_OUTPUT)
- result |= POLLOUT;
-#endif
-
- return result;
-}
-
-inline PollEvent poll_event_from_sys(int event)
-{
- PollEvent result = P_NONE;
-
-#ifdef WIN32
- (void)event;
-#else
- if(event&POLLIN)
- result = result|P_INPUT;
- if(event&POLLPRI)
- result = result|P_PRIO;
- if(event&POLLOUT)
- result = result|P_OUTPUT;
- if(event&POLLERR)
- result = result|P_ERROR;
-#endif
-
- return result;
-}
-
-inline PollEvent do_poll(Base &obj, PollEvent pe, int timeout)
-{
-#ifdef WIN32
- if(timeout<0)
- timeout = INFINITE;
-
- DWORD ret = WaitForSingleObject(*obj.get_event_handle(), timeout);
- if(ret==WAIT_OBJECT_0)
- return pe;
- else if(ret==WAIT_FAILED)
- throw system_error("WaitForSingleObject");
-
- return P_NONE;
-#else
- pollfd pfd = { *obj.get_event_handle(), sys_poll_event(pe), 0 };
-
- int ret = ::poll(&pfd, 1, timeout);
- if(ret==-1)
- {
- if(errno==EINTR)
- return P_NONE;
- else
- throw system_error("poll");
- }
-
- return poll_event_from_sys(pfd.revents);
-#endif
-}
-
-}
-
-
namespace Msp {
namespace IO {
-struct Poller::Private
-{
-#ifdef WIN32
- vector<HANDLE> handles;
-#else
- vector<pollfd> pfd;
-#endif
-};
-
-
Poller::Poller():
- priv(new Private),
- objs_changed(false)
+ priv(new Private)
{ }
-void Poller::set_object(Base &obj, PollEvent ev)
+Poller::~Poller()
+{
+ delete priv;
+}
+
+void Poller::set_object(EventObject &obj, PollEvent ev)
{
// Verify that the object has an event handle
if(ev)
obj.get_event_handle();
- EventMap::iterator i = objects.find(&obj);
+ auto i = find_member(objects, &obj, &PolledObject::object);
if(i!=objects.end())
{
if(ev)
- i->second = ev;
+ i->events = ev;
else
- objects.erase(i);
-
- objs_changed = true;
+ {
+ *i = objects.back();
+ objects.pop_back();
+ objs_changed = true;
+ }
+ events_changed = true;
+ return;
}
- else if(ev)
- {
-#ifdef WIN32
- if(objects.size()>=MAXIMUM_WAIT_OBJECTS)
- throw logic_error("Maximum number of wait objects reached");
+
+ if(!ev)
+ return;
+
+#ifdef _WIN32
+ if(objects.size()>=MAXIMUM_WAIT_OBJECTS)
+ throw invalid_state("too many objects");
#endif
- objects.insert(EventMap::value_type(&obj, ev));
- objs_changed = true;
- }
+ objects.push_back({ &obj, ev });
+ objs_changed = true;
}
-int Poller::poll()
+unsigned Poller::poll()
{
return do_poll(-1);
}
-int Poller::poll(const Time::TimeDelta &timeout)
+unsigned Poller::poll(const Time::TimeDelta &timeout)
{
if(timeout<Time::zero)
throw invalid_argument("Poller::poll");
return do_poll(static_cast<int>(timeout/Time::msec));
}
-void Poller::rebuild_array()
+unsigned Poller::do_poll(int timeout)
{
-#ifdef WIN32
- priv->handles.clear();
-
- for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i)
- priv->handles.push_back(*i->first->get_event_handle());
-#else
- priv->pfd.clear();
-
- for(EventMap::iterator i=objects.begin(); i!=objects.end(); ++i)
+ if(objs_changed || events_changed)
{
- pollfd p;
- p.fd = *i->first->get_event_handle();
- p.events = sys_poll_event(i->second);
- priv->pfd.push_back(p);
- }
-#endif
-
- objs_changed = false;
-}
-
-int Poller::do_poll(int timeout)
-{
- if(objs_changed)
rebuild_array();
-
- poll_result.clear();
-
-#ifdef WIN32
- if(timeout<0)
- timeout = INFINITE;
-
- DWORD ret = WaitForMultipleObjects(priv->handles.size(), &priv->handles.front(), false, timeout);
- if(/*ret>=WAIT_OBJECT_0 &&*/ ret<WAIT_OBJECT_0+priv->handles.size())
- {
- EventMap::iterator i = objects.begin();
- advance(i, ret-WAIT_OBJECT_0);
- poll_result.push_back(Slot(i->first, i->second));
-
- return 1;
+ events_changed = false;
+ objs_changed = false;
}
- else if(ret==WAIT_FAILED)
- throw system_error("WaitForMultipleObjects");
- return 0;
-#else
- int ret = ::poll(&priv->pfd.front(), priv->pfd.size(), timeout);
- if(ret==-1)
- {
- if(errno==EINTR)
- return 0;
- else
- throw system_error("poll");
- }
+ poll_result.clear();
- int n = ret;
- EventMap::iterator j = objects.begin();
- for(vector<pollfd>::iterator i=priv->pfd.begin(); (i!=priv->pfd.end() && n>0); ++i, ++j)
- if(i->revents)
- {
- poll_result.push_back(Slot(j->first, poll_event_from_sys(i->revents)));
- --n;
- }
+ platform_poll(timeout);
- return ret;
-#endif
+ return poll_result.size();
}
-PollEvent poll(Base &obj, PollEvent pe)
+PollEvent platform_poll(EventObject &, PollEvent, int);
+
+PollEvent poll(EventObject &obj, PollEvent pe)
{
- return do_poll(obj, pe, -1);
+ return platform_poll(obj, pe, -1);
}
-PollEvent poll(Base &obj, PollEvent pe, const Time::TimeDelta &timeout)
+PollEvent poll(EventObject &obj, PollEvent pe, const Time::TimeDelta &timeout)
{
if(timeout<Time::zero)
- throw invalid_argument("poll");
+ throw invalid_argument("IO::poll");
- return do_poll(obj, pe, static_cast<int>(timeout/Time::msec));
+ return platform_poll(obj, pe, static_cast<int>(timeout/Time::msec));
}
} // namespace IO