915983d348aed2cbed14c71b7b14d53b976bda5e
[u/mrichter/AliRoot.git] / HLT / BASE / AliHLTDimServer.cxx
1 // $Id$
2
3 //**************************************************************************
4 //* This file is property of and copyright by the ALICE HLT Project        * 
5 //* ALICE Experiment at CERN, All rights reserved.                         *
6 //*                                                                        *
7 //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
8 //*                  for The ALICE HLT Project.                            *
9 //*                                                                        *
10 //* Permission to use, copy, modify and distribute this software and its   *
11 //* documentation strictly for non-commercial purposes is hereby granted   *
12 //* without fee, provided that the above copyright notice appears in all   *
13 //* copies and that both the copyright notice and this permission notice   *
14 //* appear in the supporting documentation. The authors make no claims     *
15 //* about the suitability of this software for any purpose. It is          *
16 //* provided "as is" without express or implied warranty.                  *
17 //**************************************************************************
18
19 //  @file   AliHLTDimServer.cxx
20 //  @author Matthias Richter
21 //  @date   2010-03-10
22 //  @brief  HLT DIM server implementation and dynamic access
23 //          to DIM library
24
25 #include "AliHLTDimServer.h"
26 #include "TObjArray.h"
27 #include "TSystem.h"
28 #include "TThread.h"
29
30 /** ROOT macro for the implementation of ROOT specific class methods */
31 ClassImp(AliHLTDimServer)
32
33 AliHLTDimServer::AliHLTDimServer()
34   : TNamed()
35   , fServices()
36   , fState(kStateOff)
37   , fpServerThread(NULL)
38   , fUpdatePeriod(10000)
39 {
40   // see header file for class documentation
41   // or
42   // refer to README to build package
43   // or
44   // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
45 }
46
47 AliHLTDimServer::AliHLTDimServer(const char* servername)
48   : TNamed(servername, "AliHLTDimServer")
49   , fServices()
50   , fState(kStateOff)
51   , fpServerThread(NULL)
52   , fUpdatePeriod(10000)
53 {
54   // see header file for class documentation
55 }
56
57 AliHLTDimServer::AliHLTDimInterface* AliHLTDimServer::fgpInterface=NULL;
58
59 AliHLTDimServer::~AliHLTDimServer()
60 {
61   // see header file for class documentation
62 }
63
64 int AliHLTDimServer::RegisterService(AliHLTDimService* pService)
65 {
66   // see header file for class documentation
67   if (!pService) return -EINVAL;
68   if (fServices.FindObject(pService)) {
69     AliHLTLogging log;
70     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "RegisterService" , __FILE__ , __LINE__ , "duplicate service name %s, skip ...", pService->GetName());
71     return -EEXIST;
72   }
73   fServices.Add(pService);
74   return 0;
75 }
76
77 AliHLTDimServer::AliHLTDimService* AliHLTDimServer::CreateService(enum AliHLTDimServer::AliHLTDimServiceDataType type, const char* name)
78 {
79   // see header file for class documentation
80   AliHLTDimService* service=new AliHLTDimService(type, name);
81   int iResult=RegisterService(service);
82   if (iResult<0) {
83     AliHLTLogging log;
84     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "CreateService" , __FILE__ , __LINE__ , "failed to register service %s: %d", name, iResult);
85     if (service) delete service;
86     return NULL;
87   }
88   return service;
89 }
90
91 TObjArray* AliHLTDimServer::CreateServiceGroup(enum AliHLTDimServer::AliHLTDimServiceDataType type, const char* basename, int count)
92 {
93   // see header file for class documentation
94   int iResult=0;
95   TObjArray* pServices=new TObjArray;
96   AliHLTLogging log;
97   if (pServices) {
98     if (basename && count>0) {
99       int digits=1;
100       int i=count;
101       while ((i/=10)>0) digits++;
102       if (digits<9) {
103         log.LoggingVarargs(kHLTLogDebug, "AliHLTDimServer", "CreateServiceGroup" , __FILE__ , __LINE__ , "basename=%s count=%d digits=%d\n", basename, count, digits);
104         // length of name is at max strlen(basename) + 1 '_' + digits + 1 terminating zero
105         // length of format is independent of number of digits
106         // at max we need strlen(basename) + 5 chars + 1 terminating zero
107         int namelen=strlen(basename)+5+digits;
108         char* name=(char*)malloc(namelen);
109         char* format=(char*)malloc(namelen);
110         if (name && format) {
111           memset(name, 0, namelen);
112           memset(format, 0, namelen);
113           const char* key=strchr(basename, '%');
114           strncpy(format, basename, namelen-1);
115           if (key && key[1]!=0) {
116             int iPos=(key-basename)+1;
117             if (key[1]=='d') {
118               snprintf(format+iPos, namelen-iPos, "0*d"); // additional 3 chars
119               iPos+=3;
120             } else {
121               *(format+iPos++)='%';
122               *(format+iPos++)=key[1];
123             }
124             strncpy(format+iPos, &key[2], namelen-1-iPos);
125           } else {
126             snprintf(format+strlen(basename), namelen-strlen(basename), "_%%0*d"); // additional 5 chars
127           }
128           for (i=0; i<count && iResult>=0; i++) {
129             snprintf(name, namelen, format, digits, i);
130             AliHLTDimService* service=new AliHLTDimService(type, name);
131             iResult=RegisterService(service);
132           }
133         } else {
134           iResult=-ENOMEM;
135         }
136         if (name) free(name);
137         if (format) free(format);
138       }
139     }
140   }
141   return pServices;
142 }
143
144 int AliHLTDimServer::UpdateServices()
145 {
146   /// Update all services via the Dim channel
147   return 0;
148 }
149
150 AliHLTDimServer::AliHLTDimInterface* AliHLTDimServer::Interface()
151 {
152   // get instance of the interface
153   if (!fgpInterface) {
154     fgpInterface=new AliHLTDimInterface;
155     if (fgpInterface) {
156       fgpInterface->Init();
157     }
158   }
159   return fgpInterface;
160 }
161
162 int AliHLTDimServer::Init(const char* dimNameServer)
163 {
164   // init the dim server, check if the interface is available and set the
165   // DIM DNS node name
166   AliHLTLogging log;
167   const char* myname=GetName();
168   if (myname==NULL || myname[0]==0) {
169     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Init" , __FILE__ , __LINE__ , "can not start without a server name, skipping initialization ...");
170     return -EINVAL;
171   }
172
173   if (Interface()==NULL) return -ENODEV;
174
175   Interface()->DisSetDnsNode(dimNameServer);
176   return 0;
177 }
178
179 int AliHLTDimServer::Reset()
180 {
181   // reset the DIM server, functionality needs to be clarified
182   return 0;
183 }
184
185 int AliHLTDimServer::Start()
186 {
187   // start the server in a separate thread
188   int iResult=0;
189   AliHLTLogging log;
190   if (GetState()!=kStateOff) {
191     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Start" , __FILE__ , __LINE__ , "server is not off, currently in state %d", GetState());
192     return -ENOENT;
193   }
194   fpServerThread=new TThread(ServerLoop, (void*)this);
195   if (!fpServerThread) {
196     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Start" , __FILE__ , __LINE__ , "unable to create server thread");
197     return -ENOMEM;
198   }
199   SetState(kStateStarting);
200   fpServerThread->Run();
201   
202   int count=0;
203   const int maxcount=100;
204   const int maxsleepms=1000;
205   while (GetState()==kStateStarting) {
206     if (count++==maxcount) break;
207     gSystem->Sleep(maxsleepms/maxcount);
208   }
209
210   if (GetState()!=kStateRunning) {
211     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Start" , __FILE__ , __LINE__ , "could not start server, currently in state %d", GetState());
212     Reset();
213     iResult=-EFAULT;
214   }
215   return iResult;
216 }
217
218 int AliHLTDimServer::Stop() 
219 {
220   // stop the server thread
221   int iResult=0;
222   AliHLTLogging log;
223   if (GetState()!=kStateRunning) {
224     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Stop" , __FILE__ , __LINE__ , "server is not running, currently in state %d", GetState());
225     return -ENOENT;
226   }
227   SetState(kStateStopping);
228   int count=0;
229   const int maxcount=100;
230   const int maxsleepms=2*fUpdatePeriod;
231   while (GetState()==kStateStopping) {
232     if (count++==maxcount) break;
233     gSystem->Sleep(maxsleepms/maxcount);
234   }
235
236   if (GetState()!=kStateOff) {
237     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Stop" , __FILE__ , __LINE__ , "could not stop server, currently in state %d", GetState());
238     Reset();
239     iResult=-EFAULT;
240   }
241   return iResult;
242 }
243
244 void* AliHLTDimServer::ServerLoop(void* param)
245 {
246   // see header file for class documentation
247   if (!param) return (void*)0;
248   AliHLTDimServer* server=reinterpret_cast<AliHLTDimServer*>(param);
249   return server->ServerLoop();
250 }
251
252 void* AliHLTDimServer::ServerLoop()
253 {
254   // see header file for class documentation
255   if (!Interface()) return (void*)-ENODEV;
256
257   AliHLTLogging log;
258   TIter next(&fServices);
259   TObject* obj=NULL;
260   while ((obj=next())!=NULL) {
261     AliHLTDimService* pService=dynamic_cast<AliHLTDimService*>(obj);
262     if (!pService) continue;
263     TString name=GetName(); name+="_"; name+=pService->GetName();
264     const char* type="";
265     void* buffer=pService->GetLocation();
266     int size=0;
267     switch (pService->GetType()) {
268     case kDataTypeInt:
269       type="I";
270       size=sizeof(int);
271       break;
272     case kDataTypeFloat:
273       type="F";
274       size=sizeof(float);
275       break;
276     case kDataTypeString:
277       log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "ServerLoop" , __FILE__ , __LINE__ , "ignoring dim service %s: type 'string' not yet implemented", name.Data());
278       break;
279     default:
280       log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "ServerLoop" , __FILE__ , __LINE__ , "ignoring dim service %s: unknown type %d", name.Data(), pService->GetType());
281     }
282     if (type[0]!=0) {
283       int id=Interface()->DisAddService(name.Data(), type, buffer, size);
284       if (id<0) {
285         log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "ServerLoop" , __FILE__ , __LINE__ , "failed to add dim service %s: error %d", name.Data(), id);
286       } else {
287          pService->SetId(id);
288       }
289     }
290   }
291
292   SetState(kStateRunning);
293   Interface()->DisStartServing(GetName());
294   while (GetState()==kStateRunning) {
295     gSystem->Sleep(fUpdatePeriod);
296   }
297
298   if (GetState()!=kStateStopping) return (void*)0;
299
300   // cleanup
301   Interface()->DisStopServing();
302   next.Reset();
303   while ((obj=next())!=NULL) {
304     const AliHLTDimService* pService=dynamic_cast<const AliHLTDimService*>(obj);
305     if (!pService || pService->GetId()<0) continue;
306     // int iResult=Interface()->DisRemoveService(pService->GetId());
307     // if (iResult<0) {
308     //   log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "ServerLoop" , __FILE__ , __LINE__ , "failed to remove dim service %s: error %d", pService->GetName(), iResult);
309     // }
310   }
311
312   SetState(kStateOff);
313
314   return (void*)0;
315 }
316
317 AliHLTDimServer::AliHLTDimService::AliHLTDimService()
318   : TNamed()
319   , fData()
320   , fType(kDataTypeUnknown)
321   , fId(-1)
322 {
323   // see header file for class documentation
324 }
325
326 AliHLTDimServer::AliHLTDimService::AliHLTDimService(enum AliHLTDimServiceDataType type, const char* servicename)
327   : TNamed(servicename, "AliHLTDimService")
328   , fData()
329   , fType(type)
330   , fId(-1)
331 {
332   // see header file for class documentation
333   AliHLTLogging log;
334   switch (fType) {
335   case kDataTypeInt: break;
336   case kDataTypeFloat: break;
337   case kDataTypeString:
338     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "AliHLTDimService" , __FILE__ , __LINE__ , "dim service type 'string' not yet implemented");
339     break;
340   default:
341     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "AliHLTDimService" , __FILE__ , __LINE__ , "Unknown dim service type %d", fType);
342   };
343 }
344
345 void AliHLTDimServer::AliHLTDimService::Update(const AliHLTDimServicePoint_t& sp)
346 {
347   // see header file for class documentation
348   static bool bWarning=true;
349   AliHLTLogging log;
350   switch (fType) {
351   case kDataTypeInt: fData.iVal=sp.iVal; break;
352   case kDataTypeFloat: fData.fVal=sp.fVal; break;
353   case kDataTypeString:
354     if (bWarning) log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "Update" , __FILE__ , __LINE__ , "Failed to update dim service %s: 'string' not yet implemented", GetName());
355     bWarning=false;
356     break;
357   default:
358     if (bWarning) log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "Update" , __FILE__ , __LINE__ , "Failed to update dim service %s: unknown type %d", GetName(), fType);
359     bWarning=false;
360   };
361
362   AliHLTDimServer::Interface()->DisUpdateService(fId);
363 }
364
365 AliHLTDimServer::AliHLTDimInterface::AliHLTDimInterface()
366   : AliHLTLogging()
367   , fpDisAddService(NULL)
368   , fpDisRemoveService(NULL)
369   , fpDisUpdateService(NULL)
370   , fpDisStartServing(NULL)
371   , fpDisStopServing(NULL)
372   , fpDisSetDnsNode(NULL)
373 {
374 }
375
376 AliHLTDimServer::AliHLTDimInterface::~AliHLTDimInterface()
377 {
378 }
379
380
381 const char* AliHLTDimServer::AliHLTDimInterface::fgkDimLibraryName="libdim.so";
382 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisAddServiceSymbol="dis_add_service";
383 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisRemoveServiceSymbol="dis_remove_service";
384 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisUpdateServiceSymbol="dis_update_service";
385 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisStartServingSymbol="dis_start_serving";
386 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisStopServingSymbol="dis_stop_serving";
387 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisSetDnsNodeSymbol="dis_set_dns_node";
388
389 int AliHLTDimServer::AliHLTDimInterface::Init()
390 {
391   /// load the dim library and function pointers
392   if (gSystem->Load(fgkDimLibraryName)) {
393     HLTFatal("failed to load dim library: %s", fgkDimLibraryName);
394     return -ENODEV;
395   }
396
397   fpDisAddService=(fctDisAddService)FindSymbol(fgkDimLibraryName, fgkDisAddServiceSymbol);
398   if (!fpDisAddService) return -ENODEV;
399
400   fpDisRemoveService=(fctDisRemoveService)FindSymbol(fgkDimLibraryName, fgkDisRemoveServiceSymbol);
401   if (!fpDisRemoveService) return -ENODEV;
402
403   fpDisUpdateService=(fctDisUpdateService)FindSymbol(fgkDimLibraryName, fgkDisUpdateServiceSymbol);
404   if (!fpDisUpdateService) return -ENODEV;
405
406   fpDisStartServing=(fctDisCharArg)FindSymbol(fgkDimLibraryName, fgkDisStartServingSymbol);
407   if (!fpDisStartServing) return -ENODEV;
408
409   fpDisStopServing=(fctDisNoArg)FindSymbol(fgkDimLibraryName, fgkDisStopServingSymbol);
410   if (!fpDisStopServing) return -ENODEV;
411
412   fpDisSetDnsNode=(fctDisCharArg)FindSymbol(fgkDimLibraryName, fgkDisSetDnsNodeSymbol);
413   if (!fpDisSetDnsNode) return -ENODEV;
414
415   return 0;
416 }
417
418 AliHLTDimServer::fctVoid AliHLTDimServer::AliHLTDimInterface::FindSymbol(const char* library, const char* symbol) const
419 {
420   /// Find symbol in the dim library
421   TString tmp=symbol;
422   fctVoid fctptr=gSystem->DynFindSymbol(library, tmp.Data());
423   if (!fctptr) {
424     // do a 2nd try with appended '_'
425     tmp+="_";
426     fctptr=gSystem->DynFindSymbol(library, tmp.Data());
427   }
428   if (fctptr) return fctptr;
429
430   HLTError("can not find symbol '%s' in %s", symbol, library);
431   return NULL;
432 }