Changes required to publish custom data structures over DIM.
[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       if (fgpInterface->Init() != 0) {
157         delete fgpInterface;
158         fgpInterface = NULL;
159       }
160     }
161   }
162   return fgpInterface;
163 }
164
165 int AliHLTDimServer::Init(const char* dimNameServer)
166 {
167   // init the dim server, check if the interface is available and set the
168   // DIM DNS node name
169   AliHLTLogging log;
170   const char* myname=GetName();
171   if (myname==NULL || myname[0]==0) {
172     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Init" , __FILE__ , __LINE__ , "can not start without a server name, skipping initialization ...");
173     return -EINVAL;
174   }
175
176   if (Interface()==NULL) return -ENODEV;
177
178   Interface()->DisSetDnsNode(dimNameServer);
179   return 0;
180 }
181
182 int AliHLTDimServer::Reset()
183 {
184   // reset the DIM server, functionality needs to be clarified
185   return 0;
186 }
187
188 int AliHLTDimServer::Start()
189 {
190   // start the server in a separate thread
191   int iResult=0;
192   AliHLTLogging log;
193   if (GetState()!=kStateOff) {
194     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Start" , __FILE__ , __LINE__ , "server is not off, currently in state %d", GetState());
195     return -ENOENT;
196   }
197   fpServerThread=new TThread(ServerLoop, (void*)this);
198   if (!fpServerThread) {
199     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Start" , __FILE__ , __LINE__ , "unable to create server thread");
200     return -ENOMEM;
201   }
202   SetState(kStateStarting);
203   fpServerThread->Run();
204   
205   int count=0;
206   const int maxcount=100;
207   const int maxsleepms=1000;
208   while (GetState()==kStateStarting) {
209     if (count++==maxcount) break;
210     gSystem->Sleep(maxsleepms/maxcount);
211   }
212
213   if (GetState()!=kStateRunning) {
214     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Start" , __FILE__ , __LINE__ , "could not start server, currently in state %d", GetState());
215     Reset();
216     iResult=-EFAULT;
217   }
218   return iResult;
219 }
220
221 int AliHLTDimServer::Stop() 
222 {
223   // stop the server thread
224   int iResult=0;
225   AliHLTLogging log;
226   if (GetState()!=kStateRunning) {
227     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Stop" , __FILE__ , __LINE__ , "server is not running, currently in state %d", GetState());
228     return -ENOENT;
229   }
230   SetState(kStateStopping);
231   int count=0;
232   const int maxcount=100;
233   const int maxsleepms=2*fUpdatePeriod;
234   while (GetState()==kStateStopping) {
235     if (count++==maxcount) break;
236     gSystem->Sleep(maxsleepms/maxcount);
237   }
238
239   if (GetState()!=kStateOff) {
240     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "Stop" , __FILE__ , __LINE__ , "could not stop server, currently in state %d", GetState());
241     Reset();
242     iResult=-EFAULT;
243   }
244   return iResult;
245 }
246
247 void* AliHLTDimServer::ServerLoop(void* param)
248 {
249   // see header file for class documentation
250   if (!param) return (void*)0;
251   AliHLTDimServer* server=reinterpret_cast<AliHLTDimServer*>(param);
252   return server->ServerLoop();
253 }
254
255 void* AliHLTDimServer::ServerLoop()
256 {
257   // see header file for class documentation
258   if (!Interface()) return (void*)-ENODEV;
259
260   AliHLTLogging log;
261   TIter next(&fServices);
262   TObject* obj=NULL;
263   while ((obj=next())!=NULL) {
264     AliHLTDimService* pService=dynamic_cast<AliHLTDimService*>(obj);
265     if (!pService) continue;
266     TString name=GetName(); name+="_"; name+=pService->GetName();
267     const char* type="";
268     void* buffer=pService->GetLocation();
269     int size=0;
270     switch (pService->GetType()) {
271     case kDataTypeCustom:
272     case kDataTypeInt:
273     case kDataTypeFloat:
274       type=pService->GetTypeString();
275       size=pService->GetDataSize();
276       break;
277     case kDataTypeString:
278       log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "ServerLoop" , __FILE__ , __LINE__ , "ignoring dim service %s: type 'string' not yet implemented", name.Data());
279       break;
280     default:
281       log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "ServerLoop" , __FILE__ , __LINE__ , "ignoring dim service %s: unknown type %d", name.Data(), pService->GetType());
282     }
283     if (type[0]!=0) {
284       int id=Interface()->DisAddService(name.Data(), type, buffer, size);
285       if (id<0) {
286         log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "ServerLoop" , __FILE__ , __LINE__ , "failed to add dim service %s: error %d", name.Data(), id);
287       } else {
288          pService->SetId(id);
289       }
290     }
291   }
292
293   SetState(kStateRunning);
294   Interface()->DisStartServing(GetName());
295   while (GetState()==kStateRunning) {
296     gSystem->Sleep(fUpdatePeriod);
297   }
298
299   if (GetState()!=kStateStopping) return (void*)0;
300
301   // cleanup
302   Interface()->DisStopServing();
303   next.Reset();
304   while ((obj=next())!=NULL) {
305     const AliHLTDimService* pService=dynamic_cast<const AliHLTDimService*>(obj);
306     if (!pService || pService->GetId()<0) continue;
307     // int iResult=Interface()->DisRemoveService(pService->GetId());
308     // if (iResult<0) {
309     //   log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "ServerLoop" , __FILE__ , __LINE__ , "failed to remove dim service %s: error %d", pService->GetName(), iResult);
310     // }
311   }
312
313   SetState(kStateOff);
314
315   return (void*)0;
316 }
317
318 AliHLTDimServer::AliHLTDimService::AliHLTDimService()
319   : TNamed()
320   , fData()
321   , fType(kDataTypeUnknown)
322   , fTypeString()
323   , fDataBuffer(NULL)
324   , fDataSize(0)
325   , fId(-1)
326 {
327   // see header file for class documentation
328 }
329
330 AliHLTDimServer::AliHLTDimService::AliHLTDimService(enum AliHLTDimServiceDataType type, const char* servicename)
331   : TNamed(servicename, "AliHLTDimService")
332   , fData()
333   , fType(type)
334   , fTypeString()
335   , fDataBuffer(NULL)
336   , fDataSize(0)
337   , fId(-1)
338 {
339   // see header file for class documentation
340   AliHLTLogging log;
341   switch (fType) {
342   case kDataTypeCustom:
343     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "AliHLTDimService" , __FILE__ , __LINE__ , "cannot use the kDataTypeCustom type with this method");
344     break;
345   case kDataTypeInt:
346     fTypeString="I";
347     fDataBuffer=&fData.iVal;
348     fDataSize=sizeof(int);
349     break;
350   case kDataTypeFloat:
351     fTypeString="F";
352     fDataBuffer=&fData.fVal;
353     fDataSize=sizeof(float);
354     break;
355   case kDataTypeString:
356     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "AliHLTDimService" , __FILE__ , __LINE__ , "dim service type 'string' not yet implemented");
357     break;
358   default:
359     log.LoggingVarargs(kHLTLogError, "AliHLTDimServer", "AliHLTDimService" , __FILE__ , __LINE__ , "Unknown dim service type %d", fType);
360   };
361 }
362
363 AliHLTDimServer::AliHLTDimService::AliHLTDimService(const char* type, void* data, int size, const char* servicename)
364   : TNamed(servicename, "AliHLTDimService")
365   , fData()
366   , fType(kDataTypeCustom)
367   , fTypeString(type)
368   , fDataBuffer(data)
369   , fDataSize(size)
370   , fId(-1)
371 {
372   // see header file for class documentation
373 }
374
375 void AliHLTDimServer::AliHLTDimService::Update()
376 {
377   // see header file for class documentation
378   static bool bWarning=true;
379   AliHLTLogging log;
380   switch (fType) {
381   case kDataTypeCustom: break;
382   default:
383     if (bWarning) log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "Update" , __FILE__ , __LINE__ , "The service %s must be a custom type (kDataTypeCustom) to use this form of Update", GetName());
384     bWarning=false;
385   };
386
387   AliHLTDimServer::Interface()->DisUpdateService(fId);
388 }
389
390 void AliHLTDimServer::AliHLTDimService::Update(const AliHLTDimServicePoint_t& sp)
391 {
392   // see header file for class documentation
393   static bool bWarning=true;
394   AliHLTLogging log;
395   switch (fType) {
396   case kDataTypeCustom:
397     if (bWarning) log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "Update" , __FILE__ , __LINE__ , "Should not call this form of Update for custom type (kDataTypeCustom) service %s", GetName());
398     bWarning=false;
399     return;
400   case kDataTypeInt: fData.iVal=sp.iVal; break;
401   case kDataTypeFloat: fData.fVal=sp.fVal; break;
402   case kDataTypeString:
403     if (bWarning) log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "Update" , __FILE__ , __LINE__ , "Failed to update dim service %s: 'string' not yet implemented", GetName());
404     bWarning=false;
405     break;
406   default:
407     if (bWarning) log.LoggingVarargs(kHLTLogError, "AliHLTDimServer::AliHLTDimService", "Update" , __FILE__ , __LINE__ , "Failed to update dim service %s: unknown type %d", GetName(), fType);
408     bWarning=false;
409   };
410
411   AliHLTDimServer::Interface()->DisUpdateService(fId);
412 }
413
414 AliHLTDimServer::AliHLTDimInterface::AliHLTDimInterface()
415   : AliHLTLogging()
416   , fpDisAddService(NULL)
417   , fpDisRemoveService(NULL)
418   , fpDisUpdateService(NULL)
419   , fpDisStartServing(NULL)
420   , fpDisStopServing(NULL)
421   , fpDisSetDnsNode(NULL)
422 {
423 }
424
425 AliHLTDimServer::AliHLTDimInterface::~AliHLTDimInterface()
426 {
427 }
428
429
430 const char* AliHLTDimServer::AliHLTDimInterface::fgkDimLibraryName="libdim.so";
431 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisAddServiceSymbol="dis_add_service";
432 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisRemoveServiceSymbol="dis_remove_service";
433 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisUpdateServiceSymbol="dis_update_service";
434 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisStartServingSymbol="dis_start_serving";
435 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisStopServingSymbol="dis_stop_serving";
436 const char* AliHLTDimServer::AliHLTDimInterface::fgkDisSetDnsNodeSymbol="dis_set_dns_node";
437
438 int AliHLTDimServer::AliHLTDimInterface::Init()
439 {
440   /// load the dim library and function pointers
441   if (gSystem->Load(fgkDimLibraryName)) {
442     HLTFatal("failed to load dim library: %s", fgkDimLibraryName);
443     return -ENODEV;
444   }
445
446   fpDisAddService=(fctDisAddService)FindSymbol(fgkDimLibraryName, fgkDisAddServiceSymbol);
447   if (!fpDisAddService) return -ENODEV;
448
449   fpDisRemoveService=(fctDisRemoveService)FindSymbol(fgkDimLibraryName, fgkDisRemoveServiceSymbol);
450   if (!fpDisRemoveService) return -ENODEV;
451
452   fpDisUpdateService=(fctDisUpdateService)FindSymbol(fgkDimLibraryName, fgkDisUpdateServiceSymbol);
453   if (!fpDisUpdateService) return -ENODEV;
454
455   fpDisStartServing=(fctDisCharArg)FindSymbol(fgkDimLibraryName, fgkDisStartServingSymbol);
456   if (!fpDisStartServing) return -ENODEV;
457
458   fpDisStopServing=(fctDisNoArg)FindSymbol(fgkDimLibraryName, fgkDisStopServingSymbol);
459   if (!fpDisStopServing) return -ENODEV;
460
461   fpDisSetDnsNode=(fctDisCharArg)FindSymbol(fgkDimLibraryName, fgkDisSetDnsNodeSymbol);
462   if (!fpDisSetDnsNode) return -ENODEV;
463
464   return 0;
465 }
466
467 AliHLTDimServer::fctVoid AliHLTDimServer::AliHLTDimInterface::FindSymbol(const char* library, const char* symbol) const
468 {
469   /// Find symbol in the dim library
470   TString tmp=symbol;
471   fctVoid fctptr=gSystem->DynFindSymbol(library, tmp.Data());
472   if (!fctptr) {
473     // do a 2nd try with appended '_'
474     tmp+="_";
475     fctptr=gSystem->DynFindSymbol(library, tmp.Data());
476   }
477   if (fctptr) return fctptr;
478
479   HLTError("can not find symbol '%s' in %s", symbol, library);
480   return NULL;
481 }