00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef __GNUG__
00024 # pragma implementation "UnixEventPoll.h"
00025 #endif
00026
00027 #include "UniEvent/UnixEventPoll.h"
00028 #include "UniEvent/EventPtr.h"
00029 #include "UniEvent/Dispatcher.h"
00030 #include "UniEvent/UNIXError.h"
00031 #include <LCore/LCoreError.h>
00032 #include <utility>
00033 #include <map>
00034 #include <vector>
00035 #include <list>
00036 #include <iostream>
00037 #include <iomanip>
00038 #include <cerrno>
00039 #include <stdexcept>
00040 #include <sys/poll.h>
00041 #include <sys/time.h>
00042 #include <signal.h>
00043 #include <unistd.h>
00044
00045 typedef struct sigaction i_sigaction;
00046
00047 namespace strmod {
00048 namespace unievent {
00049
00050 const UNEVT_ClassIdent UnixEventPoll::identifier(15UL);
00051
00052 typedef UnixEventPoll::FDCondSet FDCondSet;
00053 typedef i_sigaction local_sigaction;
00054
00055 namespace {
00056
00057 struct pollstruct : public ::pollfd
00058 {
00059 pollstruct(int cfd, short cevents, short crevents) {
00060 fd = cfd;
00061 events = cevents;
00062 revents = crevents;
00063 }
00064 };
00065 struct FDEvent {
00066 EventPtr ev_;
00067 FDCondSet condset_;
00068
00069 FDEvent(const EventPtr ev, const FDCondSet &condset)
00070 : ev_(ev), condset_(condset) { }
00071 };
00072
00073 using ::std::multimap;
00074 using ::std::vector;
00075 typedef multimap<int, FDEvent> FDMap;
00076 typedef vector<pollstruct> PollList;
00077
00078
00079 typedef std::list<EventPtr> sigevtlist;
00080 struct sigdata
00081 {
00082 bool handler_registered_;
00083 sigevtlist events_;
00084
00085 sigdata() : handler_registered_(false) { }
00086 };
00087 typedef std::vector<sigdata> siglist;
00088
00089 struct UnixEventPoll::Imp
00090 {
00091 FDMap fdmap_;
00092 PollList polllist_;
00093
00094 sigset_t caught_;
00095 sigset_t handled_;
00096 sig_atomic_t sigoccurred_;
00097 siglist hdlrinfo_;
00098
00099 Imp() : sigoccurred_(false)
00100 {
00101 sigemptyset(&caught_);
00102 sigemptyset(&handled_);
00103 }
00104 };
00105
00106
00107
00108
00109
00110 class SigBlockRegion
00111 {
00112 public:
00113
00114
00115
00116
00117 SigBlockRegion(sigset_t &blockedones)
00118 {
00119 sigprocmask(SIG_BLOCK, &blockedones, &oldset_);
00120 }
00121
00122
00123 ~SigBlockRegion()
00124 {
00125 sigprocmask(SIG_SETMASK, &oldset_, 0);
00126 }
00127
00128 private:
00129 sigset_t oldset_;
00130
00131 SigBlockRegion(const SigBlockRegion &b);
00132 void operator =(const SigBlockRegion &b);
00133 };
00134
00135 }
00136
00137 UnixEventPoll::UnixEventPoll(Dispatcher *dispatcher)
00138 : impl_(*(new Imp)), dispatcher_(dispatcher)
00139 {
00140 }
00141
00142 UnixEventPoll::~UnixEventPoll()
00143 {
00144 }
00145
00146 void UnixEventPoll::registerFDCond(int fd,
00147 const FDCondSet &condbits,
00148 const EventPtr &ev)
00149 {
00150 impl_.fdmap_.insert(FDMap::value_type(fd, FDEvent(ev, condbits)));
00151 }
00152
00153 void UnixEventPoll::freeFD(int fd)
00154 {
00155 impl_.fdmap_.erase(fd);
00156 }
00157
00158
00159
00160
00161
00162 void UnixEventPoll::onSignal(int signo, const EventPtr &e)
00163 {
00164 unsigned int usigno = (signo < 0) ? ~0U : signo;
00165 if ((usigno >= (sizeof(sigset_t) * 8)) ||
00166 (usigno >= max_handled_by_S))
00167 {
00168 throw std::range_error("signo is too large in UNIXSignalHandler::onSignal");
00169 }
00170 else
00171 {
00172 if (impl_.hdlrinfo_.size() <= usigno)
00173 {
00174 impl_.hdlrinfo_.resize(usigno + 1);
00175 }
00176 sigdata &sighdlrinfo = impl_.hdlrinfo_[usigno];
00177 if (!sighdlrinfo.handler_registered_)
00178 {
00179 if (handled_by_S[usigno] && (handled_by_S[usigno] != this))
00180 {
00181 throw std::logic_error("Another handler is handling this signal in UnixEventPoll::onSignal");
00182 }
00183 handleSignal(usigno);
00184 sighdlrinfo.handler_registered_ = true;
00185 }
00186 sighdlrinfo.events_.push_back(e);
00187 }
00188 }
00189
00190 namespace {
00191 class equal_evtptr
00192 {
00193 public:
00194 equal_evtptr(const EventPtr &compptr) : compptr_(compptr) { }
00195 bool operator ()(const EventPtr &evtptr) {
00196 return evtptr.GetPtr() == compptr_.GetPtr();
00197 }
00198
00199 private:
00200 const EventPtr &compptr_;
00201 };
00202 }
00203
00204 void UnixEventPoll::clearSignal(int signo, const EventPtr &e)
00205 {
00206 unsigned int usigno = (signo < 0) ? ~0U : signo;
00207 if ((usigno >= (sizeof(sigset_t) * 8)) ||
00208 (usigno >= max_handled_by_S))
00209 {
00210 throw std::range_error("signo is too large in UNIXSignalHandler::clearSignal(int, const EventPtr &)");
00211 }
00212 else if (impl_.hdlrinfo_.size() > usigno)
00213 {
00214 sigdata &sd = impl_.hdlrinfo_[usigno];
00215 sd.events_.remove_if(equal_evtptr(e));
00216 if (sd.events_.size() <= 0)
00217 {
00218 unHandleSignal(signo);
00219 sd.handler_registered_ = false;
00220 }
00221 }
00222 }
00223
00224 void UnixEventPoll::clearSignal(int signo)
00225 {
00226 unsigned int usigno = (signo < 0) ? ~0U : signo;
00227 if ((usigno >= (sizeof(sigset_t) * 8)) ||
00228 (usigno >= max_handled_by_S))
00229 {
00230 throw std::range_error("signo is too large in UNIXSignalHandler::clearSignal(int)");
00231 }
00232 else if (impl_.hdlrinfo_.size() > usigno)
00233 {
00234 sigdata &sd = impl_.hdlrinfo_[usigno];
00235 if (sd.handler_registered_)
00236 {
00237 sd.events_.clear();
00238 unHandleSignal(signo);
00239 impl_.hdlrinfo_[usigno].handler_registered_ = false;
00240 }
00241 }
00242 }
00243
00244 namespace {
00245 inline short condmask_to_pollmask(const FDCondSet &condset)
00246 {
00247 short pollmask = 0;
00248
00249 if (condset.test(UnixEventRegistry::FD_Readable))
00250 {
00251 pollmask |= POLLIN;
00252 }
00253 if (condset.test(UnixEventRegistry::FD_Writeable))
00254 {
00255 pollmask |= POLLOUT;
00256 }
00257 if (condset.test(UnixEventRegistry::FD_Error))
00258 {
00259 pollmask |= POLLERR;
00260 }
00261 if (condset.test(UnixEventRegistry::FD_Closed))
00262 {
00263 pollmask |= POLLHUP;
00264 }
00265 if (condset.test(UnixEventRegistry::FD_Invalid))
00266 {
00267 pollmask |= POLLNVAL;
00268 }
00269 return pollmask;
00270 }
00271
00272 inline const FDCondSet pollmask_to_condmask(short pollmask)
00273 {
00274 FDCondSet condset;
00275
00276 if (pollmask & POLLIN)
00277 {
00278 condset.set(UnixEventRegistry::FD_Readable);
00279 }
00280 if (pollmask & POLLOUT)
00281 {
00282 condset.set(UnixEventRegistry::FD_Writeable);
00283 }
00284 if (pollmask & POLLERR)
00285 {
00286 condset.set(UnixEventRegistry::FD_Error);
00287 }
00288 if (pollmask & POLLHUP)
00289 {
00290 condset.set(UnixEventRegistry::FD_Closed);
00291 }
00292 if (pollmask & POLLNVAL)
00293 {
00294 condset.set(UnixEventRegistry::FD_Invalid);
00295 }
00296 return condset;
00297 }
00298 }
00299
00300 void UnixEventPoll::doPoll(bool wait)
00301 {
00302 impl_.polllist_.clear();
00303 {
00304 const FDMap::iterator end = impl_.fdmap_.end();
00305 for (FDMap::iterator i = impl_.fdmap_.begin(); i != end; )
00306 {
00307 const int curfd = i->first;
00308 FDCondSet condset;
00309 for (; (i != end) && (curfd == i->first); ++i)
00310 {
00311 FDEvent &fdev = i->second;
00312 condset |= fdev.condset_;
00313 }
00314 impl_.polllist_.push_back(pollstruct(curfd,
00315 condmask_to_pollmask(condset),
00316 0));
00317 }
00318 }
00319 int myerrno = 0;
00320 int pollresult = 0;
00321 do {
00322 if (postSigEvents())
00323 {
00324 wait = false;
00325 }
00326 if (wait)
00327 {
00328 const absolute_t curtime = currentTime();
00329
00330 interval_t waittil = nextExpirationIn(curtime, interval_t(1073741));
00331 int polltimeout = (waittil.seconds * 1000U) +
00332 (waittil.nanoseconds / 1000000U);
00333 pollresult = ::poll(&(impl_.polllist_[0]), impl_.polllist_.size(),
00334 polltimeout);
00335 myerrno = UNIXError::getErrno();
00336 }
00337 else
00338 {
00339 pollresult = ::poll(&(impl_.polllist_[0]), impl_.polllist_.size(), 0);
00340 myerrno = UNIXError::getErrno();
00341 }
00342 postExpired(currentTime(), dispatcher_);
00343 if (pollresult >= 0)
00344 {
00345 const PollList::iterator end = impl_.polllist_.end();
00346 PollList::iterator i = impl_.polllist_.begin();
00347 while ((pollresult > 0) && (i != end))
00348 {
00349 const pollstruct &pollval = *i;
00350 if (pollval.revents)
00351 {
00352 const FDCondSet condset = pollmask_to_condmask(pollval.revents);
00353 const FDCondSet badset(FD_Closed, FD_Invalid);
00354 --pollresult;
00355 FDMap::iterator fdcur = impl_.fdmap_.lower_bound(pollval.fd);
00356 const FDMap::iterator fdend = impl_.fdmap_.upper_bound(pollval.fd);
00357 while (fdcur != fdend)
00358 {
00359 const FDEvent &curfdev = fdcur->second;
00360 if (condset & curfdev.condset_)
00361 {
00362 dispatcher_->addEvent(curfdev.ev_);
00363 impl_.fdmap_.erase(fdcur++);
00364 }
00365 else if (badset & condset)
00366 {
00367 impl_.fdmap_.erase(fdcur++);
00368 }
00369 else
00370 {
00371 ++fdcur;
00372 }
00373 }
00374 }
00375 ++i;
00376 }
00377 }
00378 } while ((pollresult < 0) && (myerrno == EINTR));
00379 }
00380
00381 bool UnixEventPoll::invariant() const
00382 {
00383 return true;
00384 }
00385
00386 void UnixEventPoll::printState(::std::ostream &os) const
00387 {
00388 os << "UnixEventPoll(\n";
00389 const FDMap::iterator end = impl_.fdmap_.end();
00390 int prevfd = -1;
00391 for (FDMap::iterator i = impl_.fdmap_.begin(); i != end; ++i)
00392 {
00393 const int fd = i->first;
00394 const FDCondSet &condset = i->second.condset_;
00395
00396 if (fd != prevfd)
00397 {
00398 prevfd = fd;
00399 os << std::setw(4) << fd << " (";
00400 }
00401 else
00402 {
00403 os << " (";
00404 }
00405 {
00406 bool first = true;
00407 if (condset[UnixEventPoll::FD_Readable])
00408 {
00409 if (!first)
00410 {
00411 os << " | ";
00412 first = false;
00413 }
00414 os << "FD_Readable";
00415 }
00416 if (condset.test(UnixEventRegistry::FD_Writeable))
00417 {
00418 if (!first)
00419 {
00420 os << " | ";
00421 first = false;
00422 }
00423 os << "FD_Writeable";
00424 }
00425 if (condset.test(UnixEventRegistry::FD_Error))
00426 {
00427 if (!first)
00428 {
00429 os << " | ";
00430 first = false;
00431 }
00432 os << "FD_Error";
00433 }
00434 if (condset.test(UnixEventRegistry::FD_Closed))
00435 {
00436 if (!first)
00437 {
00438 os << " | ";
00439 first = false;
00440 }
00441 os << "FD_Closed";
00442 }
00443 if (condset.test(UnixEventRegistry::FD_Invalid))
00444 {
00445 if (!first)
00446 {
00447 os << " | ";
00448 first = false;
00449 }
00450 os << "FD_Invalid";
00451 }
00452 }
00453 os << ")\n";
00454 }
00455 TimerEventTracker::printState(os);
00456 os << ")";
00457 }
00458
00459 void UnixEventPoll::signalHandler(int signo)
00460 {
00461 UnixEventPoll *parent = dynamic_cast<UnixEventPoll *>(handled_by_S[signo]);
00462 if (parent)
00463 {
00464 parent->sigOccurred(signo);
00465 }
00466 else
00467 {
00468 char str[] = "UnixEventPoll::signalHandler - Got bad signal #0x00\n";
00469 str[49] = "0123456789ABCDEF"[(signo >> 8) & 0x0f];
00470 str[50] = "0123456789ABCDEF"[signo & 0x0f];
00471 ::write(2, str, sizeof(str));
00472 local_sigaction act;
00473 act.sa_handler = SIG_DFL;
00474 sigemptyset(&act.sa_mask);
00475 act.sa_flags = 0;
00476 ::sigaction(signo, &act, 0);
00477 }
00478 }
00479
00480 void UnixEventPoll::handleSignal(int signo)
00481 {
00482 local_sigaction act;
00483 act.sa_handler = signalHandler;
00484 sigemptyset(&act.sa_mask);
00485 act.sa_flags = 0;
00486 handled_by_S[signo] = this;
00487 if (::sigaction(signo, &act, 0) != 0)
00488 {
00489 const int myerrno = UNIXError::getErrno();
00490 throw UNIXError("sigaction", myerrno,
00491 lcore::LCoreError(LCORE_GET_COMPILERINFO()));
00492 }
00493 sigaddset(&impl_.handled_, signo);
00494 }
00495
00496 void UnixEventPoll::unHandleSignal(int signo)
00497 {
00498 local_sigaction act;
00499 act.sa_handler = SIG_DFL;
00500 sigemptyset(&act.sa_mask);
00501 act.sa_flags = 0;
00502 ::sigaction(signo, &act, 0);
00503 handled_by_S[signo] = 0;
00504 sigdelset(&impl_.handled_, signo);
00505 }
00506
00507 void UnixEventPoll::sigOccurred(int signo)
00508 {
00509 SigBlockRegion blocker(impl_.handled_);
00510 sigaddset(&impl_.caught_, signo);
00511 if (!impl_.sigoccurred_)
00512 {
00513 impl_.sigoccurred_ = true;
00514 }
00515 }
00516
00517 bool UnixEventPoll::postSigEvents()
00518 {
00519 sigset_t caughtnow;
00520 {
00521 SigBlockRegion blocker(impl_.handled_);
00522 if (impl_.sigoccurred_)
00523 {
00524 caughtnow = impl_.caught_;
00525 sigemptyset(&impl_.caught_);
00526 impl_.sigoccurred_ = false;
00527 }
00528 else
00529 {
00530 return false;
00531 }
00532 }
00533 bool caughtany = false;
00534 {
00535 const siglist::size_type lastel = impl_.hdlrinfo_.size();
00536 for (siglist::size_type i = 0; i != lastel; ++i)
00537 {
00538 if (sigismember(&caughtnow, i))
00539 {
00540 sigdata &thissig = impl_.hdlrinfo_[i];
00541 if (!thissig.handler_registered_)
00542 {
00543 thissig.events_.clear();
00544 }
00545 else if (thissig.events_.size() <= 0)
00546 {
00547 unHandleSignal(i);
00548 thissig.handler_registered_ = false;
00549 }
00550 else
00551 {
00552 const sigevtlist::iterator end = thissig.events_.end();
00553 for (sigevtlist::iterator i = thissig.events_.begin();
00554 i != end;
00555 ++i)
00556 {
00557 caughtany = true;
00558 dispatcher_->addEvent(*i);
00559 }
00560 }
00561 }
00562 }
00563 }
00564 return caughtany;
00565 }
00566
00567 Timer::absolute_t UnixEventPoll::currentTime() const
00568 {
00569 struct ::timeval tv;
00570 ::gettimeofday(&tv, 0);
00571 return absolute_t(tv.tv_sec, 0, tv.tv_usec * 1000U);
00572 }
00573
00574 }
00575 }