00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00026 #include "Daemon.hh"
00027 #include "Daemon.ih"
00028
00029
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <sys/wait.h>
00033 #include <unistd.h>
00034 #include <limits.h>
00035 #include <fcntl.h>
00036 #include <errno.h>
00037 #include <signal.h>
00038 #ifdef SENF_BACKTRACE
00039 #include <execinfo.h>
00040 #endif
00041 #include <sstream>
00042 #include <algorithm>
00043 #include <boost/algorithm/string/predicate.hpp>
00044 #include <boost/algorithm/string/trim.hpp>
00045 #include <boost/format.hpp>
00046 #include <senf/Utils/Exception.hh>
00047 #include <senf/Utils/membind.hh>
00048 #include <senf/Utils/Backtrace.hh>
00049 #include <senf/Utils/signalnames.hh>
00050
00051
00052 #include <ucontext.h>
00053
00054
00055 #define prefix_
00056
00057
00058 #define LIBC_CALL(fn, args) if (fn args < 0) \
00059 SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
00060
00061 #define LIBC_CALL_RV(var, fn, args) \
00062 int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
00063
00064
00065
00066
00067 prefix_ senf::Daemon::~Daemon()
00068 {
00069 if (pidfileCreated_) {
00070 try {
00071 LIBC_CALL( ::unlink, (pidfile_.c_str()) );
00072 } catch (Exception & e) {
00073
00074
00075 }
00076 }
00077 }
00078
00079 prefix_ void senf::Daemon::daemonize(bool v)
00080 {
00081 daemonize_ = v;
00082 }
00083
00084 prefix_ bool senf::Daemon::daemon()
00085 {
00086 return daemonize_;
00087 }
00088
00089 prefix_ int senf::Daemon::argc()
00090 {
00091 return argc_;
00092 }
00093
00094 prefix_ char const ** senf::Daemon::argv()
00095 {
00096 return argv_;
00097 }
00098
00099 namespace {
00100
00101 struct IsDaemonOpt {
00102 bool operator()(std::string const & str) const {
00103 return str == "--no-daemon"
00104 || boost::starts_with(str, std::string("--pid-file="))
00105 || boost::starts_with(str, std::string("--console-log="));
00106 }
00107 };
00108 }
00109
00110 prefix_ void senf::Daemon::removeDaemonArgs()
00111 {
00112 char const ** last (std::remove_if(argv_+1, argv_+argc_, IsDaemonOpt()));
00113 *last = 0;
00114 argc_ = last - argv_;
00115 }
00116
00117 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
00118 {
00119 switch (which) {
00120 case StdOut : stdoutLog_ = path; break;
00121 case StdErr : stderrLog_ = path; break;
00122 case Both : stdoutLog_ = path; stderrLog_ = path; break;
00123 }
00124 }
00125
00126
00127 prefix_ void senf::Daemon::openLog()
00128 {
00129 int fd (-1);
00130 if (! stdoutLog_.empty()) {
00131 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
00132 if (fd < 0)
00133 SENF_THROW_SYSTEM_EXCEPTION("")
00134 << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout.";
00135 stdout_ = fd;
00136 }
00137 if (! stderrLog_.empty()) {
00138 if (stderrLog_ == stdoutLog_) {
00139 stderr_ = ::dup(fd);
00140 if (stderr_ < 0)
00141 SENF_THROW_SYSTEM_EXCEPTION("::dup()");
00142 }
00143 else {
00144 fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
00145 if (fd < 0)
00146 SENF_THROW_SYSTEM_EXCEPTION("")
00147 << " Could not open \"" << stderrLog_ << "\" for redirecting stderr.";
00148 stderr_ = fd;
00149 }
00150 }
00151 }
00152
00153 prefix_ void senf::Daemon::logReopen()
00154 {
00155 if (! stdoutLog_.empty()) {
00156 int fd (::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
00157 if (fd < 0)
00158 goto error;
00159 if (::dup2(fd, 1) < 0)
00160 goto error;
00161 if (stderrLog_ == stdoutLog_) {
00162 if (::dup2(fd, 2) < 0)
00163 goto error;
00164 return;
00165 }
00166 }
00167 if (! stderrLog_.empty()) {
00168 int fd (::open(stderrLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
00169 if (fd < 0)
00170 goto error;
00171 if (::dup2(fd, 2) < 0)
00172 goto error;
00173 }
00174 return;
00175
00176 error:
00177 SENF_LOG(
00178 (senf::log::CRITICAL)
00179 ("log-file reopen failed: (" << errno << ") " << ::strerror(errno)) );
00180 }
00181
00182 prefix_ void senf::Daemon::pidFile(std::string const & f)
00183 {
00184 pidfile_ = f;
00185 }
00186
00187 namespace {
00188 bool signaled (false);
00189 void waitusr(int) {
00190 signaled = true;
00191 }
00192 }
00193
00194 prefix_ void senf::Daemon::detach()
00195 {
00196 if (daemonize_ && ! detached_) {
00197
00198
00199
00200
00201
00202
00203 ::sigset_t oldsig;
00204 ::sigset_t usrsig;
00205 ::sigemptyset(&usrsig);
00206 LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
00207 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
00208 struct ::sigaction oldact;
00209 struct ::sigaction usract;
00210 ::memset(&usract, 0, sizeof(usract));
00211 usract.sa_handler = &waitusr;
00212 LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
00213 ::sigset_t waitsig (oldsig);
00214 LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
00215
00216 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
00217 LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
00218 LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
00219 LIBC_CALL( ::close, (nul) );
00220
00221 signaled = false;
00222 while (! signaled) {
00223 ::sigsuspend(&waitsig);
00224 if (errno != EINTR)
00225 SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()");
00226 }
00227
00228 LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
00229 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
00230
00231 detached_ = true;
00232 }
00233 }
00234
00235 namespace {
00236
00237 struct DaemonExitException {
00238 DaemonExitException(unsigned c) : code(c) {}
00239 unsigned code;
00240 };
00241 }
00242
00243 prefix_ void senf::Daemon::exit(unsigned code)
00244 {
00245 throw DaemonExitException(code);
00246 }
00247
00248 prefix_ int senf::Daemon::start(int argc, char const ** argv)
00249 {
00250 argc_ = argc;
00251 argv_ = argv;
00252
00253 try {
00254 configure();
00255
00256 if (daemonize_) {
00257 openLog();
00258 fork();
00259 }
00260 installSighandlers();
00261 if (! pidfile_.empty()) {
00262 if (pidfileCreate())
00263 pidfileCreated_ = true;
00264 else {
00265 std::cerr << "PID file '" << pidfile_
00266 << "' creation failed. Daemon running ?" << std::endl;
00267 return 1;
00268 }
00269 }
00270
00271 main();
00272 }
00273 catch (DaemonExitException & e) {
00274 return e.code;
00275 }
00276
00277 #ifndef SENF_DEBUG
00278
00279 catch (std::exception & e) {
00280 std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl;
00281 return 1;
00282 }
00283 catch (...) {
00284 std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl;
00285 return 1;
00286 }
00287
00288 # endif
00289
00290 return 0;
00291 }
00292
00293 prefix_ senf::Daemon & senf::Daemon::instance()
00294 {
00295 BOOST_ASSERT( instance_ );
00296 return *instance_;
00297 }
00298
00299
00300
00301
00302 prefix_ senf::Daemon::Daemon()
00303 : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
00304 pidfileCreated_(false), detached_(false)
00305 {
00306 BOOST_ASSERT( ! instance_ );
00307 instance_ = this;
00308 }
00309
00310 senf::Daemon * senf::Daemon::instance_ (0);
00311
00312
00313
00314
00315 prefix_ void senf::Daemon::configure()
00316 {
00317
00318 for (int i (1); i<argc_; ++i) {
00319 std::string argv (argv_[i]);
00320 if (argv == "--no-daemon")
00321 daemonize(false);
00322 else if (boost::starts_with(argv, "--console-log=")) {
00323 std::string arg (argv.substr(14u));
00324 std::string::size_type komma (arg.find(','));
00325 if (komma == std::string::npos) {
00326 boost::trim(arg);
00327 if (arg == std::string("none")) consoleLog("");
00328 else if (!arg.empty()) consoleLog(arg);
00329 } else {
00330 std::string arg1 (arg,0,komma);
00331 std::string arg2 (arg,komma+1);
00332 boost::trim(arg1);
00333 boost::trim(arg2);
00334 if (arg1 == std::string("none")) consoleLog("",StdOut);
00335 else if (! arg1.empty() ) consoleLog(arg1, StdOut);
00336 if (arg2 == std::string("none")) consoleLog("",StdErr);
00337 else if (! arg2.empty() ) consoleLog(arg2, StdErr);
00338 }
00339 }
00340 else if (boost::starts_with(argv, "--pid-file="))
00341 pidFile(std::string(std::string(argv_[i]), 11u));
00342 }
00343 }
00344
00345 prefix_ void senf::Daemon::main()
00346 {
00347 init();
00348 detach();
00349 run();
00350 }
00351
00352 prefix_ void senf::Daemon::init()
00353 {}
00354
00355 prefix_ void senf::Daemon::run()
00356 {}
00357
00358 prefix_ void senf::Daemon::fork()
00359 {
00360 int coutpipe[2];
00361 int cerrpipe[2];
00362
00363 LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
00364 LIBC_CALL( ::dup2, (nul, 0) );
00365 LIBC_CALL( ::close, (nul) );
00366 LIBC_CALL( ::pipe, (coutpipe) );
00367 LIBC_CALL( ::pipe, (cerrpipe) );
00368
00369
00370
00371 ::sigset_t oldsig;
00372 ::sigset_t cldsig;
00373 ::sigemptyset(&cldsig);
00374 LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
00375 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
00376
00377 if (! senf::scheduler::empty() ) {
00378 std::cerr <<
00379 "\n"
00380 "*** WARNING ***\n"
00381 "Scheduler not empty before fork(). THIS MUST NOT HAPPEN.\n"
00382 "The scheduler will be reinitialized by the fork() and lose all registrations.\n\n";
00383 senf::scheduler::detail::EventManager::instance().listEvents(std::cerr);
00384 std::cerr <<
00385 "\n*** WARNING ***\n"
00386 "\n";
00387 }
00388
00389 LIBC_CALL_RV( pid, ::fork, () );
00390
00391 if (pid == 0) {
00392
00393
00394 LIBC_CALL( ::dup2, (coutpipe[1],1) );
00395 LIBC_CALL( ::dup2, (cerrpipe[1],2) );
00396 LIBC_CALL( ::close, (coutpipe[0]) );
00397 LIBC_CALL( ::close, (coutpipe[1]) );
00398 LIBC_CALL( ::close, (cerrpipe[0]) );
00399 LIBC_CALL( ::close, (cerrpipe[1]) );
00400 LIBC_CALL( ::setsid, () );
00401 LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
00402
00403 senf::scheduler::restart();
00404 return;
00405 }
00406
00407
00408 pidfile_ = "";
00409
00410 LIBC_CALL( ::close, (coutpipe[1]) );
00411 LIBC_CALL( ::close, (cerrpipe[1]) );
00412
00413 senf::scheduler::restart();
00414
00415 detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
00416 watcher.run();
00417
00418 ::_exit(0);
00419 }
00420
00421 prefix_ bool senf::Daemon::pidfileCreate()
00422 {
00423
00424
00425
00426
00427 std::string tempname;
00428 boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\".");
00429
00430 {
00431 char hostname[HOST_NAME_MAX+1];
00432 LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
00433 hostname[HOST_NAME_MAX] = 0;
00434 std::stringstream tempname_s;
00435 tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
00436 tempname = tempname_s.str();
00437 }
00438
00439 while (1) {
00440 {
00441 std::ofstream pidf (tempname.c_str());
00442 if (! pidf)
00443 SENF_THROW_SYSTEM_EXCEPTION("")
00444 << " Could not open pidfile \"" << tempname << "\" for output.";
00445 pidf << ::getpid() << std::endl;
00446 if (! pidf)
00447 SENF_THROW_SYSTEM_EXCEPTION("")
00448 << " Could not write to pidfile \"" << tempname << "\".";
00449 }
00450
00451 if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
00452 if (errno != EEXIST)
00453 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname;
00454 }
00455 else {
00456 struct ::stat s;
00457 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
00458 LIBC_CALL( ::unlink, (tempname.c_str()) );
00459 return s.st_nlink == 2;
00460 }
00461
00462
00463 {
00464 int old_pid (-1);
00465 std::ifstream pidf (pidfile_.c_str());
00466 if ( ! (pidf >> old_pid)
00467 || old_pid < 0
00468 || ::kill(old_pid, 0) >= 0
00469 || errno == EPERM ) {
00470 LIBC_CALL( ::unlink, (tempname.c_str()) );
00471 return false;
00472 }
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483 LIBC_CALL( ::unlink, (tempname.c_str() ));
00484 if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
00485 if (errno != ENOENT)
00486 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_;
00487
00488 continue;
00489 }
00490
00491 {
00492 struct ::stat s;
00493 LIBC_CALL( ::stat, (tempname.c_str(), &s) );
00494 if (s.st_nlink != 2) {
00495 LIBC_CALL( ::unlink, (tempname.c_str()) );
00496 return false;
00497 }
00498 }
00499
00500 {
00501 std::ofstream pidf (tempname.c_str());
00502 pidf << ::getpid() << std::endl;
00503 }
00504
00505 LIBC_CALL( ::unlink, (tempname.c_str()) );
00506 break;
00507 }
00508 return true;
00509 }
00510
00511
00512 #ifdef SENF_DEBUG
00513
00514 namespace {
00515 void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg)
00516 {
00517
00518 std::cerr << "\n" << "Signal " << senf::signalName(sig) << '(' << sig << ')'
00519 << " received\n";
00520
00521 if (sig == SIGSEGV)
00522 std::cerr << "Invalid memory access at " << info->si_addr << "\n";
00523 #ifdef SENF_BACKTRACE
00524 static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
00525 int nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
00526
00527
00528
00529
00530 std::cerr << "Backtrace:\n";
00531 senf::formatBacktrace(std::cerr, entries, nEntries);
00532 std::cerr << "-- \n";
00533 #endif //SENF_BACKTRACE
00534 if (sig != SIGUSR2) {
00535 ::signal(sig, SIG_DFL);
00536 ::kill(::getpid(), sig);
00537 }
00538 }
00539
00540 }
00541
00542 #endif // SENF_DEBUG
00543
00544 namespace {
00545 void sighupHandler(int sig)
00546 {
00547 senf::Daemon::instance().logReopen();
00548 }
00549 }
00550
00551 prefix_ void senf::Daemon::installSighandlers()
00552 {
00553 struct ::sigaction sa;
00554
00555 ::sigemptyset(&sa.sa_mask);
00556 sa.sa_handler = &sighupHandler;
00557 sa.sa_flags = SA_RESTART;
00558
00559 ::sigaction(SIGHUP, &sa, NULL);
00560
00561 sa.sa_handler = SIG_IGN;
00562 ::sigaction(SIGPIPE, &sa, NULL);
00563
00564 #ifdef SENF_DEBUG
00565 sa.sa_sigaction = &fatalSignalsHandler;
00566 sa.sa_flags = SA_RESTART | SA_SIGINFO;
00567
00568 ::sigaction(SIGILL, &sa, NULL);
00569 ::sigaction(SIGTRAP, &sa, NULL);
00570 ::sigaction(SIGABRT, &sa, NULL);
00571 ::sigaction(SIGFPE, &sa, NULL);
00572 ::sigaction(SIGBUS, &sa, NULL);
00573 ::sigaction(SIGSEGV, &sa, NULL);
00574 #ifdef SIGSTKFLT //SIGSTKFLT is used for stack faults on coprocessors. That condition doesn't exist on MIPS
00575 ::sigaction(SIGSTKFLT, &sa, NULL);
00576 #endif
00577 ::sigaction(SIGSYS, &sa, NULL);
00578 ::sigaction(SIGUSR2, &sa, NULL);
00579 #endif
00580 }
00581
00582
00583
00584
00585 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
00586 int stdout, int stderr)
00587 : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
00588 stderr_(stderr), sigChld_(false),
00589 cldSignal_ (SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)),
00590 timer_ ("senf::detail::DaemonWatcher::childOk", senf::membind(&DaemonWatcher::childOk, this)),
00591 coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
00592 cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
00593 {
00594 coutForwarder_.addTarget(1);
00595 if (stdout_ >= 0)
00596 coutForwarder_.addTarget(stdout_);
00597 cerrForwarder_.addTarget(2);
00598 if (stderr_ >= 0)
00599 cerrForwarder_.addTarget(stderr_);
00600 }
00601
00602 prefix_ void senf::detail::DaemonWatcher::run()
00603 {
00604 scheduler::process();
00605 }
00606
00607
00608
00609
00610 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
00611 {
00612 switch (id) {
00613 case 1 : coutpipe_ = -1; break;
00614 case 2 : cerrpipe_ = -1; break;
00615 }
00616
00617 if (coutpipe_ == -1 && cerrpipe_ == -1) {
00618 if (sigChld_)
00619 childDied();
00620 if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH)
00621 SENF_THROW_SYSTEM_EXCEPTION("::kill()");
00622 timer_.timeout(scheduler::eventTime() + ClockService::seconds(1));
00623 }
00624 }
00625
00626 prefix_ void senf::detail::DaemonWatcher::sigChld(siginfo_t const &)
00627 {
00628 sigChld_ = true;
00629 if (coutpipe_ == -1 && cerrpipe_ == -1)
00630 childDied();
00631 }
00632
00633 prefix_ void senf::detail::DaemonWatcher::childDied()
00634 {
00635 int status (0);
00636 if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
00637 if (WIFSIGNALED(status)) {
00638 ::signal(WTERMSIG(status),SIG_DFL);
00639 ::kill(::getpid(), WTERMSIG(status));
00640
00641 ::_exit(126);
00642 }
00643 if (WEXITSTATUS(status) == 0)
00644 ::_exit(127);
00645 ::_exit(WEXITSTATUS(status));
00646 }
00647
00648 prefix_ void senf::detail::DaemonWatcher::childOk()
00649 {
00650 scheduler::terminate();
00651 }
00652
00653
00654
00655
00656 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
00657 : src_(src), cb_(cb),
00658 readevent_("senf::detail::DaemonWatcher::Forwarder::readevent", senf::membind(&Forwarder::readData, this),
00659 src_, scheduler::FdEvent::EV_READ)
00660 {}
00661
00662 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
00663 {
00664 targets_.clear_and_destroy(DestroyDelete());
00665 }
00666
00667 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
00668 {
00669 targets_.push_back(*(new Target(*this, fd)));
00670 }
00671
00672 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(int event)
00673 {
00674 char buf[1024];
00675 int n (0);
00676
00677 while (1) {
00678 n = ::read(src_,buf,1024);
00679 if (n<0) {
00680 if (errno != EINTR)
00681 SENF_THROW_SYSTEM_EXCEPTION("::read()");
00682 }
00683 else
00684 break;
00685 }
00686
00687 if (n == 0) {
00688 if (buffer_.empty())
00689 cb_();
00690 src_ = -1;
00691 readevent_.disable();
00692 return;
00693 }
00694
00695 if (targets_.empty())
00696 return;
00697
00698 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
00699 if (i->offset >= buffer_.size())
00700 i->writeevent.enable();
00701
00702 buffer_.insert(buffer_.end(), buf, buf+n);
00703 }
00704
00705 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(int event, Target * target)
00706 {
00707 if (event != scheduler::FdEvent::EV_WRITE) {
00708
00709 targets_.erase_and_destroy(Targets::current(*target),DestroyDelete());
00710 if (targets_.empty() && src_ == -1)
00711 cb_();
00712 return;
00713 }
00714
00715 char buf[1024];
00716 int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
00717 std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
00718
00719 int w (::write(target->fd, buf, n));
00720 if (w < 0) {
00721 if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
00722 return;
00723 }
00724 target->offset += w;
00725
00726 n = std::min_element(
00727 targets_.begin(), targets_.end(),
00728 boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
00729
00730 buffer_.erase(buffer_.begin(), buffer_.begin()+n);
00731
00732 for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
00733 i->offset -= n;
00734
00735 if (target->offset >= buffer_.size())
00736 target->writeevent.disable();
00737 if (src_ == -1 && (buffer_.empty() || targets_.empty()))
00738 cb_();
00739 }
00740
00741 #undef LIBC_CALL
00742 #undef LIBC_CALL_RV
00743
00744
00745 #undef prefix_
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756
00757