// This is based on the ROOT example program "spyserv.C" // It has been generalized to provide any object (primarily histograms) // specified by name. #include #include #include #include using namespace std; #include "DROOTHistServer.h" #ifndef __CINT__ #include #endif DROOTHistServer* groot_hist_server=NULL; //----------------------------------------------------------------- // Handle SIGHUP signals (just SIGHUP for now) //----------------------------------------------------------------- extern "C" { // Handle HUP signals void HistResetOnSIGHUP(int signum){ if(signum == SIGHUP){ if(groot_hist_server)groot_hist_server->ResetHistograms(NULL); } } } // "C" //------------------------- // DROOTHistServer //------------------------- DROOTHistServer::DROOTHistServer(int port, TDirectory *dir) { // Set port number. If no port value was passed, notify user if(port==-1){ cerr<<"Port number not set. Using 9090"<fPort = port; this->fDir = dir; fDone = false; // Initialize mutex pthread_mutex_init(&fMutex, NULL); // Launch a thread to watch for connections. We do it this way // since it the Select call takes way too much time pthread_create(&fThread_id, NULL, RootServerMonitorThread, this); // Set up to recieve HUP signals and reset histos when they occur signal(SIGHUP, HistResetOnSIGHUP); groot_hist_server = this; } //------------------------- // ~DROOTHistServer //------------------------- DROOTHistServer::~DROOTHistServer(void) { // Signal the monitor thread to end and wait for it fDone = true; void *ptr; pthread_join(fThread_id, &ptr); } //------------------------- // RootServerMonitorThread //------------------------- void* RootServerMonitorThread(void* arg) { // This is just a C-style entry point that can be called // via pthread_create and re-dispatch back to a method of // the DROOTHistServer object. DROOTHistServer *rhs = (DROOTHistServer*)arg; return rhs->MonitorThread(); } //------------------------- // MonitorThread //------------------------- void* DROOTHistServer::MonitorThread(void) { // Wait until the directory is set. We can't do anything // without it anyway and setting up the server first may // have led to seg. faults (the evidence wasn't completely // clear). while(!fDir)sleep(1); // Open a server socket looking for connections on our port Lock(); fServ = new TServerSocket(fPort, kTRUE); // Add server socket to monitor so we are notified when a client needs to be accepted fMon = new TMonitor; fMon->Add(fServ); // Create a list to contain all client connections fSockets = new TList; Unlock(); cout<Select(20); if (fSock == (TSocket*)-1)continue; // There is either a new connection or data ready to read! // Service the request. Note that RootServer was originally written to // be an EVNT routine (hence the Banks_t* argument). Now it is // called only when a request arrives. This change was implemented // to allow the roottools server to continue to respond even when // the event loop stops to wait for events. HandleRequest(); } return NULL; } //------------------------- // HandleRequest //------------------------- void DROOTHistServer::HandleRequest(void) { char request[256]; // Lock the mutex so we don't interfere with filling of histograms Lock(); // Check if this is a new connection by checking the class of the "s" object if (fSock->IsA() == TServerSocket::Class()) { // accept new connection from spy TSocket *sock = ((TServerSocket*)fSock)->Accept(); fMon->Add(sock); fSockets->Add(sock); cout<<"accepted connection from "<GetInetAddress().GetHostName()<Recv(request, sizeof(request)) <= 0) { fMon->Remove(fSock); fSockets->Remove(fSock); cout<<"closed connection from "<GetInetAddress().GetHostName()<FindObject(who); if(!object)cout<ClassName(); int size=GetObjectSize(classname, object); answer.WriteObject(object); cout<<"Sending \""<Send(answer); fSock = (TSocket*)-1; // Unlock the mutex. Unlock(); return; } //------------------------- // ListDirectory //------------------------- string DROOTHistServer::ListDirectory(TDirectory *dir) { string ls; // Loop over all objects in the directory TIter nextobject(dir->GetList()); TObject *object; while((object = (TObject*)nextobject())){ char *classname = (char*)object->ClassName(); int size=GetObjectSize(classname, object); char item[256]; sprintf(item,"%8dkB %s %s\n",size, classname, object->GetName()); ls = ls + item; } // remove trailing carriage return return ls; } //------------------------- // GetObjectSize //------------------------- int DROOTHistServer::GetObjectSize(char *classname, TObject *object) { // return the approximate size of the object in kB. // This just counts the number of bins in the 1D,2D, // or 3D histo and assumes 4 bytes per bin. It is really // only meant as an estimator TH1 *h1 = NULL; TH2 *h2 = NULL; TH3 *h3 = NULL; if(!strncmp(classname, "TH1", 3))h1 = (TH1*)object; if(!strncmp(classname, "TH2", 3))h2 = (TH2*)object; if(!strncmp(classname, "TH3", 3))h3 = (TH3*)object; if(!h1 && !h2 && !h3)return 0; // we're only interested in histograms int size=0; if(h1)size = h1->GetNbinsX(); if(h2)size = h2->GetNbinsX()*h2->GetNbinsY(); if(h3)size = h3->GetNbinsX()*h3->GetNbinsY()*h3->GetNbinsZ(); size = (size*4)/1024; return size; } //------------------------- // ResetHistograms //------------------------- void DROOTHistServer::ResetHistograms(TDirectory *dir) { if(!dir)dir = fDir; cout<GetName()<<"..."<GetList()); TObject *object; while((object = (TObject*)nextobject())){ char *classname = (char*)object->ClassName(); TH1 *h1 = NULL; TH2 *h2 = NULL; TH3 *h3 = NULL; if(!strncmp(classname, "TH1", 3))h1 = (TH1*)object; if(!strncmp(classname, "TH2", 3))h2 = (TH2*)object; if(!strncmp(classname, "TH3", 3))h3 = (TH3*)object; if(h1)h1->Reset(); if(h2)h2->Reset(); if(h3)h3->Reset(); cout<<" Resetting "<GetName()<