From: g0dil Date: Fri, 10 Nov 2006 23:10:53 +0000 (+0000) Subject: Implement Read/WriteHelper X-Git-Url: http://g0dil.de/git?a=commitdiff_plain;h=c5ab87643518405aa5171ed4602f7234873a4900;p=senf.git Implement Read/WriteHelper fix EPOLLERR and EPOLLHUP handling git-svn-id: https://svn.berlios.de/svnroot/repos/senf/trunk@152 270642c3-0616-0410-b53a-bc976706d245 --- diff --git a/Scheduler/ReadHelper.cci b/Scheduler/ReadHelper.cci new file mode 100644 index 0000000..81d7e6a --- /dev/null +++ b/Scheduler/ReadHelper.cci @@ -0,0 +1,27 @@ +// $Id$ +// +// Copyright (C) 2006 + +// Definition of inline non-template functions + +// Custom includes + +#define prefix_ inline +///////////////////////////////cci.p/////////////////////////////////////// + +prefix_ satcom::lib::ReadUntil::ReadUntil(std::string target_) + : target(target_) +{} + +prefix_ std::string::size_type satcom::lib::ReadUntil::operator()(std::string data) +{ + return data.find(target); +} + +///////////////////////////////cci.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// End: diff --git a/Scheduler/ReadHelper.ct b/Scheduler/ReadHelper.ct new file mode 100644 index 0000000..16d2850 --- /dev/null +++ b/Scheduler/ReadHelper.ct @@ -0,0 +1,98 @@ +// $Id$ +// +// Copyright (C) 2006 + +// Definition of non-inline template functions + +#include "ReadHelper.ih" + +// Custom includes +#include +#include "Utils/membind.hh" +#include "Utils/Exception.hh" +#include "Scheduler.hh" + +#define prefix_ +///////////////////////////////ct.p//////////////////////////////////////// + +template +prefix_ satcom::lib::ReadHelper::ReadHelper(Handle handle, std::string::size_type maxSize, + InternalPredicate * predicate, Callback cb) + : handle_(handle), maxSize_(maxSize), predicate_(predicate), callback_(cb), + errno_(0), complete_(false) +{ + // Here we add a *static* member taking a *smart* pointer as first + // argumnet instead of a simple bound-member as callback to the + // scheduler. This ensures, that the refcount is at least 1 as + // long as the helper is registered with the scheduler. + satcom::lib::Scheduler::instance() + .add(handle,boost::bind(&ReadHelper::dispatchProcess,ptr(this),_1,_2), + satcom::lib::Scheduler::EV_READ); +} + +template +prefix_ void satcom::lib::ReadHelper::revoke() +{ + ptr guard (this); // To ensure, 'this' is deleted only after this method terminates ... + satcom::lib::Scheduler::instance() + .remove(handle_,satcom::lib::Scheduler::EV_READ); +} + +template +prefix_ void +satcom::lib::ReadHelper::dispatchProcess(ptr helper, Handle handle, + satcom::lib::Scheduler::EventId event) +{ + // since we have a 'ptr' argument, the instance cannot be deleted + // before this method returns + return helper->process(handle,event); +} + +template +prefix_ void satcom::lib::ReadHelper::process(Handle handle, + satcom::lib::Scheduler::EventId event) +{ + try { + if (event != satcom::lib::Scheduler::EV_READ) + throw SystemException(EPIPE); + std::string rcv (handle.read(maxSize_ - data_.size())); + data_.append(rcv); + std::string::size_type n = predicate_ ? (*predicate_)(data_) : std::string::npos; + if (n != std::string::npos || data_.size() >= maxSize_ || rcv.size() == 0) { + complete_ = true; + if (n < data_.size()) { + tail_.assign(data_,n,std::string::npos); + data_.erase(n); + } + done(); + } + } + catch (satcom::lib::SystemException const & ex) { + errno_ = ex.err; + done(); + } +} + +template +prefix_ void satcom::lib::ReadHelper::done() +{ + revoke(); + callback_(ptr(this)); +} + +template +template +prefix_ std::string::size_type +satcom::lib::ReadHelper::InternalPredicate::Dispatcher:: +operator()(std::string const & data) +{ + return predicate(data); +} + +///////////////////////////////ct.e//////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// End: diff --git a/Scheduler/ReadHelper.cti b/Scheduler/ReadHelper.cti new file mode 100644 index 0000000..75613d2 --- /dev/null +++ b/Scheduler/ReadHelper.cti @@ -0,0 +1,89 @@ +// $Id$ +// +// Copyright (C) 2006 + +// Definition of inline template functions + +#include "ReadHelper.ih" + +// Custom includes +#include "Utils/Exception.hh" + +#define prefix_ inline +///////////////////////////////cti.p/////////////////////////////////////// + +template +prefix_ typename satcom::lib::ReadHelper::ptr +satcom::lib::ReadHelper::dispatch(Handle handle, std::string::size_type maxSize, + Callback callback) +{ + return ptr(new ReadHelper(handle, maxSize, 0, callback)); +} + +template +template +prefix_ typename satcom::lib::ReadHelper::ptr +satcom::lib::ReadHelper::dispatch(Handle handle, std::string::size_type maxSize, + Predicate predicate, Callback callback) +{ + return ptr(new ReadHelper(handle, maxSize, + new typename InternalPredicate::template Dispatcher(predicate), + callback)); +} + +template +prefix_ Handle satcom::lib::ReadHelper::handle() + const +{ + return handle_; +} + +template +prefix_ unsigned satcom::lib::ReadHelper::maxSize() + const +{ + return maxSize_; +} + +template +prefix_ std::string const & satcom::lib::ReadHelper::data() + const +{ + return data_; +} + +template +prefix_ std::string const & satcom::lib::ReadHelper::tail() + const +{ + return tail_; +} + +template +prefix_ bool satcom::lib::ReadHelper::complete() + const +{ + return complete_; +} + +template +prefix_ bool satcom::lib::ReadHelper::error() + const +{ + return errno_ != 0; +} + +template +prefix_ void satcom::lib::ReadHelper::throw_error() + const +{ + if (errno_ != 0) throw SystemException(errno_); +} + +///////////////////////////////cti.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// End: diff --git a/Scheduler/ReadHelper.hh b/Scheduler/ReadHelper.hh new file mode 100644 index 0000000..8f38b16 --- /dev/null +++ b/Scheduler/ReadHelper.hh @@ -0,0 +1,103 @@ +// $Id$ +// +// Copyright (C) 2006 + +// TODO: Move all not Handle dependent members to a ReadHandleBase class + +#ifndef HH_ReadHelper_ +#define HH_ReadHelper_ 1 + +// Custom includes +#include +#include +#include +#include + +#include "Utils/intrusive_refcount.hh" +#include "Scheduler.hh" + +//#include "ReadHelper.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace satcom { +namespace lib { + + template + class ReadHelper + : public satcom::lib::intrusive_refcount + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::intrusive_ptr ptr; + typedef boost::function Callback; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + static ptr dispatch(Handle handle, std::string::size_type maxSize, + Callback callback); + + template + static ptr dispatch(Handle handle, std::string::size_type maxSize, Predicate predicate, + Callback callback); + + ///@} + /////////////////////////////////////////////////////////////////////////// + + Handle handle() const; + unsigned maxSize() const; + + std::string const & data() const; + std::string const & tail() const; + + bool complete() const; + bool error() const; + void throw_error() const; + + void revoke(); + + protected: + + private: + struct InternalPredicate; + + ReadHelper(Handle handle, unsigned maxSize, InternalPredicate * predicate, Callback cb); + + static void dispatchProcess(ptr helper, Handle handle, satcom::lib::Scheduler::EventId event); + void process(Handle handle, satcom::lib::Scheduler::EventId event); + void done(); + + Handle handle_; + std::string::size_type maxSize_; + boost::scoped_ptr predicate_; + Callback callback_; + + std::string data_; + std::string tail_; + int errno_; + bool complete_; + }; + + struct ReadUntil + { + ReadUntil(std::string target); + std::string::size_type operator()(std::string data); + std::string target; + }; + +}} + +///////////////////////////////hh.e//////////////////////////////////////// +#include "ReadHelper.cci" +#include "ReadHelper.ct" +#include "ReadHelper.cti" +//#include "ReadHelper.mpp" +#endif + + +// Local Variables: +// mode: c++ +// End: diff --git a/Scheduler/ReadHelper.ih b/Scheduler/ReadHelper.ih new file mode 100644 index 0000000..e174b5f --- /dev/null +++ b/Scheduler/ReadHelper.ih @@ -0,0 +1,40 @@ +// $Id$ +// +// Copyright (C) 2006 + +#ifndef IH_ReadHelper_ +#define IH_ReadHelper_ 1 + +// Custom includes + +///////////////////////////////ih.p//////////////////////////////////////// + +namespace satcom { +namespace lib { + + template + struct ReadHelper::InternalPredicate + { + virtual ~InternalPredicate() {} + template + struct Dispatcher + : public ReadHelper::InternalPredicate + { + Dispatcher(Predicate p) : predicate(p) {} + virtual std::string::size_type operator()(std::string const & data); + Predicate predicate; + }; + + virtual std::string::size_type operator()(std::string const & data) = 0; + }; + +}} + + +///////////////////////////////ih.e//////////////////////////////////////// +#endif + + +// Local Variables: +// mode: c++ +// End: diff --git a/Scheduler/ReadHelper.test.cc b/Scheduler/ReadHelper.test.cc new file mode 100644 index 0000000..14a3686 --- /dev/null +++ b/Scheduler/ReadHelper.test.cc @@ -0,0 +1,27 @@ +// $Id$ +// +// Copyright (C) 2006 + +// Unit tests + +//#include "ReadHelper.test.hh" +//#include "ReadHelper.test.ih" + +// Custom includes +#include "ReadHelper.hh" + +#include +#include + +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + + + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// End: diff --git a/Scheduler/SConscript b/Scheduler/SConscript index fc9284e..2909ad3 100644 --- a/Scheduler/SConscript +++ b/Scheduler/SConscript @@ -7,4 +7,4 @@ SatSCons.StandardTargets(env) SatSCons.Lib(env, library = 'Scheduler', sources = SatSCons.GlobSources(), - LIBS = [ 'Utils' ]) + LIBS = [ 'Socket', 'Utils' ]) diff --git a/Scheduler/Scheduler.cc b/Scheduler/Scheduler.cc index 4f39c4b..75ed7f8 100644 --- a/Scheduler/Scheduler.cc +++ b/Scheduler/Scheduler.cc @@ -96,7 +96,7 @@ prefix_ satcom::lib::Scheduler::Scheduler() throw SystemException(errno); } -prefix_ void satcom::lib::Scheduler::do_add(int fd, SimpleCallback const & cb, EventId eventMask) +prefix_ void satcom::lib::Scheduler::do_add(int fd, SimpleCallback const & cb, int eventMask) { FdTable::iterator i (fdTable_.find(fd)); int action (EPOLL_CTL_MOD); @@ -120,7 +120,7 @@ prefix_ void satcom::lib::Scheduler::do_add(int fd, SimpleCallback const & cb, E throw SystemException(errno); } -prefix_ void satcom::lib::Scheduler::do_remove(int fd, EventId eventMask) +prefix_ void satcom::lib::Scheduler::do_remove(int fd, int eventMask) { FdTable::iterator i (fdTable_.find(fd)); if (i == fdTable_.end()) @@ -136,7 +136,7 @@ prefix_ void satcom::lib::Scheduler::do_remove(int fd, EventId eventMask) memset(&ev,0,sizeof(ev)); ev.events = i->second.epollMask(); ev.data.fd = fd; - + int action (EPOLL_CTL_MOD); if (ev.events==0) { action = EPOLL_CTL_DEL; @@ -164,7 +164,7 @@ prefix_ void satcom::lib::Scheduler::process() { terminate_ = false; while (! terminate_) { - struct epoll_event ev; + MicroTime timeNow = now(); while ( ! timerQueue_.empty() && timerQueue_.top().timeout <= timeNow ) { timerQueue_.top().cb(); @@ -174,6 +174,7 @@ prefix_ void satcom::lib::Scheduler::process() return; int timeout = timerQueue_.empty() ? -1 : int((timerQueue_.top().timeout - timeNow)/1000); + struct epoll_event ev; int events = epoll_wait(epollFd_, &ev, 1, timeout); if (events<0) // Hmm ... man epoll says, it will NOT return with EINTR ?? @@ -200,13 +201,22 @@ prefix_ void satcom::lib::Scheduler::process() } else if (ev.events & EPOLLHUP) { - BOOST_ASSERT(spec.cb_hup); - spec.cb_hup(EV_HUP); + if (spec.cb_hup) + spec.cb_hup(EV_HUP); + else if (ev.events & EPOLLERR) { + if (spec.cb_write) spec.cb_write(EV_HUP); + if (spec.cb_read) spec.cb_read(EV_HUP); + } } - else if (ev.events & EPOLLERR) { - BOOST_ASSERT(spec.cb_err); - spec.cb_err(EV_ERR); + else if (ev.events & EPOLLERR && ! ev.events & EPOLLHUP) { + if (spec.cb_err) + spec.cb_err(EV_ERR); + else { + if (spec.cb_write) spec.cb_write(EV_ERR); + if (spec.cb_read) spec.cb_read(EV_ERR); + } } + } } diff --git a/Scheduler/Scheduler.cti b/Scheduler/Scheduler.cti index be41961..0bd2d7f 100644 --- a/Scheduler/Scheduler.cti +++ b/Scheduler/Scheduler.cti @@ -33,14 +33,16 @@ template prefix_ void satcom::lib::Scheduler::add(Handle const & handle, typename GenericCallback::Callback const & cb, - EventId eventMask) + int eventMask) { // retrieve_filehandle is found via ADL - do_add(retrieve_filehandle(handle),boost::bind(cb,handle,_1),eventMask); + SimpleCallback scb (boost::bind(cb,handle,_1)); + int fd = retrieve_filehandle(handle); + do_add(fd,scb,eventMask); } template -prefix_ void satcom::lib::Scheduler::remove(Handle const & handle, EventId eventMask) +prefix_ void satcom::lib::Scheduler::remove(Handle const & handle, int eventMask) { // retrieve_filehandle is found via ADL do_remove(retrieve_filehandle(handle),eventMask); diff --git a/Scheduler/Scheduler.hh b/Scheduler/Scheduler.hh index a535fad..6788f61 100644 --- a/Scheduler/Scheduler.hh +++ b/Scheduler/Scheduler.hh @@ -20,6 +20,8 @@ // Free Software Foundation, Inc., // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +// TODO: Fix EventId parameter (probably to int) to allow |-ing without casting ... + #ifndef HH_Scheduler_ #define HH_Scheduler_ 1 @@ -83,9 +85,9 @@ namespace lib { template void add(Handle const & handle, typename GenericCallback::Callback const & cb, - EventId eventMask = EV_ALL); + int eventMask = EV_ALL); template - void remove(Handle const & handle, EventId eventMask = EV_ALL); + void remove(Handle const & handle, int eventMask = EV_ALL); void timeout(unsigned long timeout, TimerCallback const & cb); @@ -97,8 +99,8 @@ namespace lib { private: Scheduler(); - void do_add(int fd, SimpleCallback const & cb, EventId eventMask = EV_ALL); - void do_remove(int fd, EventId eventMask = EV_ALL); + void do_add(int fd, SimpleCallback const & cb, int eventMask = EV_ALL); + void do_remove(int fd, int eventMask = EV_ALL); struct EventSpec { diff --git a/Scheduler/Scheduler.test.cc b/Scheduler/Scheduler.test.cc index 26dd7fd..6845277 100644 --- a/Scheduler/Scheduler.test.cc +++ b/Scheduler/Scheduler.test.cc @@ -190,7 +190,7 @@ namespace { bool is_close(MicroTime a, MicroTime b) { - return (a +#include "Utils/Exception.hh" +#include "Scheduler.hh" + +#define prefix_ +///////////////////////////////ct.p//////////////////////////////////////// + +template +prefix_ satcom::lib::WriteHelper::WriteHelper(Handle handle, std::string data, + Callback callback) + : handle_(handle), data_(data), callback_(callback), + offset_(0), errno_(0) +{ + satcom::lib::Scheduler::instance() + .add(handle_, boost::bind(&WriteHelper::dispatchProcess, ptr(this), _1, _2), + satcom::lib::Scheduler::EV_WRITE); +} + +template +prefix_ std::string const & satcom::lib::WriteHelper::data() + const +{ + if (offset_ > 0) { + data_.erase(0,offset_); + offset_ = 0; + } + return data_; +} + +template +prefix_ void satcom::lib::WriteHelper::revoke() +{ + ptr guard (this); // To ensure, 'this' is deleted only after this method terminates ... + satcom::lib::Scheduler::instance() + .remove(handle_, satcom::lib::Scheduler::EV_WRITE); +} + +template +prefix_ void +satcom::lib::WriteHelper::dispatchProcess(ptr helper, Handle handle, + satcom::lib::Scheduler::EventId event) +{ + // since we have a 'ptr' argument, the instance cannot be deleted + // before this method returns + return helper->process(handle,event); +} + +template +prefix_ void satcom::lib::WriteHelper::process(Handle handle, + satcom::lib::Scheduler::EventId event) +{ + try { + if (event != satcom::lib::Scheduler::EV_WRITE) + throw satcom::lib::SystemException(EPIPE); + offset_ += handle.write(data_.data()+offset_,data_.size()-offset_); + if (offset_ >= data_.size()) { + data_.erase(); + done(); + } + } + catch (satcom::lib::SystemException const & ex) { + errno_ = ex.err; + done(); + } +} + +template +prefix_ void satcom::lib::WriteHelper::done() +{ + revoke(); + callback_(ptr(this)); +} + +///////////////////////////////ct.e//////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// End: diff --git a/Scheduler/WriteHelper.cti b/Scheduler/WriteHelper.cti new file mode 100644 index 0000000..e73fd19 --- /dev/null +++ b/Scheduler/WriteHelper.cti @@ -0,0 +1,58 @@ +// $Id$ +// +// Copyright (C) 2006 + +// Definition of inline template functions + +//#include "WriteHelper.ih" + +// Custom includes +#include "Utils/Exception.hh" + +#define prefix_ inline +///////////////////////////////cti.p/////////////////////////////////////// + +template +prefix_ typename satcom::lib::WriteHelper::ptr +satcom::lib::WriteHelper::dispatch(Handle handle, std::string data, Callback callback) +{ + return ptr(new WriteHelper(handle, data, callback)); +} + +template +prefix_ Handle satcom::lib::WriteHelper::handle() + const +{ + return handle_; +} + +template +prefix_ bool satcom::lib::WriteHelper::complete() + const +{ + return data_.empty(); +} + +template +prefix_ bool satcom::lib::WriteHelper::error() + const +{ + return errno_ != 0; +} + +template +prefix_ void satcom::lib::WriteHelper::throw_error() + const +{ + if (errno_ != 0) + throw satcom::lib::SystemException(errno_); +} + + +///////////////////////////////cti.e/////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// End: diff --git a/Scheduler/WriteHelper.hh b/Scheduler/WriteHelper.hh new file mode 100644 index 0000000..02c3161 --- /dev/null +++ b/Scheduler/WriteHelper.hh @@ -0,0 +1,81 @@ +// $Id$ +// +// Copyright (C) 2006 + +#ifndef HH_WriteHelper_ +#define HH_WriteHelper_ 1 + +// Custom includes +#include +#include +#include +#include "Utils/intrusive_refcount.hh" +#include "Scheduler.hh" + +//#include "WriteHelper.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace satcom { +namespace lib { + + template + class WriteHelper + : public satcom::lib::intrusive_refcount + { + public: + /////////////////////////////////////////////////////////////////////////// + // Types + + typedef boost::intrusive_ptr ptr; + typedef boost::function Callback; + + /////////////////////////////////////////////////////////////////////////// + ///\name Structors and default members + ///@{ + + static ptr dispatch(Handle handle, std::string data, Callback callback); + + ///@} + /////////////////////////////////////////////////////////////////////////// + + Handle handle() const; + + std::string const & data() const; + + bool complete() const; + bool error() const; + void throw_error() const; + + void revoke(); + + protected: + + private: + WriteHelper(Handle handle, std::string data, Callback callback); + + static void dispatchProcess(ptr helper, Handle handle, satcom::lib::Scheduler::EventId event); + void process(Handle handle, satcom::lib::Scheduler::EventId event); + void done(); + + Handle handle_; + mutable std::string data_; + Callback callback_; + + mutable std::string::size_type offset_; + int errno_; + }; + + +}} + +///////////////////////////////hh.e//////////////////////////////////////// +//#include "WriteHelper.cci" +#include "WriteHelper.ct" +#include "WriteHelper.cti" +//#include "WriteHelper.mpp" +#endif + + +// Local Variables: +// mode: c++ +// End: diff --git a/Scheduler/WriteHelper.test.cc b/Scheduler/WriteHelper.test.cc new file mode 100644 index 0000000..7cb91df --- /dev/null +++ b/Scheduler/WriteHelper.test.cc @@ -0,0 +1,27 @@ +// $Id$ +// +// Copyright (C) 2006 + +// Unit tests + +//#include "WriteHelper.test.hh" +//#include "WriteHelper.test.ih" + +// Custom includes +#include "WriteHelper.hh" + +#include +#include + +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + + + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ + + +// Local Variables: +// mode: c++ +// End: