X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=blobdiff_plain;f=source%2Fio%2Fpoll.cpp;fp=source%2Fio%2Fpoll.cpp;h=dce1912f830e27921df6835d3b8e96b9969279f3;hp=0000000000000000000000000000000000000000;hb=6e0fd758970bcb5bad5e3f2454b694cc4d7b4b66;hpb=b97d4e9f86e90254ab9edef7ee62a910f6333c78 diff --git a/source/io/poll.cpp b/source/io/poll.cpp new file mode 100644 index 0000000..dce1912 --- /dev/null +++ b/source/io/poll.cpp @@ -0,0 +1,212 @@ +#include +#include +#include +#include "except.h" +#include "base.h" +#include "poll.h" + +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 InvalidParameterValue("Invalid poll events"); + +#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 + // Stop the compiler from complaining about unused parameter + event = 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 SystemError("Poll failed", GetLastError()); + + 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 SystemError("Poll failed", errno); + } + + return poll_event_from_sys(pfd.revents); +#endif +} + +} + +namespace Msp { +namespace IO { + +Poller::Poller(): + pfd_dirty(false) +{ } + +void Poller::set_object(Base &obj, PollEvent ev) +{ + // Verify that the object has an event handle + if(ev) + obj.get_event_handle(); + + SlotMap::iterator i = objects.find(&obj); + if(i!=objects.end()) + { + if(ev) + i->second.events = ev; + else + objects.erase(i); + + pfd_dirty = true; + } + else if(ev) + { +#ifdef WIN32 + if(objects.size()>=MAXIMUM_WAIT_OBJECTS) + throw InvalidState("Maximum number of wait objects reached"); +#endif + objects.insert(SlotMap::value_type(&obj, Slot(&obj, ev))); + + pfd_dirty = true; + } +} + +int Poller::poll() +{ + return do_poll(-1); +} + +int Poller::poll(const Time::TimeDelta &timeout) +{ + if(timeout(timeout/Time::msec)); +} + +void Poller::rebuild_pfd() +{ + pfd.clear(); + + pollfd p; + + for(SlotMap::iterator i=objects.begin(); i!=objects.end(); ++i) + { + p.fd = i->second.object->get_event_handle(); +#ifndef WIN32 + p.events = sys_poll_event(i->second.events); +#endif + pfd.push_back(p); + } + + pfd_dirty = false; +} + +int Poller::do_poll(int timeout) +{ + if(pfd_dirty) + rebuild_pfd(); + + poll_result.clear(); + +#ifdef WIN32 + if(timeout<0) + timeout = INFINITE; + + DWORD ret = WaitForMultipleObjects(pfd.size(), &pfd.front().fd, false, timeout); + if(/*ret>=WAIT_OBJECT_0 &&*/ retsecond.object, i->second.events)); + + return 1; + } + else if(ret==WAIT_FAILED) + throw SystemError("Poll failed", GetLastError()); + + return 0; +#else + int ret = ::poll(&pfd.front(), pfd.size(), timeout); + if(ret==-1) + { + if(errno==EINTR) + return 0; + else + throw SystemError("Poll failed", errno); + } + + int n = ret; + SlotMap::iterator j = objects.begin(); + for(std::vector::iterator i=pfd.begin(); (i!=pfd.end() && n>0); ++i,++j) + if(i->revents) + { + poll_result.push_back(Slot(j->second.object, poll_event_from_sys(i->revents))); + --n; + } + + return ret; +#endif +} + + +PollEvent poll(Base &obj, PollEvent pe) +{ + return do_poll(obj, pe, -1); +} + +PollEvent poll(Base &obj, PollEvent pe, const Time::TimeDelta &timeout) +{ + if(timeout(timeout/Time::msec)); +} + +} // namespace IO +} // namespace Msp