// @(#)root/net:$Id: TMonitor.cxx 23091 2008-04-09 15:04:27Z rdm $ // Author: Fons Rademakers 09/01/97 /************************************************************************* * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * * All rights reserved. * * * * For the licensing terms see $ROOTSYS/LICENSE. * * For the list of contributors see $ROOTSYS/README/CREDITS. * *************************************************************************/ ////////////////////////////////////////////////////////////////////////// // // // TMonitor // // // // This class monitors activity on a number of network sockets. // // The actual monitoring is done by TSystem::DispatchOneEvent(). // // Typical usage: create a TMonitor object. Register a number of // // TSocket objects and call TMonitor::Select(). Select() returns the // // socket object which has data waiting. TSocket objects can be added, // // removed, (temporary) enabled or disabled. // // // ////////////////////////////////////////////////////////////////////////// #include "TMonitor.h" #include "TSocket.h" #include "TList.h" #include "TSystem.h" #include "TSysEvtHandler.h" #include "TTimer.h" #include "TError.h" //---- Socket event handler ---------------------------------------------------- // // This utility class is only used by TMonitor. // class TSocketHandler : public TFileHandler { private: TMonitor *fMonitor; //monitor to which this handler belongs TSocket *fSocket; //socket being handled public: TSocketHandler(TMonitor *m, TSocket *s, Int_t interest, Bool_t mainloop = kTRUE); Bool_t Notify(); Bool_t ReadNotify() { return Notify(); } Bool_t WriteNotify() { return Notify(); } TSocket *GetSocket() const { return fSocket; } }; TSocketHandler::TSocketHandler(TMonitor *m, TSocket *s, Int_t interest, Bool_t mainloop) : TFileHandler(s->GetDescriptor(), interest) { //constructor fMonitor = m; fSocket = s; if (mainloop) Add(); } Bool_t TSocketHandler::Notify() { //notifier fMonitor->SetReady(fSocket); return kTRUE; } //---- Timeout timer ----------------------------------------------------------- // // This utility class is only used via TMonitor::Select(Int_t timeout) // class TTimeOutTimer : public TTimer { private: TMonitor *fMonitor; //monitor to which this timer belongs public: TTimeOutTimer(TMonitor *m, Long_t ms); Bool_t Notify(); }; TTimeOutTimer::TTimeOutTimer(TMonitor *m, Long_t ms) : TTimer(ms, kTRUE) { //constructor fMonitor = m; gSystem->AddTimer(this); } Bool_t TTimeOutTimer::Notify() { //notifier fMonitor->SetReady((TSocket *)-1); Remove(); // one shot only return kTRUE; } //------------------------------------------------------------------------------ ClassImp(TMonitor) //______________________________________________________________________________ TMonitor::TMonitor(Bool_t mainloop) { // Create a monitor object. If mainloop is true the monitoring will be // done in the main event loop. R__ASSERT(gSystem); fActive = new TList; fDeActive = new TList; fMainLoop = mainloop; fInterrupt = kFALSE; } //______________________________________________________________________________ TMonitor::~TMonitor() { // Cleanup the monitor object. Does not delete socket being monitored. fActive->Delete(); SafeDelete(fActive); fDeActive->Delete(); SafeDelete(fDeActive); } //______________________________________________________________________________ void TMonitor::Add(TSocket *sock, Int_t interest) { // Add socket to the monitor's active list. If interest=kRead then we // want to monitor the socket for read readiness, if interest=kWrite // then we monitor the socket for write readiness, if interest=kRead|kWrite // then we monitor both read and write readiness. fActive->Add(new TSocketHandler(this, sock, interest, fMainLoop)); } //______________________________________________________________________________ void TMonitor::SetInterest(TSocket *sock, Int_t interest) { // Set interest mask for socket sock to interest. If the socket is not // in the active list move it or add it there. // If interest=kRead then we want to monitor the socket for read readiness, // if interest=kWrite then we monitor the socket for write readiness, // if interest=kRead|kWrite then we monitor both read and write readiness. TSocketHandler *s = 0; if (!interest) interest = kRead; // Check first the activated list ... TIter next(fActive); while ((s = (TSocketHandler *) next())) { if (sock == s->GetSocket()) { s->SetInterest(interest); return; } } // Check now the deactivated list ... TIter next1(fDeActive); while ((s = (TSocketHandler *) next1())) { if (sock == s->GetSocket()) { fDeActive->Remove(s); fActive->Add(s); s->SetInterest(interest); return; } } // The socket is not in our lists: just add it fActive->Add(new TSocketHandler(this, sock, interest, fMainLoop)); } //______________________________________________________________________________ void TMonitor::Remove(TSocket *sock) { // Remove a socket from the monitor. TIter next(fActive); TSocketHandler *s; while ((s = (TSocketHandler *) next())) { if (sock == s->GetSocket()) { fActive->Remove(s); delete s; return; } } TIter next1(fDeActive); while ((s = (TSocketHandler *) next1())) { if (sock == s->GetSocket()) { fDeActive->Remove(s); delete s; return; } } } //______________________________________________________________________________ void TMonitor::RemoveAll() { // Remove all sockets from the monitor. fActive->Delete(); fDeActive->Delete(); } //______________________________________________________________________________ void TMonitor::Activate(TSocket *sock) { // Activate a de-activated socket. TIter next(fDeActive); TSocketHandler *s; while ((s = (TSocketHandler *) next())) { if (sock == s->GetSocket()) { fDeActive->Remove(s); fActive->Add(s); s->Add(); return; } } } //______________________________________________________________________________ void TMonitor::ActivateAll() { // Activate all de-activated sockets. TIter next(fDeActive); TSocketHandler *s; while ((s = (TSocketHandler *) next())) { fActive->Add(s); s->Add(); } fDeActive->Clear(); } //______________________________________________________________________________ void TMonitor::DeActivate(TSocket *sock) { // De-activate a socket. TIter next(fActive); TSocketHandler *s; while ((s = (TSocketHandler *) next())) { if (sock == s->GetSocket()) { fActive->Remove(s); fDeActive->Add(s); s->Remove(); return; } } } //______________________________________________________________________________ void TMonitor::DeActivateAll() { // De-activate all activated sockets. TIter next(fActive); TSocketHandler *s; while ((s = (TSocketHandler *) next())) { fDeActive->Add(s); s->Remove(); } fActive->Clear(); } //______________________________________________________________________________ TSocket *TMonitor::Select() { // Return pointer to socket for which an event is waiting. // Return 0 in case of error. fInterrupt = kFALSE; fReady = 0; while (!fReady && !fInterrupt) gSystem->InnerLoop(); // Notify interrupts if (fInterrupt) { fReady = 0; Info("Select","*** interrupt occured ***"); } return fReady; } //______________________________________________________________________________ TSocket *TMonitor::Select(Long_t timeout) { // Return pointer to socket for which an event is waiting. // Wait a maximum of timeout milliseconds. // If return is due to timeout it returns (TSocket *)-1. // Return 0 in case of any other error situation. if (timeout < 0) return TMonitor::Select(); fInterrupt = kFALSE; fReady = 0; TTimeOutTimer t(this, timeout); while (!fReady && !fInterrupt) gSystem->InnerLoop(); // Notify interrupts if (fInterrupt) { fReady = 0; Info("Select","*** interrupt occured ***"); } return fReady; } //______________________________________________________________________________ Int_t TMonitor::Select(TList *rdready, TList *wrready, Long_t timeout) { // Return numbers of sockets that are ready for reading or writing. // Wait a maximum of timeout milliseconds. // Return 0 if timed-out. Return < 0 in case of error. // If rdready and/or wrready are not 0, the lists of sockets with // something to read and/or write are also returned. Int_t nr = -2; TSocketHandler *h = 0; Int_t ns = fActive->GetSize(); if (ns == 1) { // Avoid additional loops inside h = (TSocketHandler *)fActive->First(); nr = gSystem->Select((TFileHandler *)h, timeout); } else if (ns > 1) { nr = gSystem->Select(fActive, timeout); } if (nr > 0 && (rdready || wrready)) { // Clear the lists if (rdready) rdready->Clear(); if (wrready) wrready->Clear(); // Got a file descriptor if (!h) { TIter next(fActive); while ((h = (TSocketHandler *)next())) { if (rdready && h->IsReadReady()) rdready->Add(h->GetSocket()); if (wrready && h->IsWriteReady()) wrready->Add(h->GetSocket()); } } else { if (rdready && h->IsReadReady()) rdready->Add(h->GetSocket()); if (wrready && h->IsWriteReady()) wrready->Add(h->GetSocket()); } } return nr; } //______________________________________________________________________________ void TMonitor::SetReady(TSocket *sock) { // Called by TSocketHandler::Notify() to signal which socket is ready // to be read or written. User should not call this routine. The ready // socket will be returned via the Select() user function. // Ready(TSocket *sock) signal is emitted. fReady = sock; Ready(fReady); } //______________________________________________________________________________ Int_t TMonitor::GetActive() const { // Return number of sockets in the active list. return fActive->GetSize(); } //______________________________________________________________________________ Int_t TMonitor::GetDeActive() const { // Return number of sockets in the de-active list. return fDeActive->GetSize(); } //______________________________________________________________________________ Bool_t TMonitor::IsActive(TSocket *sock) const { // Check if socket 's' is in the active list. Avoids the duplication // of active list via TMonitor::GetListOfActives(). TIter next(fActive); while (TSocketHandler *h = (TSocketHandler*) next()) if (sock == h->GetSocket()) return kTRUE; // Not found return kFALSE; } //______________________________________________________________________________ TList *TMonitor::GetListOfActives() const { // Returns a list with all active sockets. This list must be deleted // by the user. DO NOT call Delete() on this list as it will delete // the sockets that are still being used by the monitor. TList *list = new TList; TIter next(fActive); while (TSocketHandler *h = (TSocketHandler*) next()) list->Add(h->GetSocket()); return list; } //______________________________________________________________________________ TList *TMonitor::GetListOfDeActives() const { // Returns a list with all de-active sockets. This list must be deleted // by the user. DO NOT call Delete() on this list as it will delete // the sockets that are still being used by the monitor. TList *list = new TList; TIter next(fDeActive); while (TSocketHandler *h = (TSocketHandler*) next()) list->Add(h->GetSocket()); return list; } //______________________________________________________________________________ void TMonitor::Ready(TSocket *sock) { // Emit signal when some socket is ready Emit("Ready(TSocket*)", (Long_t)sock); }