OpenCores
URL https://opencores.org/ocsvn/w11/w11/trunk

Subversion Repositories w11

[/] [w11/] [tags/] [w11a_V0.61/] [tools/] [src/] [librlink/] [ReventLoop.cpp] - Rev 40

Go to most recent revision | Compare with Previous | Blame | View Log

// $Id: ReventLoop.cpp 511 2013-04-27 13:51:46Z mueller $
//
// Copyright 2013- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
//
// This program is free software; you may redistribute and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 2, or at your option any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for complete details.
// 
// Revision History: 
// Date         Rev Version  Comment
// 2013-04-27   511   1.1.3  BUGFIX: logic in DoCall() fixed (loop range)
// 2013-03-05   495   1.1.2  add exception catcher to EventLoop
// 2013-03-01   493   1.1.1  DoCall(): remove handler on negative return
// 2013-02-22   491   1.1    use new RlogFile/RlogMsg interfaces
// 2013-01-11   473   1.0    Initial version
// ---------------------------------------------------------------------------
 
/*!
  \file
  \version $Id: ReventLoop.cpp 511 2013-04-27 13:51:46Z mueller $
  \brief   Implemenation of class ReventLoop.
*/
 
#include <string.h>
#include <poll.h>
#include <errno.h>
 
#include "boost/bind.hpp" 
#include "boost/thread/locks.hpp"
 
#include "librtools/Rexception.hpp"
#include "librtools/RosPrintf.hpp"
#include "librtools/RosFill.hpp"
#include "librtools/RlogMsg.hpp"
 
#include "ReventLoop.hpp"
 
using namespace std;
 
/*!
  \class Retro::ReventLoop
  \brief FIXME_docs
*/
 
// all method definitions in namespace Retro
namespace Retro {
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
ReventLoop::ReventLoop()
  : fLoopActive(false),
    fUpdatePoll(false),
    fPollDscMutex(),
    fPollDsc(),
    fPollFd(),
    fPollHdl(),
    fTraceLevel(0),
    fspLog()
{}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
ReventLoop::~ReventLoop()
{}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
// by default handlers should start with: 
//     if (pfd.revents & (~pfd.events)) return -1;
 
void ReventLoop::AddPollHandler(const pollhdl_t& pollhdl,
                                int fd, short events)
{
  boost::lock_guard<boost::mutex> lock(fPollDscMutex);
 
  for (size_t i=0; i<fPollDsc.size(); i++) {
    if (fPollDsc[i].fFd     == fd &&
        fPollDsc[i].fEvents == events) {
      throw Rexception("ReventLoop::AddPollHandler()", 
                       "Bad args: duplicate handler");
    }
  }
 
  fPollDsc.push_back(PollDsc(pollhdl,fd,events));
  fUpdatePoll = true;
 
  if (fspLog && fTraceLevel >= 1) {
    RlogMsg lmsg(*fspLog, 'I');
    lmsg << "eloop: add handler: " << fd << "," << RosPrintf(events,"x");
  }
 
  return;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
void ReventLoop::RemovePollHandler(int fd, short events, bool nothrow)
{
  boost::lock_guard<boost::mutex> lock(fPollDscMutex);
 
  for (size_t i=0; i<fPollDsc.size(); i++) {
    if (fPollDsc[i].fFd     == fd &&
        fPollDsc[i].fEvents == events) {
      fPollDsc.erase(fPollDsc.begin()+i);
      fUpdatePoll = true;
      if (fspLog && fTraceLevel >= 1) {
        RlogMsg lmsg(*fspLog, 'I');
        lmsg << "eloop: remove handler: " << fd << "," << RosPrintf(events,"x");
      }
      return;
    }
  }
  if (!nothrow) throw Rexception("ReventLoop::RemovePollHandler()", 
                                 "Bad args: unknown handler");
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
bool ReventLoop::TestPollHandler(int fd, short events)
{
  boost::lock_guard<boost::mutex> lock(fPollDscMutex);
 
  for (size_t i=0; i<fPollDsc.size(); i++) {
    if (fPollDsc[i].fFd     == fd &&
        fPollDsc[i].fEvents == events) {
      return true;
    }
  }
  return false;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
void ReventLoop::RemovePollHandler(int fd)
{
  boost::lock_guard<boost::mutex> lock(fPollDscMutex);
 
  for (size_t i=0; i<fPollDsc.size(); i++) {
    if (fPollDsc[i].fFd == fd) {
      fPollDsc.erase(fPollDsc.begin()+i);
      fUpdatePoll = true;
      i--;                                  // re-probe this index
    }
  }
  return;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
void ReventLoop::EventLoop()
{
  fLoopActive = true;
  fUpdatePoll = true;
 
  try {
    while (fLoopActive) {   
      int irc = DoPoll();
      if (fPollFd.size() == 0) break;
      if (irc>0) DoCall();
    }
  } catch (exception& e) {
    if (fspLog) {
      RlogMsg lmsg(*fspLog, 'F');
      lmsg << "eloop: crashed with exception: " << e.what();
    }
    return; 
  }
 
  return;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
void ReventLoop::Dump(std::ostream& os, int ind, const char* text) const
{
  RosFill bl(ind);
  os << bl << (text?text:"--") << "ReventLoop @ " << this << endl;
  os << bl << "  fLoopActive:     " << fLoopActive << endl;
  os << bl << "  fUpdatePoll:     " << fUpdatePoll << endl;
  {
    boost::lock_guard<boost::mutex> lock(((ReventLoop*)this)->fPollDscMutex);
    os << bl << "  fPollDsc.size    " << fPollDsc.size() << endl;
    os << bl << "  fPollFd.size     " << fPollFd.size()  << endl;
    os << bl << "  fPollHdl.size    " << fPollHdl.size() << endl;
    for (size_t i=0; i<fPollDsc.size(); i++) {
      os << bl << "    [" << RosPrintf(i,"d",3) << "]:"
         << " fd:" << RosPrintf(fPollDsc[i].fFd,"d",3)
         << " evt:" << RosPrintf(fPollDsc[i].fEvents,"x",2)
         << " hdl:" << (bool)fPollDsc[i].fHandler
         << endl;
    }
  }
  os << bl << "  fTraveLevel:     " << fTraceLevel << endl;
  os << bl << "  fspLog:          " << fspLog.get() << endl;
 
  return;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
int ReventLoop::DoPoll(int timeout)
{
  if (fUpdatePoll) {
    boost::lock_guard<boost::mutex> lock(fPollDscMutex);
 
    fPollFd.resize(fPollDsc.size());
    fPollHdl.resize(fPollDsc.size());
    for (size_t i=0; i<fPollDsc.size(); i++) {
      fPollFd[i].fd      = fPollDsc[i].fFd;
      fPollFd[i].events  = fPollDsc[i].fEvents;
      fPollFd[i].revents = 0;
      fPollHdl[i] = fPollDsc[i].fHandler;
    }
    fUpdatePoll = false;
 
    if (fspLog && fTraceLevel >= 1) {
      RlogMsg lmsg(*fspLog, 'I');
      lmsg << "eloop: redo pollfd list, size=" << fPollDsc.size() << endl;
    }
  }
 
  if (fPollFd.size() == 0) return 0;
 
  int irc = poll(fPollFd.data(), fPollFd.size(), timeout);
  if (irc < 0 && errno == EINTR) return 0;
  if (irc < 0) 
    throw Rexception("ReventLoop::EventLoop()", "poll() failed: ", errno);
 
  if (fspLog && fTraceLevel >= 2) {
    RlogMsg lmsg(*fspLog, 'I');
    lmsg << "eloop: poll(): ";
    for (size_t i=0; i<fPollFd.size(); i++) {
      if (fPollFd[i].revents == 0) continue;
      lmsg << " (" << fPollFd[i].fd 
           << "," << RosPrintf(fPollFd[i].events,"x") 
           << "," << RosPrintf(fPollFd[i].revents,"x") << ")";
    }
  }
 
  return irc;
}
 
//------------------------------------------+-----------------------------------
//! FIXME_docs
 
void ReventLoop::DoCall(void)
{
  for (size_t i=0; i<fPollFd.size(); i++) {
    if (fPollFd[i].revents) {      
      int irc = fPollHdl[i](fPollFd[i]);
      // remove handler negative return (nothrow=true to prevent remove race)
      if (irc < 0) {
        if (fspLog && fTraceLevel >= 1) {
          RlogMsg lmsg(*fspLog, 'I');
          lmsg << "eloop: handler(" << fPollFd[i].fd 
               << "," << RosPrintf(fPollFd[i].events,"x")
               << ") got " << RosPrintf(fPollFd[i].revents,"x")
               << " and requested removal";
        }
        RemovePollHandler(fPollFd[i].fd, fPollFd[i].events, true);
      }
    }
  }
  return;
}
 
} // end namespace Retro
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.