Salome HOME
f46b0a35c961f62ad7f65a5d93863cd5cf500d2d
[modules/yacs.git] / src / runtime / CppContainer.cxx
1 // Copyright (C) 2006-2024  CEA, EDF
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <iostream>
21 #include <sstream>
22 #ifdef WIN32
23 #include <windows.h>
24 #define dlopen LoadLibrary
25 #define dlclose FreeLibrary
26 #define dlsym GetProcAddress
27 #else
28 #include <dlfcn.h>
29 #endif
30
31 #include "CppContainer.hxx"
32 #include "CppComponent.hxx"
33 #include "Exception.hxx"
34 #include <algorithm>
35 #include <iostream>
36
37
38 using namespace YACS::ENGINE;
39
40 char CppContainer::KIND[]="Cpp";
41
42 //#define _DEVDEBUG_
43 #include "YacsTrace.hxx"
44
45 //=============================================================================
46 /*! 
47  *  Local C++ container class constructor
48  */
49 //=============================================================================
50
51 CppContainer::CppContainer() : _trueCont(0L)
52 {
53     DEBTRACE("CppContainer::CppContainer()");
54 }
55
56
57 //=============================================================================
58 /*! 
59  *  Local C++ container class destructor
60  */
61 //=============================================================================
62
63 CppContainer::~CppContainer()
64 {
65     DEBTRACE("CppContainer::~CppContainer()");
66 }
67
68 void CppContainer::lock()
69 {
70   _mutex.lock();
71 }
72
73 void CppContainer::unLock()
74 {
75   _mutex.unLock();
76 }
77
78 std::string CppContainer::getKind() const
79 {
80   return KIND;
81 }
82
83 bool CppContainer::isAlreadyStarted(const Task *askingNode) const
84 {
85   return NULL != _trueCont;
86 }
87
88 void CppContainer::start(const Task *askingNode)
89 {
90   _trueCont = LocalContainer::get();
91 }
92
93 void CppContainer::shutdown(int level)
94 {
95
96 }
97
98 Container *CppContainer::clone() const
99 {
100   if(_isAttachedOnCloning)
101     {
102       incrRef();
103       return (Container*) (this);
104     }
105   else
106     return new CppContainer(*this);
107 }
108
109 Container *CppContainer::cloneAlways() const
110 {
111   return new CppContainer(*this);
112 }
113
114 bool CppContainer::loadComponentLibrary(const std::string & componentName)
115     {
116   if (_trueCont)
117     {
118       LocalLibrary L = _trueCont->loadComponentLibrary(componentName);
119       return L.good();
120     }
121   else
122     {
123       std::string mesg = "CppContainer not started";
124       throw YACS::Exception(mesg);
125     }
126   return false;
127     }
128
129 CppComponent * CppContainer::createComponentInstance(const std::string & componentName)
130 {
131   DEBTRACE("CppContainer::createComponentInstance");
132   if (_trueCont)
133     return _trueCont->createComponentInstance(componentName.c_str());
134   else
135     {
136       std::string mesg = "CppContainer not started";
137       throw YACS::Exception(mesg);
138     }
139 }
140
141 void CppContainer::createInternalInstance(const std::string & name, void *&obj, 
142                                           RunFunction &r, TerminateFunction &t)
143 {
144   DEBTRACE("CppContainer::createInternalInstance");
145   if (_trueCont)
146     _trueCont->createInternalInstance(name.c_str(), obj, r, t);
147   else
148     {
149       std::string mesg = "CppContainer not started";
150       throw YACS::Exception(mesg);
151     }
152 }
153
154 void CppContainer::unregisterComponentInstance(CppComponent *compo)
155 {
156   if (_trueCont)
157     _trueCont->unregisterComponentInstance(compo);
158 }
159
160
161 std::string CppContainer::getPlacementId(const Task *askingNode) const
162 {
163   return "/";
164 }
165
166 std::string CppContainer::getFullPlacementId(const Task *askingNode) const
167 {
168   return "/";
169 }
170
171 void CppContainer::checkCapabilityToDealWith(const ComponentInstance *inst) const
172 {
173   if(inst->getKind()!=CppComponent::KIND)
174     throw Exception("CppContainer::checkCapabilityToDealWith : CppContainer is not able to deal with this type of ComponentInstance.");
175 }
176
177 std::map<std::string, LocalLibrary> LocalContainer::_library_map; // libraries, loaded
178 std::multimap<std::string, CppComponent *> LocalContainer::_instance_map;
179
180 LocalContainer * LocalContainer::_singleton = NULL;
181
182 LocalContainer::LocalContainer()
183 {
184 }
185
186 LocalContainer::~LocalContainer()
187 {
188     destroy();
189 }
190
191 LocalContainer * LocalContainer::get()
192 {
193     if (NULL == _singleton) 
194     {
195         _singleton = new LocalContainer;
196     }
197     return _singleton;
198 }
199
200 void LocalContainer::destroy()
201 {
202   if (NULL == _singleton)
203     return;
204
205   // destroy all component instances
206   _instance_mapMutex.lock(); // lock
207   std::multimap<std::string, CppComponent *>::iterator iI, iJ;
208   for (iI=_instance_map.begin(); iI != _instance_map.end(); iI = iJ)
209     {
210       iJ = iI++;
211       iI->second->setContainer(NULL);
212       delete iI->second;
213     }
214   _instance_map.clear();
215   _instance_mapMutex.unLock(); // unlock
216
217   // unload all dynamic libraries
218   _library_mapMutex.lock();
219   std::map<std::string, LocalLibrary>::iterator iL;
220   for (iL=_library_map.begin(); iL != _library_map.end(); iL++)
221     dlclose(iL->second.handle);
222   _library_map.clear();
223   _library_mapMutex.unLock();
224
225   delete _singleton;
226   _singleton = NULL;
227 }
228
229
230 //=============================================================================
231 //! Find or create a new C++ component instance
232 /*! 
233  *  Create a new component class (C++ implementation)
234  *  \param name : component name
235  *
236  *  Try to return a handle to an new instance of a C++ component
237  *  If the associated library is not loaded, try to load it
238  *  
239  * \return a handle to the component instance or throw an exception
240  *  if it's not possible
241  */
242 //=============================================================================
243 CppComponent * LocalContainer::createComponentInstance(const char * name)
244 {
245   void *o;
246   RunFunction r;
247   TerminateFunction t;
248   
249   createInternalInstance(name, o, r, t);
250   
251   CppComponent * C;
252   C = new CppComponent(o, r, t, name);
253   _instance_mapMutex.lock(); // lock to be alone 
254   _instance_map.insert(std::pair<std::string, CppComponent *>(name, C));
255   _instance_mapMutex.unLock(); // unlock
256   return C;
257 }
258
259 void LocalContainer::createInternalInstance(const char *name, void *&obj, 
260                                             RunFunction &r, TerminateFunction &t)
261 {
262   LocalLibrary L;
263
264   std::map<std::string, LocalLibrary>::iterator foundL = _library_map.find(name);
265   if (foundL != _library_map.end())
266     L = foundL->second;
267   else
268     L = loadComponentLibrary(name, NULL, false);
269   
270   r = L.runHandle;
271   InitFunction i = L.initHandle;
272   t = L.terminateHandle;
273   
274   PingFunction p = L.pingHandle;
275   if (p) p();
276   
277   obj = i();
278   
279 }
280
281 void LocalContainer::unregisterComponentInstance(CppComponent * C)
282 {
283   _instance_mapMutex.lock(); // lock to be alone
284   _instance_map.erase(C->getCompoName());
285   _instance_mapMutex.unLock(); // unlock
286 }
287
288 inline void toupper (std::string & s)
289 {
290   transform (s.begin (), s.end (), s.begin (), (int(*)(int)) toupper);
291 }
292
293 LocalLibrary  LocalContainer::loadComponentLibrary(const std::string & aCompName, const char * prefix, bool forcedLoad)
294 {
295
296   // if forcedLoad is true, unload library if it exists
297   // if forcedLoad is false, return the existing library or load it
298   
299   if (forcedLoad)
300       unLoadComponentLibrary(aCompName);
301   else 
302     {
303       std::map<std::string, LocalLibrary >::iterator itLib 
304            = _library_map.find(aCompName);
305       if (itLib !=  _library_map.end()) return itLib->second;
306     }
307     
308   // --- try dlopen C++ component
309
310   std::string sprefix;
311   if (prefix)
312     sprefix = prefix;
313   else 
314     {
315       std::string s = aCompName + "_ROOT_DIR";
316       toupper(s);
317       const char * t = getenv(s.c_str());
318       sprefix="";
319       if (t) 
320         {
321           sprefix = t;
322           sprefix += "/lib/salome";
323         }
324     }
325   
326 #ifndef WIN32
327 #ifdef __APPLE__
328   std::string impl_name = std::string ("lib") + aCompName + std::string("Local.dylib");
329 #else
330   std::string impl_name = std::string ("lib") + aCompName + std::string("Local.so");
331 #endif
332   if(sprefix != "")
333     impl_name = sprefix + std::string("/") + impl_name;
334 #else
335   std::string impl_name = aCompName + std::string("Local.dll");
336   impl_name = sprefix + std::string("\\") + impl_name;
337 #endif
338   DEBTRACE("impl_name = " << impl_name);
339     
340 #if defined( WIN32 )
341   HMODULE handle;
342 #if defined(UNICODE)
343   size_t length = strlen(impl_name.c_str()) + sizeof(char);
344   wchar_t* aPath = new wchar_t[length + 1];
345   memset(aPath, '\0', length);
346   mbstowcs(aPath, impl_name.c_str(), length);
347 #else
348   const char* aPath = fullLibName.c_str();
349 #endif
350   handle = dlopen( aPath ) ;
351 #else
352   void* handle;
353   handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
354 #endif
355
356   const char * sError;
357 #if defined( WIN32 )
358   sError = "Not available here !";
359 #endif
360   
361 #if defined( WIN32 )
362   if (!handle) 
363 #else
364   sError = dlerror();
365   if ((sError = dlerror()) || !handle) 
366 #endif
367     {
368       std::stringstream msg;
369       msg << "Can't load shared library : " << impl_name
370           << " (dlopen error : " << sError << ") at "
371           << __FILE__ << ":" << __LINE__;
372       throw YACS::Exception(msg.str());
373     }
374   
375   void *ihandle, *rhandle, *phandle = NULL, *thandle = NULL;
376       
377   ihandle = dlsym(handle, "__init");
378 #if defined( WIN32 )
379   if (!ihandle)
380 #else
381   if (sError = dlerror()) 
382 #endif
383     {
384       dlclose(handle);
385       std::stringstream msg;
386       msg << "Library " << impl_name
387           << " doesn't contains initialization function (" << sError << ") at "
388           << __FILE__ << ":" << __LINE__;
389       throw YACS::Exception(msg.str());
390     }
391   
392   rhandle = dlsym(handle, "__run");
393 #if defined( WIN32 )
394   if (!rhandle)
395 #else
396   if (sError = dlerror()) 
397 #endif
398     {
399       dlclose(handle);
400       std::stringstream msg;
401       msg << "Library " << impl_name
402           << " doesn't contains main switch function (" << sError << ") at "
403           << __FILE__ << ":" << __LINE__;
404       throw YACS::Exception(msg.str());
405     }
406       
407   thandle = dlsym(handle, "__terminate");
408 #if defined( WIN32 )
409   if (!thandle)
410 #else
411   if (sError = dlerror()) 
412 #endif
413     {
414       dlclose(handle);
415       std::stringstream msg;
416       msg << "Library " << impl_name
417           << " doesn't contains terminate function (" << sError << ") at "
418           << __FILE__ << ":" << __LINE__;
419       throw YACS::Exception(msg.str());
420     }
421   phandle = dlsym(handle, "__ping");
422       
423   _library_map[aCompName] = LocalLibrary(handle, (InitFunction) ihandle, 
424                                                  (RunFunction)  rhandle, 
425                                                  (PingFunction) phandle,
426                                                  (TerminateFunction) thandle);
427   return _library_map[aCompName];
428 }
429
430 void LocalContainer::unLoadComponentLibrary(const std::string & aCompName)
431 {
432   std::map<std::string, LocalLibrary >::iterator itLib 
433            = _library_map.find(aCompName);
434   
435   if (itLib ==  _library_map.end()) return;
436   
437   dlclose(itLib->second.handle);
438   _library_map.erase(itLib);
439
440 }