Salome HOME
[EDF29138] : measure CPU/Mem even in OutOfProcess mode
[modules/kernel.git] / src / Container / Container_i.cxx
index 06cd2c382b5aefa320d67f5afbd25f9348aec204..aee98c06c9f88c40f5455002f82623f8e8141d12 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
+// Copyright (C) 2007-2024  CEA, EDF, OPEN CASCADE
 //
 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
 #include <stdio.h>
 #include <time.h>
 #include <sys/types.h>
+#include <memory>
+#include <vector>
 #ifndef WIN32
 #include <sys/time.h>
 #include <dlfcn.h>
 #include <unistd.h>
 #include <sys/wait.h>
+#include <errno.h>
+#include <stdlib.h>
 #else
 #include <signal.h>
 #include <process.h>
@@ -48,20 +52,30 @@ int SIGUSR1 = 1000;
 #include CORBA_SERVER_HEADER(SALOME_Component)
 #include CORBA_SERVER_HEADER(SALOME_Exception)
 #include <pthread.h>  // must be before Python.h !
+#include "OpUtil.hxx"
 #include "SALOME_Container_i.hxx"
 #include "SALOME_Component_i.hxx"
 #include "SALOME_FileRef_i.hxx"
 #include "SALOME_FileTransfer_i.hxx"
 #include "Salome_file_i.hxx"
 #include "SALOME_NamingService.hxx"
+#include "SALOME_Fake_NamingService.hxx"
+#include "SALOME_Embedded_NamingService_Client.hxx"
+#include "SALOME_Embedded_NamingService.hxx"
 #include "Basics_Utils.hxx"
+#include "PythonCppUtils.hxx"
+#include "Utils_CorbaException.hxx"
 
 #ifdef _XOPEN_SOURCE
 #undef _XOPEN_SOURCE
 #endif
 
 #include <Python.h>
+#include <structmember.h>
 #include "Container_init_python.hxx"
+#ifdef BOS26455_WITH_BOOST_PYTHON
+#include <boost/python.hpp>
+#endif
 
 bool _Sleeping = false ;
 
@@ -78,7 +92,11 @@ extern "C" {void SigIntHandler( int ) ; }
 
 #ifndef WIN32
 #define LIB "lib"
+#ifdef __APPLE__
+#define ENGINESO "Engine.dylib"
+#else
 #define ENGINESO "Engine.so"
+#endif
 #else
 #define LIB ""
 #define ENGINESO "Engine.dll"
@@ -92,12 +110,14 @@ extern "C" {void SigIntHandler( int ) ; }
 #define SLASH '/'
 #endif
 
-std::map<std::string, int> Engines_Container_i::_cntInstances_map;
-std::map<std::string, void *> Engines_Container_i::_library_map;
-std::map<std::string, void *> Engines_Container_i::_toRemove_map;
-omni_mutex Engines_Container_i::_numInstanceMutex ;
+const int Abstract_Engines_Container_i::DFT_TIME_INTERVAL_BTW_MEASURE = 500;
 
-static PyObject* _pyCont;
+std::map<std::string, int> Abstract_Engines_Container_i::_cntInstances_map;
+std::map<std::string, void *> Abstract_Engines_Container_i::_library_map;
+std::map<std::string, void *> Abstract_Engines_Container_i::_toRemove_map;
+omni_mutex Abstract_Engines_Container_i::_numInstanceMutex ;
+
+static PyObject *_pyCont = nullptr;
 
 int checkifexecutable(const std::string&);
 int findpathof(const std::string& path, std::string&, const std::string&);
@@ -114,29 +134,30 @@ int findpathof(const std::string& path, std::string&, const std::string&);
 */
 //=============================================================================
 
-Engines_Container_i::Engines_Container_i () :
-_numInstance(0),_id(0),_NS(0)
+Abstract_Engines_Container_i::Abstract_Engines_Container_i () :
+  _NS(nullptr),_id(nullptr),_numInstance(0)
 {
 }
 
 //=============================================================================
 /*! 
-*  Construtor to use
+*  Constructor to use
 */
 //=============================================================================
 
-Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb, 
-                                          PortableServer::POA_ptr poa,
-                                          char *containerName ,
-                                          int argc , char* argv[],
-                                          bool activAndRegist,
-                                          bool isServantAloneInProcess
-                                          ) :
-  _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess),_id(0),_NS(0)
+Abstract_Engines_Container_i::Abstract_Engines_Container_i (const std::string& pyContainerClsName,
+                                                            CORBA::ORB_ptr orb, 
+                                                            PortableServer::POA_ptr poa,
+                                                            char *containerName ,
+                                                            int argc , char* argv[],
+                                                            SALOME_NamingService_Container_Abstract *ns,
+                                                            bool isServantAloneInProcess
+                                                            ) :
+  _NS(nullptr),_py_container_name(pyContainerClsName),_id(0),_numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
 {
   _pid = (long)getpid();
 
-  if(activAndRegist)
+  if( isServantAloneInProcess )
     ActSigIntHandler() ;
 
   _argc = argc ;
@@ -144,27 +165,11 @@ Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb,
 
   std::string hostname = Kernel_Utils::GetHostname();
 #ifndef WIN32
-  MESSAGE(hostname << " " << getpid() << 
-    " Engines_Container_i starting argc " <<
-    _argc << " Thread " << pthread_self() ) ;
+  INFO_MESSAGE("Starting Container servant instance on Hostname :" << hostname << " with  PID : " << getpid() ) ;
 #else
   MESSAGE(hostname << " " << _getpid() << 
     " Engines_Container_i starting argc " << _argc<< " Thread " << pthread_self().p ) ;
 #endif
-
-  int i = 0 ;
-  while ( _argv[ i ] )
-  {
-    MESSAGE("           argv" << i << " " << _argv[ i ]) ;
-    i++ ;
-  }
-
-  if ( argc < 2 )
-  {
-    INFOS("SALOME_Container usage : SALOME_Container ServerName");
-    ASSERT(0) ;
-  }
-  SCRUTE(argv[1]);
   _isSupervContainer = false;
 
   _orb = CORBA::ORB::_duplicate(orb) ;
@@ -173,67 +178,62 @@ Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb,
   // Pour les containers paralleles: il ne faut pas enregistrer et activer
   // le container generique, mais le container specialise
 
-  if(activAndRegist)
   {
     _id = _poa->activate_object(this);
-    _NS = new SALOME_NamingService();
+    // key point : if ns is nullptr : this servant is alone in its process
+    //             if ns is not null : this servant embedded into single process.
+    _NS = ns==nullptr ? new SALOME_NamingService : ns->clone();
     _NS->init_orb( _orb ) ;
     CORBA::Object_var obj=_poa->id_to_reference(*_id);
-    Engines::Container_var pCont 
-      = Engines::Container::_narrow(obj);
+    Engines::Container_var pCont = Engines::Container::_narrow(obj);
     _remove_ref();
 
-    _containerName = _NS->BuildContainerNameForNS(containerName,
-      hostname.c_str());
-    SCRUTE(_containerName);
-    _NS->Register(pCont, _containerName.c_str());
-    MESSAGE("Engines_Container_i::Engines_Container_i : Container name "
-      << _containerName);
+    _containerName =  SALOME_NamingService_Abstract::BuildContainerNameForNS(containerName, hostname.c_str());
 
     // Python: 
     // import SALOME_Container
     // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
 
     CORBA::String_var sior =  _orb->object_to_string(pCont);
-    std::string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
-    myCommand += _containerName + "','";
-    myCommand += sior;
-    myCommand += "')\n";
-    SCRUTE(myCommand);
+    std::ostringstream myCommand;
+    myCommand << "pyCont = SALOME_Container." << this->getPyContainerClassName() << "('" << _containerName << "','" << sior << "'," <<  DFT_TIME_INTERVAL_BTW_MEASURE << ")\n";
+    INFO_MESSAGE("Python command executed : " << myCommand.str());
 
     //[RNV]: Comment the PyEval_AcquireLock() and PyEval_ReleaseLock() because this 
     //approach leads to the deadlock of the main thread of the application on Windows platform
     //in case if cppContainer runs in the standalone mode. The problem with the PyThreadState 
     //described by ABN seems not reproduced, to be checked carefully later...
-    PyGILState_STATE gstate = PyGILState_Ensure();
-    
-    //// [ABN]: using the PyGILState* API here is unstable. omniORB logic is invoked
-    //// by the Python code executed below, and in some (random) cases, the Python code
-    //// execution ends with a PyThreadState which was not the one we have here.
-    //// (TODO: understand why ...)
-    //// To be on the safe side we get and load the thread state ourselves:    
-    //PyEval_AcquireLock();  // get GIL
-    //PyThreadState * mainThreadState = PyThreadState_Get();
-    //PyThreadState_Swap(mainThreadState);
+    {
+      AutoGIL gstate;    
+      //// [ABN]: using the PyGILState* API here is unstable. omniORB logic is invoked
+      //// by the Python code executed below, and in some (random) cases, the Python code
+      //// execution ends with a PyThreadState which was not the one we have here.
+      //// (TODO: understand why ...)
+      //// To be on the safe side we get and load the thread state ourselves:    
+      //PyEval_AcquireLock();  // get GIL
+      //PyThreadState * mainThreadState = PyThreadState_Get();
+      //PyThreadState_Swap(mainThreadState);
 
 #ifdef WIN32
-    // mpv: this is temporary solution: there is a unregular crash if not
-    //Sleep(2000);
-    //
-    // first element is the path to Registry.dll, but it's wrong
-    PyRun_SimpleString("import sys\n");
-    PyRun_SimpleString("sys.path = sys.path[1:]\n");
+      // mpv: this is temporary solution: there is a unregular crash if not
+      //Sleep(2000);
+      //
+      // first element is the path to Registry.dll, but it's wrong
+      PyRun_SimpleString("import sys\n");
+      PyRun_SimpleString("sys.path = sys.path[1:]\n");
 #endif
-    PyRun_SimpleString("import SALOME_Container\n");
-    PyRun_SimpleString((char*)myCommand.c_str());
-    PyObject *mainmod = PyImport_AddModule("__main__");
-    PyObject *globals = PyModule_GetDict(mainmod);
-    _pyCont = PyDict_GetItemString(globals, "pyCont");
-
-    //PyThreadState_Swap(NULL);
-    //PyEval_ReleaseLock();
-    PyGILState_Release(gstate);
-
+      PyRun_SimpleString("import SALOME_Container\n");
+      PyRun_SimpleString((char*)myCommand.str().c_str());
+      PyObject *mainmod = PyImport_AddModule("__main__");
+      PyObject *globals = PyModule_GetDict(mainmod);
+      _pyCont = PyDict_GetItemString(globals, "pyCont");
+      //PyThreadState_Swap(NULL);
+      //PyEval_ReleaseLock();
+    }
+    {// register to NS after python initialization to be sure that client invoke after py constructor execution
+      _NS->Register(pCont, _containerName.c_str());
+      DEBUG_MESSAGE("Container registred in NS as : " << _containerName);
+    }
     fileTransfer_i* aFileTransfer = new fileTransfer_i();
     CORBA::Object_var obref=aFileTransfer->_this();
     _fileTransfer = Engines::fileTransfer::_narrow(obref);
@@ -247,25 +247,14 @@ Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb,
 */
 //=============================================================================
 
-Engines_Container_i::~Engines_Container_i()
+Abstract_Engines_Container_i::~Abstract_Engines_Container_i()
 {
-  MESSAGE("Container_i::~Container_i()");
+  MESSAGE("Abstract_Container_i::~Abstract_Container_i()");
   if(_id)
     delete _id;
   if(_NS)
     delete _NS;
-  for(std::map<std::string,Engines::PyNode_var>::iterator it=_dftPyNode.begin();it!=_dftPyNode.end();it++)
-  {
-    Engines::PyNode_var tmpVar((*it).second);
-    if(!CORBA::is_nil(tmpVar))
-      tmpVar->UnRegister();
-  }
-  for(std::map<std::string,Engines::PyScriptNode_var>::iterator it=_dftPyScriptNode.begin();it!=_dftPyScriptNode.end();it++)
-  {
-    Engines::PyScriptNode_var tmpVar((*it).second);
-    if(!CORBA::is_nil(tmpVar))
-      tmpVar->UnRegister();
-  }
+  cleanAllPyScripts();
 }
 
 //=============================================================================
@@ -275,7 +264,7 @@ Engines_Container_i::~Engines_Container_i()
 */
 //=============================================================================
 
-char* Engines_Container_i::name()
+char* Abstract_Engines_Container_i::name()
 {
   return CORBA::string_dup(_containerName.c_str()) ;
 }
@@ -287,7 +276,7 @@ char* Engines_Container_i::name()
 */
 //=============================================================================
 
-char* Engines_Container_i::workingdir()
+char* Abstract_Engines_Container_i::workingdir()
 {
   char wd[256];
   getcwd (wd,256);
@@ -301,17 +290,87 @@ char* Engines_Container_i::workingdir()
 */
 //=============================================================================
 
-charEngines_Container_i::logfilename()
+char *Abstract_Engines_Container_i::logfilename()
 {
   return CORBA::string_dup(_logfilename.c_str()) ;
 }
 
 //! Set container log file name
-void Engines_Container_i::logfilename(const char* name)
+void Abstract_Engines_Container_i::logfilename(const char* name)
 {
   _logfilename=name;
 }
 
+char *Abstract_Engines_Container_i::locallogfilename()
+{
+  return CORBA::string_dup( _localfilename.c_str() );
+}
+
+void Abstract_Engines_Container_i::locallogfilename(const char *name)
+{
+  AutoGIL gstate;
+  _localfilename = name;
+  AutoPyRef result = PyObject_CallMethod(_pyCont,(char*)"setLogFileName","s",name,nullptr);
+  if (PyErr_Occurred())
+  {
+    std::string error("can not set logfilename");
+    PyErr_Print();
+    THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
+  }
+}
+
+CORBA::Long Abstract_Engines_Container_i::monitoringtimeresms()
+{
+  AutoGIL gstate;
+  AutoPyRef result = PyObject_CallMethod(_pyCont,(char*)"monitoringtimeresms",nullptr);
+  if (PyErr_Occurred())
+  {
+    std::string error("can not retrieve time interval between 2 measures");
+    PyErr_Print();
+    THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
+  }
+  CORBA::Long ret = PyLong_AsLong( result );
+  return ret;
+}
+
+void Abstract_Engines_Container_i::monitoringtimeresms(CORBA::Long intervalInMs)
+{
+  AutoGIL gstate;
+  AutoPyRef result = PyObject_CallMethod(_pyCont,(char*)"SetMonitoringtimeresms","i",intervalInMs,nullptr);
+  if (PyErr_Occurred())
+  {
+    std::string error("can not set time interval between 2 measures");
+    PyErr_Print();
+    THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
+  }
+}
+
+void Abstract_Engines_Container_i::verbosity(bool& activated, CORBA::String_out level)
+{
+  activated = SALOME::VerbosityActivated();
+  level = CORBA::string_dup( SALOME::VerbosityLevelStr().c_str() );
+}
+
+void Abstract_Engines_Container_i::setVerbosity(bool activated, const char *level)
+{
+  SALOME::SetVerbosityActivated( activated );
+  SALOME::SetVerbosityLevelStr( level );
+  {
+    AutoGIL gstate;
+    AutoPyRef res = PyObject_CallMethod(_pyCont,
+      (char*)"positionVerbosityOfLogger",NULL);
+    if(res==NULL)
+    {
+      //internal error
+      PyErr_Print();
+      SALOME::ExceptionStruct es;
+      es.type = SALOME::INTERNAL_ERROR;
+      es.text = "can not create a python node";
+      throw SALOME::SALOME_Exception(es);
+    }
+  }
+}
+
 //=============================================================================
 //! Get container host name
 /*! 
@@ -319,7 +378,7 @@ void Engines_Container_i::logfilename(const char* name)
 */
 //=============================================================================
 
-char* Engines_Container_i::getHostName()
+char* Abstract_Engines_Container_i::getHostName()
 {
   std::string s = Kernel_Utils::GetHostname();
   //  MESSAGE("Engines_Container_i::getHostName " << s);
@@ -333,7 +392,7 @@ char* Engines_Container_i::getHostName()
 */
 //=============================================================================
 
-CORBA::Long Engines_Container_i::getPID()
+CORBA::Long Abstract_Engines_Container_i::getPID()
 {
   return (CORBA::Long)getpid();
 }
@@ -344,11 +403,302 @@ CORBA::Long Engines_Container_i::getPID()
 *  CORBA method: check if servant is still alive
 */
 //=============================================================================
-void Engines_Container_i::ping()
+void Abstract_Engines_Container_i::ping()
 {
   MESSAGE("Engines_Container_i::ping() pid "<< getpid());
 }
 
+//=============================================================================
+//! Get number of CPU cores in the calculation node
+/*!
+*  CORBA method: get number of CPU cores
+*/
+//=============================================================================
+
+CORBA::Long Abstract_Engines_Container_i::getNumberOfCPUCores()
+{
+  AutoGIL gstate;
+  PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
+  AutoPyRef result = PyObject_CallMethod(module,
+                                         (char*)"getNumberOfCPUCores", NULL);
+  int n = PyLong_AsLong(result);
+  return (CORBA::Long)n;
+}
+
+//=============================================================================
+//! Get a load of each CPU core in the calculation node
+/*!
+*  CORBA method: get a load of each CPU core
+*/
+//=============================================================================
+namespace {
+  typedef struct
+  {
+    PyObject_HEAD
+    int softspace;
+    std::string *out;
+  } PyStdOut;
+
+  static void
+  PyStdOut_dealloc(PyStdOut *self)
+  {
+    PyObject_Del(self);
+  }
+
+  static PyObject*
+  PyStdOut_write(PyStdOut* self, PyObject* args)
+  {
+    char *c;
+    if (!PyArg_ParseTuple(args, "s", &c))
+      return NULL;
+
+    *(self->out) = *(self->out) + c;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+  }
+
+  static PyMethodDef PyStdOut_methods[] =
+  {
+    {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS,
+      PyDoc_STR("write(string) -> None")},
+    {0, 0, 0, 0}  /* sentinel */
+  };
+
+  static PyMemberDef PyStdOut_memberlist[] =
+  {
+    {(char*)"softspace", T_INT, offsetof(PyStdOut, softspace), 0,
+     (char*)"flag indicating that a space needs to be printed; used by print"},
+    {0, 0, 0, 0, 0}   /* sentinel */
+  };
+
+  static PyTypeObject PyStdOut_Type =
+  {
+    /* The ob_type field must be initialized in the module init function
+     * to be portable to Windows without using C++. */
+    PyVarObject_HEAD_INIT(NULL, 0)
+    /* 0, */                      /*ob_size*/
+    "PyOut",                      /*tp_name*/
+    sizeof(PyStdOut),             /*tp_basicsize*/
+    0,                            /*tp_itemsize*/
+    /* methods */
+    (destructor)PyStdOut_dealloc, /*tp_dealloc*/
+    0,                            /*tp_print*/
+    0,                            /*tp_getattr*/
+    0,                            /*tp_setattr*/
+    0,                            /*tp_compare*/
+    0,                            /*tp_repr*/
+    0,                            /*tp_as_number*/
+    0,                            /*tp_as_sequence*/
+    0,                            /*tp_as_mapping*/
+    0,                            /*tp_hash*/
+    0,                            /*tp_call*/
+    0,                            /*tp_str*/
+    PyObject_GenericGetAttr,      /*tp_getattro*/
+    /* softspace is writable:  we must supply tp_setattro */
+    PyObject_GenericSetAttr,      /* tp_setattro */
+    0,                            /*tp_as_buffer*/
+    Py_TPFLAGS_DEFAULT,           /*tp_flags*/
+    0,                            /*tp_doc*/
+    0,                            /*tp_traverse*/
+    0,                            /*tp_clear*/
+    0,                            /*tp_richcompare*/
+    0,                            /*tp_weaklistoffset*/
+    0,                            /*tp_iter*/
+    0,                            /*tp_iternext*/
+    PyStdOut_methods,             /*tp_methods*/
+    PyStdOut_memberlist,          /*tp_members*/
+    0,                            /*tp_getset*/
+    0,                            /*tp_base*/
+    0,                            /*tp_dict*/
+    0,                            /*tp_descr_get*/
+    0,                            /*tp_descr_set*/
+    0,                            /*tp_dictoffset*/
+    0,                            /*tp_init*/
+    0,                            /*tp_alloc*/
+    0,                            /*tp_new*/
+    0,                            /*tp_free*/
+    0,                            /*tp_is_gc*/
+    0,                            /*tp_bases*/
+    0,                            /*tp_mro*/
+    0,                            /*tp_cache*/
+    0,                            /*tp_subclasses*/
+    0,                            /*tp_weaklist*/
+    0,                            /*tp_del*/
+    0,                            /*tp_version_tag*/
+    0,                            /*tp_finalize*/
+  };
+
+  PyObject* newPyStdOut(std::string& out)
+  {
+    PyStdOut* self = PyObject_New(PyStdOut, &PyStdOut_Type);
+    if (self) {
+      self->softspace = 0;
+      self->out=&out;
+    }
+    return (PyObject*)self;
+  }
+
+  std::string parseException()
+  {
+    std::string error;
+    if (PyErr_Occurred())
+    {
+#ifdef BOS26455_WITH_BOOST_PYTHON
+      PyObject *ptype = nullptr;
+      PyObject *pvalue = nullptr;
+      PyObject *ptraceback = nullptr;
+      PyErr_Fetch(&ptype, &pvalue, &ptraceback);
+      if (ptype == nullptr)
+        return std::string("Null exception type");
+      PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
+      if (ptraceback != nullptr)
+        PyException_SetTraceback(pvalue, ptraceback);
+      boost::python::handle<> htype(ptype);
+      boost::python::handle<> hvalue(boost::python::allow_null(pvalue));
+      boost::python::handle<> htraceback(boost::python::allow_null(ptraceback));
+      boost::python::object traceback = boost::python::import("traceback");
+      boost::python::object format_exc = traceback.attr("format_exception");
+      boost::python::object formatted = format_exc(htype, hvalue, htraceback);
+      error = boost::python::extract<std::string>(boost::python::str("\n").join(formatted));
+#else
+      PyObject* new_stderr = newPyStdOut(error);
+      PyObject* old_stderr = PySys_GetObject((char*)"stderr");
+      Py_INCREF(old_stderr);
+      PySys_SetObject((char*)"stderr", new_stderr);
+      PyErr_Print();
+      PySys_SetObject((char*)"stderr", old_stderr);
+      Py_DECREF(new_stderr);
+#endif
+    }
+    return error;
+  }
+}
+  
+Engines::vectorOfDouble* Abstract_Engines_Container_i::loadOfCPUCores()
+{
+  AutoGIL gstate;
+  PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
+  AutoPyRef result = PyObject_CallMethod(module,
+                                         (char*)"loadOfCPUCores", "s",
+                                         _load_script.c_str());
+  if (PyErr_Occurred())
+  {
+    std::string error = parseException();
+    PyErr_Print();
+    SALOME::ExceptionStruct es;
+    es.type = SALOME::INTERNAL_ERROR;
+    es.text = CORBA::string_dup(error.c_str());
+    throw SALOME::SALOME_Exception(es);
+  }
+
+  int n = this->getNumberOfCPUCores();
+  if (!PyList_Check(result) || PyList_Size(result) != n) {
+    // bad number of cores
+    SALOME::ExceptionStruct es;
+    es.type = SALOME::INTERNAL_ERROR;
+    es.text = "wrong number of cores";
+    throw SALOME::SALOME_Exception(es);
+  }
+
+  Engines::vectorOfDouble_var loads = new Engines::vectorOfDouble;
+  loads->length(n);
+  for (Py_ssize_t i = 0; i < PyList_Size(result); ++i) {
+    PyObject* item = PyList_GetItem(result, i);
+    double foo = PyFloat_AsDouble(item);
+    if (foo < 0.0 || foo > 1.0)
+    {
+      // value not in [0, 1] range
+      SALOME::ExceptionStruct es;
+      es.type = SALOME::INTERNAL_ERROR;
+      es.text = "load not in [0, 1] range";
+      throw SALOME::SALOME_Exception(es);
+    }
+    loads[i] = foo;
+  }
+
+  return loads._retn();
+}
+
+//=============================================================================
+//! Set custom script to calculate a load of each CPU core
+/*!
+*  CORBA method: Set custom script to calculate CPU load
+*  \param script Python script to execute
+*/
+//=============================================================================
+
+void Abstract_Engines_Container_i::setPyScriptForCPULoad(const char *script)
+{
+  _load_script = script;
+}
+
+//=============================================================================
+//! Nullify custom script to calculate each CPU core's load
+/*!
+*  CORBA method: reset script for load calculation to default implementation
+*/
+//=============================================================================
+
+void Abstract_Engines_Container_i::resetScriptForCPULoad()
+{
+  _load_script = "";
+}
+
+//=============================================================================
+//! Get total physical memory of calculation node, in megabytes
+/*!
+*  CORBA method: get total physical memory of calculation node
+*/
+//=============================================================================
+
+CORBA::Long Abstract_Engines_Container_i::getTotalPhysicalMemory()
+{
+  AutoGIL gstate;
+  PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
+  AutoPyRef result = PyObject_CallMethod(module,
+                                         (char*)"getTotalPhysicalMemory", NULL);
+  int n = PyLong_AsLong(result);
+
+  return (CORBA::Long)n;
+}
+
+//=============================================================================
+//! Get used physical memory of calculation node, in megabytes
+/*!
+*  CORBA method: get used physical memory of calculation node
+*/
+//=============================================================================
+
+CORBA::Long Abstract_Engines_Container_i::getTotalPhysicalMemoryInUse()
+{
+  AutoGIL gstate;
+  PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
+  AutoPyRef result = PyObject_CallMethod(module,
+                                         (char*)"getTotalPhysicalMemoryInUse", NULL);
+  int n = PyLong_AsLong(result);
+
+  return (CORBA::Long)n;
+}
+
+//=============================================================================
+//! Obtain physical memory, used by the current process, in megabytes.
+/*!
+*  CORBA method: get physical memory, used by the current process
+*/
+//=============================================================================
+
+CORBA::Long Abstract_Engines_Container_i::getTotalPhysicalMemoryInUseByMe()
+{
+  AutoGIL gstate;
+  PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
+  AutoPyRef result = PyObject_CallMethod(module,
+                                         (char*)"getTotalPhysicalMemoryInUseByMe", NULL);
+  int n = PyLong_AsLong(result);
+
+  return (CORBA::Long)n;
+}
+
 //=============================================================================
 //! Shutdown the container
 /*! 
@@ -358,7 +708,25 @@ void Engines_Container_i::ping()
 *  - orb shutdown if no other servants in the process 
 */
 //=============================================================================
-void Engines_Container_i::Shutdown()
+void Abstract_Engines_Container_i::Shutdown()
+{
+  ShutdownCommonPart();
+  if(_isServantAloneInProcess)
+  {
+    MESSAGE("Effective Shutdown of container Begins...");
+    try
+    {
+      if(!CORBA::is_nil(_orb))
+        _orb->shutdown(0);
+    }
+    catch(...)
+    {
+    }
+    MESSAGE("Effective Shutdown of container Ends...");  
+  }
+}
+
+void Abstract_Engines_Container_i::ShutdownCommonPart()
 {
   MESSAGE("Engines_Container_i::Shutdown()");
 
@@ -375,7 +743,7 @@ void Engines_Container_i::Shutdown()
     {
       itm->second->destroy();
     }
-    catch(const CORBA::Exception& e)
+    catch(const CORBA::Exception&)
     {
       // ignore this entry and continue
     }
@@ -385,14 +753,39 @@ void Engines_Container_i::Shutdown()
     }
   }
   _listInstances_map.clear();
+  MESSAGE("Engines_Container_i::Shutdown() -- step 2");
+  // NS unregistering may throw in SSL mode if master process hosting SALOME_Embedded_NamingService servant has vanished
+  // In this case it's skip it and still continue.
+  try
+  {
+    _NS->Destroy_FullDirectory(_containerName.c_str());
+    _NS->Destroy_Name(_containerName.c_str());
+  }
+  catch(...)
+  {
+  }
+  MESSAGE("Engines_Container_i::Shutdown() -- step 3");
+  try
+  {
+    this->cleanAllPyScripts();
+    //
+    {
+      AutoGIL gstate;
+      AutoPyRef result = PyObject_CallMethod(_pyCont, (char*)"shutdownPy", (char*)"",nullptr);
+    }
+  }
+  catch(...)
+  {
+  }
+  MESSAGE("Engines_Container_i::Shutdown() -- step 4");
+}
 
-  _NS->Destroy_FullDirectory(_containerName.c_str());
-  _NS->Destroy_Name(_containerName.c_str());
-  if(_isServantAloneInProcess)
+void Abstract_Engines_Container_i::ShutdownNow()
+{
+  ShutdownCommonPart();if(_isServantAloneInProcess)
   {
-    MESSAGE("Effective Shutdown of container Begins...");
-    if(!CORBA::is_nil(_orb))
-      _orb->shutdown(0);
+    AutoGIL gstate;
+    AutoPyRef result = PyObject_CallMethod(_pyCont, (char*)"killMe", (char*)"",nullptr);
   }
 }
 
@@ -402,11 +795,11 @@ void Engines_Container_i::Shutdown()
 *  CORBA method
 *  \param componentName         component name
 *  \param reason                explains error when load fails
-*  \return true if dlopen successfull or already done, false otherwise
+*  \return true if dlopen successful or already done, false otherwise
 */
 //=============================================================================
 bool
-Engines_Container_i::load_component_Library(const char* componentName, CORBA::String_out reason)
+Abstract_Engines_Container_i::load_component_Library(const char* componentName, CORBA::String_out reason)
 {
 
   //=================================================================
@@ -490,11 +883,11 @@ Engines_Container_i::load_component_Library(const char* componentName, CORBA::St
 *  C++ method: 
 *  \param componentName      the name of the component (COMPONENT, for example)
 *  \param reason             explains error when load fails
-*  \return true if loading is successfull or already done, false otherwise
+*  \return true if loading is successful or already done, false otherwise
 */
 //=============================================================================
 bool
-Engines_Container_i::load_component_CppImplementation(const char* componentName, std::string& reason)
+Abstract_Engines_Container_i::load_component_CppImplementation(const char* componentName, std::string& reason)
 {
   std::string aCompName(componentName);
   std::string impl_name = std::string(LIB) + aCompName + ENGINESO;
@@ -514,39 +907,48 @@ Engines_Container_i::load_component_CppImplementation(const char* componentName,
 
 #ifndef WIN32
   void* handle;
-  handle = dlopen( impl_name.c_str() , RTLD_NOW ) ;
+  handle = dlopen( impl_name.c_str() , RTLD_NOW | RTLD_GLOBAL ) ;
   if ( !handle )
   {
     //not loadable. Try to find the lib file in LD_LIBRARY_PATH
     std::string path;
-    char* p=getenv("LD_LIBRARY_PATH");
-    if(p)path=p;
-    path=path+SEP+"/usr/lib"+SEP+"/lib";
-
-    std::string pth;
-    if(findpathof(path, pth, impl_name))
-    {
-      //found but not loadable
-      reason="Component ";
-      reason+=aCompName;
-      reason+=": C++ implementation found ";
-      reason+=pth;
-      reason+=" but it is not loadable. Error:\n";
-      reason+=dlerror();
-      std::cerr << reason << std::endl;
-      return false;
-    }
-    else
-    {
-      //not found
-      //continue with other implementation
-      reason="ImplementationNotFound";
-      return false;
+#ifdef __APPLE__
+      char* p=getenv("DYLD_LIBRARY_PATH");
+#else
+      char* p=getenv("LD_LIBRARY_PATH");
+#endif
+      if(p)path=p;
+      path=path+SEP+"/usr/lib"+SEP+"/lib";
+
+      std::string pth;
+      if(findpathof(path, pth, impl_name))
+        {
+          //found but not loadable
+          reason="Component ";
+          reason+=aCompName;
+          reason+=": C++ implementation found ";
+          reason+=pth;
+          reason+=" but it is not loadable. Error:\n";
+          reason+=dlerror();
+          std::cerr << reason << std::endl;
+          return false;
+        }
+      else
+        {
+          //not found
+          //continue with other implementation
+          reason="ImplementationNotFound";
+          return false;
     }
   }
 #else
   HINSTANCE handle;
-  handle = LoadLibrary( impl_name.c_str() );
+#ifdef UNICODE
+  std::wstring libToLoad = Kernel_Utils::utf8_decode_s( impl_name );
+#else
+  std::string libToLoad = impl_name;
+#endif
+  handle = LoadLibrary(libToLoad.c_str() );
   if ( !handle )
   {
     reason="ImplementationNotFound";
@@ -571,11 +973,11 @@ Engines_Container_i::load_component_CppImplementation(const char* componentName,
 *  C++ method: 
 *  \param componentName         name of the component
 *  \param reason                explains error when load fails
-*  \return true if loading is successfull or already done, false otherwise
+*  \return true if loading is successful or already done, false otherwise
 */
 //=============================================================================
 bool
-Engines_Container_i::load_component_PythonImplementation(const char* componentName, std::string& reason)
+Abstract_Engines_Container_i::load_component_PythonImplementation(const char* componentName, std::string& reason)
 {
   std::string aCompName(componentName);
 
@@ -588,15 +990,15 @@ Engines_Container_i::load_component_PythonImplementation(const char* componentNa
   }
   _numInstanceMutex.unlock() ;
 
-  PyGILState_STATE gstate = PyGILState_Ensure();
-  PyObject *result = PyObject_CallMethod(_pyCont,
-                                         (char*)"import_component",
-                                         (char*)"s",componentName);
+  {
+    AutoGIL gstate;
+    AutoPyRef result = PyObject_CallMethod(_pyCont,
+                                          (char*)"import_component",
+                                          (char*)"s",componentName);
 
-  reason=PyString_AsString(result);
-  Py_XDECREF(result);
-  SCRUTE(reason);
-  PyGILState_Release(gstate);
+    reason=PyUnicode_AsUTF8(result);
+    SCRUTE(reason);
+  }
 
   if (reason=="")
   {
@@ -626,11 +1028,11 @@ Engines_Container_i::load_component_PythonImplementation(const char* componentNa
 *  C++ method: 
 *  \param componentName        name of the component
 *  \param reason               explains error when load fails
-*  \return true if loading is successfull or already done, false otherwise
+*  \return true if loading is successful or already done, false otherwise
 */
 //=============================================================================
 bool
-Engines_Container_i::load_component_ExecutableImplementation(const char* componentName, std::string& reason)
+Abstract_Engines_Container_i::load_component_ExecutableImplementation(const char* componentName, std::string& reason)
 {
   std::string aCompName(componentName);
   std::string executable=aCompName+".exe";
@@ -670,14 +1072,14 @@ Engines_Container_i::load_component_ExecutableImplementation(const char* compone
 //! Create a new component instance
 /*! 
 *  CORBA method: Creates a new servant instance of a component.
-*  The servant registers itself to naming service and Registry.
+*  The servant registers itself to naming service and Registry.tdlib
 *  \param genericRegisterName  Name of the component instance to register
 *                         in Registry & Name Service (without _inst_n suffix)
 *  \return a loaded component
 */
 //=============================================================================
 Engines::EngineComponent_ptr
-Engines_Container_i::create_component_instance(const char*genericRegisterName)
+Abstract_Engines_Container_i::create_component_instance(const char*genericRegisterName)
 {
   Engines::FieldsDict_var env = new Engines::FieldsDict;
   char* reason;
@@ -687,6 +1089,136 @@ Engines_Container_i::create_component_instance(const char*genericRegisterName)
   return compo;
 }
 
+void EffectiveOverrideEnvironment( const Engines::FieldsDict& env )
+{
+  MESSAGE("Positionning environment on container ");
+  for (CORBA::ULong i=0; i < env.length(); i++)
+  {
+    if (env[i].value.type()->kind() == CORBA::tk_string)
+    {
+      const char *value = nullptr;
+      env[i].value >>= value;
+      MESSAGE( env[i].key << " = " << value);
+#ifndef WIN32
+      if( setenv(env[i].key,value,1) != 0 )
+      {
+        int errsv = errno;
+        std::string sErr( strerror( errsv) );
+        MESSAGE(sErr);
+      }
+#endif
+    }
+  }
+}
+
+std::vector< std::pair<std::string,std::string> > GetOSEnvironment()
+{
+  std::vector< std::pair<std::string,std::string> > ret;
+#ifndef WIN32
+  char **envPt( environ );
+  for(;*envPt != nullptr; ++envPt)
+  {
+    std::string s( *envPt );
+    auto pos = s.find_first_of('=');
+    std::string k( s.substr(0,pos) ),v( s.substr(pos+1) );
+    ret.emplace_back( std::pair<std::string,std::string>(k,v) );
+  }
+#endif
+  return ret;
+}
+
+void Abstract_Engines_Container_i::override_environment( const Engines::FieldsDict& env )
+{
+  EffectiveOverrideEnvironment(env);
+}
+
+void Abstract_Engines_Container_i::override_environment_python( const Engines::FieldsDict& env )
+{
+  constexpr char NODE_NAME[] = "ScriptNodeForEnv";
+  constexpr char SCRIPT[] = R"foo(
+import os
+for k,v in env:
+  os.environ[k] = v
+)foo";
+  Engines::PyScriptNode_var scriptNode = this->createPyScriptNode(NODE_NAME,SCRIPT);
+  auto sz = env.length();
+  Engines::listofstring keys, vals;
+  keys.length( sz ); vals.length( sz );
+  for( auto i = 0 ; i < sz ; ++i )
+  {
+    keys[i] = CORBA::string_dup( env[i].key );
+    const char *value = nullptr;
+    env[i].value >>= value;
+    vals[i] = CORBA::string_dup( value );
+  }
+  scriptNode->executeSimple(keys,vals);
+  this->removePyScriptNode(NODE_NAME);
+}
+
+Engines::FieldsDict *Abstract_Engines_Container_i::get_os_environment()
+{
+  std::unique_ptr<Engines::FieldsDict> ret( new Engines::FieldsDict );
+  std::vector< std::pair<std::string,std::string> > retCpp( GetOSEnvironment() );
+  auto sz = retCpp.size();
+  ret->length( sz );
+  for(auto i = 0 ; i < sz ; ++i)
+  {
+    (*ret)[i].key = CORBA::string_dup( retCpp[i].first.c_str() );
+    (*ret)[i].value <<= CORBA::string_dup( retCpp[i].second.c_str() );
+  }
+  return ret.release();
+}
+
+Engines::vectorOfString_var FromVecStringCppToCORBA( const std::vector<std::string>& group)
+{
+  Engines::vectorOfString_var ret( new Engines::vectorOfString );
+  auto sz( group.size() );
+  ret->length( sz );
+  for(auto i = 0 ; i < sz ; ++i)
+  {
+    ret[i] = CORBA::string_dup( group[i].c_str() );
+  }
+  return ret;
+}
+
+std::vector<std::string> FromCORBAVecStringToCpp(const Engines::vectorOfString& groupOfLogFileNames)
+{
+  auto len = groupOfLogFileNames.length();
+  std::vector<std::string> ret( len );
+  for( auto i = 0 ; i < len ; ++i )
+  {
+    ret[i] = groupOfLogFileNames[i];
+  }
+  return ret;
+}
+
+void Abstract_Engines_Container_i::addLogFileNameGroup(const Engines::vectorOfString& groupOfLogFileNames)
+{
+  this->_groups_of_log_files.push_back( FromCORBAVecStringToCpp(groupOfLogFileNames) );
+}
+    
+Engines::vectorOfVectorOfString *Abstract_Engines_Container_i::getAllLogFileNameGroups()
+{
+  std::unique_ptr<Engines::vectorOfVectorOfString> ret( new Engines::vectorOfVectorOfString );
+  auto nbOfGrps = this->_groups_of_log_files.size();
+  ret->length( nbOfGrps );
+  for(auto i = 0 ; i < nbOfGrps ; ++i)
+  {
+    (*ret)[i] = FromVecStringCppToCORBA( _groups_of_log_files[i] );
+  }
+  return ret.release();
+}
+
+void Abstract_Engines_Container_i::execute_python_code(const char *code)
+{
+  AutoGIL gstate;
+  if( PyRun_SimpleString( code ) != 0 )
+  {
+    std::string error = parseException();
+    THROW_SALOME_CORBA_EXCEPTION(error.c_str(),SALOME::INTERNAL_ERROR);
+  }
+}
+
 //=============================================================================
 //! Create a new component instance with environment variables specified
 /*! 
@@ -700,7 +1232,7 @@ Engines_Container_i::create_component_instance(const char*genericRegisterName)
 */
 //=============================================================================
 Engines::EngineComponent_ptr
-Engines_Container_i::create_component_instance_env(const char*genericRegisterName,
+Abstract_Engines_Container_i::create_component_instance_env(const char*genericRegisterName,
                                                    const Engines::FieldsDict& env,
                                                    CORBA::String_out reason)
 {
@@ -753,9 +1285,9 @@ Engines_Container_i::create_component_instance_env(const char*genericRegisterNam
 */
 //=============================================================================
 Engines::EngineComponent_ptr
-Engines_Container_i::createExecutableInstance(std::string CompName,
-                                              const Engines::FieldsDict& env,
-                                              std::string& reason)
+Abstract_Engines_Container_i::createExecutableInstance(std::string CompName,
+                                                      const Engines::FieldsDict& env,
+                                                      std::string& reason)
 {
   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
 
@@ -808,18 +1340,7 @@ Engines_Container_i::createExecutableInstance(std::string CompName,
   pid_t pid = fork();
   if(pid == 0) // child
   {
-    for (CORBA::ULong i=0; i < env.length(); i++)
-    {
-      if (env[i].value.type()->kind() == CORBA::tk_string)
-      {
-        const char* value;
-        env[i].value >>= value;
-        std::string s(env[i].key);
-        s+='=';
-        s+=value;
-        putenv(strdup(s.c_str()));
-      }
-    }
+    EffectiveOverrideEnvironment(env);
 
     execl("/bin/sh", "sh", "-c", command.c_str() , (char *)0);
     status=-1;
@@ -910,7 +1431,7 @@ Engines_Container_i::createExecutableInstance(std::string CompName,
 */
 //=============================================================================
 Engines::EngineComponent_ptr
-Engines_Container_i::createPythonInstance(std::string CompName,
+Abstract_Engines_Container_i::createPythonInstance(std::string CompName,
                                           std::string& reason)
 {
   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
@@ -924,20 +1445,20 @@ Engines_Container_i::createPythonInstance(std::string CompName,
   sprintf( aNumI , "%d" , numInstance ) ;
   std::string instanceName = CompName + "_inst_" + aNumI ;
   std::string component_registerName = _containerName + "/" + instanceName;
-
-  PyGILState_STATE gstate = PyGILState_Ensure();
-  PyObject *result = PyObject_CallMethod(_pyCont,
-                                         (char*)"create_component_instance",
-                                         (char*)"ss",
-                                         CompName.c_str(),
-                                         instanceName.c_str());
-  const char *ior;
-  const char *error;
-  PyArg_ParseTuple(result,"ss", &ior, &error);
-  std::string iors = ior;
-  reason=error;
-  Py_DECREF(result);
-  PyGILState_Release(gstate);
+  std::string iors;
+  {
+    AutoGIL gstate;
+    AutoPyRef result = PyObject_CallMethod(_pyCont,
+                                          (char*)"create_component_instance",
+                                          (char*)"ss",
+                                          CompName.c_str(),
+                                          instanceName.c_str());
+    const char *ior;
+    const char *error;
+    PyArg_ParseTuple(result,"ss", &ior, &error);
+    iors = ior;
+    reason=error;
+  }
 
   if( iors!="" )
   {
@@ -949,7 +1470,7 @@ Engines_Container_i::createPythonInstance(std::string CompName,
 }
 
 char *
-Engines_Container_i::create_python_service_instance(const char * CompName,
+Abstract_Engines_Container_i::create_python_service_instance(const char * CompName,
                                                     CORBA::String_out reason)
 {
   CORBA::Object_var object = CORBA::Object::_nil();
@@ -964,20 +1485,20 @@ Engines_Container_i::create_python_service_instance(const char * CompName,
   std::string instanceName = std::string(CompName) + "_inst_" + aNumI ;
   std::string component_registerName = _containerName + "/" + instanceName;
 
-  PyGILState_STATE gstate = PyGILState_Ensure();
-  PyObject *result = PyObject_CallMethod(_pyCont,
-                                         (char*)"create_component_instance",
-                                         (char*)"ss",
-                                         CompName,
-                                         instanceName.c_str());
-  const char *ior;
-  const char *error;
-  PyArg_ParseTuple(result,"ss", &ior, &error);
-  reason = CORBA::string_dup(error);
-  char * _ior = CORBA::string_dup(ior);
-  Py_DECREF(result);
-  PyGILState_Release(gstate);
-
+  char * _ior = nullptr;
+  {
+    AutoGIL gstate;
+    AutoPyRef result = PyObject_CallMethod(_pyCont,
+                                          (char*)"create_component_instance",
+                                          (char*)"ss",
+                                          CompName,
+                                          instanceName.c_str());
+    const char *ior;
+    const char *error;
+    PyArg_ParseTuple(result,"ss", &ior, &error);
+    reason = CORBA::string_dup(error);
+    _ior = CORBA::string_dup(ior);
+  }
   return _ior;
 }
 
@@ -1003,7 +1524,7 @@ Engines_Container_i::create_python_service_instance(const char * CompName,
 */
 //=============================================================================
 Engines::EngineComponent_ptr
-Engines_Container_i::createInstance(std::string genericRegisterName,
+Abstract_Engines_Container_i::createInstance(std::string genericRegisterName,
                                     void *handle,
                                     std::string& reason)
 {
@@ -1052,7 +1573,7 @@ Engines_Container_i::createInstance(std::string genericRegisterName,
     std::string component_registerName =
       _containerName + "/" + instanceName;
 
-    // --- Instanciate required CORBA object
+    // --- Instantiate required CORBA object
 
     PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
     id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
@@ -1084,7 +1605,7 @@ Engines_Container_i::createInstance(std::string genericRegisterName,
   }
   catch (...)
   {
-    reason="Container_i::createInstance exception catched";
+    reason="Container_i::createInstance exception caught";
     INFOS(reason) ;
   }
   return iobject._retn();
@@ -1100,7 +1621,7 @@ Engines_Container_i::createInstance(std::string genericRegisterName,
 */
 //=============================================================================
 Engines::EngineComponent_ptr
-Engines_Container_i::find_component_instance( const char* registeredName)
+Abstract_Engines_Container_i::find_component_instance( const char* registeredName)
 {
   Engines::EngineComponent_var anEngine = Engines::EngineComponent::_nil();
   std::map<std::string,Engines::EngineComponent_var>::iterator itm =_listInstances_map.begin();
@@ -1126,7 +1647,7 @@ Engines_Container_i::find_component_instance( const char* registeredName)
 */
 //=============================================================================
 
-void Engines_Container_i::remove_impl(Engines::EngineComponent_ptr component_i)
+void Abstract_Engines_Container_i::remove_impl(Engines::EngineComponent_ptr component_i)
 {
   ASSERT(! CORBA::is_nil(component_i));
   std::string instanceName = component_i->instanceName() ;
@@ -1144,7 +1665,7 @@ void Engines_Container_i::remove_impl(Engines::EngineComponent_ptr component_i)
 *  CORBA method: Discharges unused libraries from the container.
 */
 //=============================================================================
-void Engines_Container_i::finalize_removal()
+void Abstract_Engines_Container_i::finalize_removal()
 {
   MESSAGE("finalize unload : dlclose");
   _numInstanceMutex.lock(); // lock to be alone
@@ -1172,7 +1693,7 @@ void Engines_Container_i::finalize_removal()
 *
 */
 //=============================================================================
-void Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
+void Abstract_Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
 {
   if(_cntInstances_map.count(genericRegisterName)==0)
     return;
@@ -1214,8 +1735,8 @@ void Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
 //=============================================================================
 
 Engines::EngineComponent_ptr
-Engines_Container_i::load_impl( const char* genericRegisterName,
-                                const char* componentName )
+Abstract_Engines_Container_i::load_impl( const char* genericRegisterName,
+                                         const char* /*componentName*/ )
 {
   char* reason;
   std::string impl_name = std::string(LIB) + genericRegisterName + ENGINESO;
@@ -1226,6 +1747,27 @@ Engines_Container_i::load_impl( const char* genericRegisterName,
   return iobject._retn();
 }
 
+Engines::EmbeddedNamingService_ptr Abstract_Engines_Container_i::get_embedded_NS_if_ssl()
+{
+  SALOME_Embedded_NamingService_Client *nsc(dynamic_cast<SALOME_Embedded_NamingService_Client *>(this->_NS));
+  if(nsc)
+  {
+    Engines::EmbeddedNamingService_var obj = nsc->GetObject();
+    return Engines::EmbeddedNamingService::_duplicate(obj);
+  }
+  else
+  {
+    SALOME_Fake_NamingService *fns(dynamic_cast<SALOME_Fake_NamingService *>(this->_NS));
+    if(fns)
+    {
+      Engines::EmbeddedNamingService_var ret = GetEmbeddedNamingService();
+      return ret._retn();
+    }
+    else
+      return Engines::EmbeddedNamingService::_nil();
+  } 
+}
+
 //=============================================================================
 //! Finds an already existing component instance or create a new instance
 /*!
@@ -1250,8 +1792,8 @@ Engines_Container_i::load_impl( const char* genericRegisterName,
 //=============================================================================
 
 Engines::EngineComponent_ptr
-Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
-                                             std::string componentLibraryName)
+Abstract_Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
+                                                      std::string componentLibraryName)
 {
   std::string aGenRegisterName = genericRegisterName;
   std::string impl_name = componentLibraryName;
@@ -1286,7 +1828,7 @@ Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
     }
     catch (...)
     {
-      INFOS( "Container_i::load_impl catched" ) ;
+      INFOS( "Container_i::load_impl caught" ) ;
     }
     return iobject._retn();
   }
@@ -1298,10 +1840,10 @@ Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
 *  Retrieves only with container naming convention if it is a python container
 */
 //=============================================================================
-bool Engines_Container_i::isPythonContainer(const char* ContainerName)
+bool Abstract_Engines_Container_i::isPythonContainer(const char* ContainerName)
 {
   bool ret=false;
-  int len=strlen(ContainerName);
+  size_t len=strlen(ContainerName);
   if(len>=2)
     if(strcmp(ContainerName+len-2,"Py")==0)
       ret=true;
@@ -1315,7 +1857,7 @@ bool Engines_Container_i::isPythonContainer(const char* ContainerName)
 *  To remove :  never returns !
 */
 //=============================================================================
-bool Engines_Container_i::Kill_impl()
+bool Abstract_Engines_Container_i::Kill_impl()
 {
   MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
     << _containerName.c_str() << " machineName "
@@ -1384,9 +1926,9 @@ void SetCpuUsed() ;
 void CallCancelThread() ;
 
 #ifndef WIN32
-void SigIntHandler(int what ,
+void SigIntHandler(int /*what*/ ,
                    siginfo_t * siginfo ,
-                   void * toto ) 
+                   void * /*toto*/ ) 
 {
   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
   //             use of streams (and so on) should never be used because :
@@ -1482,14 +2024,14 @@ void SigIntHandler( int what )
 */
 //=============================================================================
 Engines::fileRef_ptr
-Engines_Container_i::createFileRef(const char* origFileName)
+Abstract_Engines_Container_i::createFileRef(const char* origFileName)
 {
   std::string origName(origFileName);
   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
 
   if (origName[0] != '/')
   {
-    INFOS("path of file to copy must be an absolute path begining with '/'");
+    INFOS("path of file to copy must be an absolute path beginning with '/'");
     return Engines::fileRef::_nil();
   }
 
@@ -1517,7 +2059,7 @@ Engines_Container_i::createFileRef(const char* origFileName)
 */
 //=============================================================================
 Engines::fileTransfer_ptr
-Engines_Container_i::getFileTransfer()
+Abstract_Engines_Container_i::getFileTransfer()
 {
   Engines::fileTransfer_var aFileTransfer
     = Engines::fileTransfer::_duplicate(_fileTransfer);
@@ -1528,7 +2070,7 @@ Engines_Container_i::getFileTransfer()
 //! Create a Salome file
 //=============================================================================
 Engines::Salome_file_ptr
-Engines_Container_i::createSalome_file(const char* origFileName)
+Abstract_Engines_Container_i::createSalome_file(const char* origFileName)
 {
   std::string origName(origFileName);
   if (CORBA::is_nil(_Salome_file_map[origName]))
@@ -1540,7 +2082,7 @@ Engines_Container_i::createSalome_file(const char* origFileName)
       aSalome_file->setLocalFile(origFileName);
       aSalome_file->recvFiles();
     }
-    catch (const SALOME::SALOME_Exception& e)
+    catch (const SALOME::SALOME_Exception& /*e*/) //!< TODO: unused variable
     {
       return Engines::Salome_file::_nil();
     }
@@ -1565,7 +2107,7 @@ Engines_Container_i::createSalome_file(const char* origFileName)
  * \param localFile the local file
  */
 //=============================================================================
-void Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
+void Abstract_Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
 {
   Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
 
@@ -1610,31 +2152,32 @@ void Engines_Container_i::copyFile(Engines::Container_ptr container, const char*
  * \return the PyNode
  */
 //=============================================================================
-Engines::PyNode_ptr Engines_Container_i::createPyNode(const char* nodeName, const char* code)
+Engines::PyNode_ptr Abstract_Engines_Container_i::createPyNode(const char* nodeName, const char* code)
 {
   Engines::PyNode_var node= Engines::PyNode::_nil();
-
-  PyGILState_STATE gstate = PyGILState_Ensure();
-  PyObject *res = PyObject_CallMethod(_pyCont,
-    (char*)"create_pynode",
-    (char*)"ss",
-    nodeName,
-    code);
-  if(res==NULL)
-  {
-    //internal error
-    PyErr_Print();
-    PyGILState_Release(gstate);
-    SALOME::ExceptionStruct es;
-    es.type = SALOME::INTERNAL_ERROR;
-    es.text = "can not create a python node";
-    throw SALOME::SALOME_Exception(es);
+  long ierr(-1);
+  std::string astr;
+  {
+    AutoGIL gstate;
+    PyObject *res = PyObject_CallMethod(_pyCont,
+      (char*)"create_pynode",
+      (char*)"ss",
+      nodeName,
+      code);
+    if(res==NULL)
+    {
+      //internal error
+      PyErr_Print();
+      SALOME::ExceptionStruct es;
+      es.type = SALOME::INTERNAL_ERROR;
+      es.text = "can not create a python node";
+      throw SALOME::SALOME_Exception(es);
+    }
+    ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
+    PyObject* result=PyTuple_GetItem(res,1);
+    astr = PyUnicode_AsUTF8(result);
+    Py_DECREF(res);
   }
-  long ierr=PyInt_AsLong(PyTuple_GetItem(res,0));
-  PyObject* result=PyTuple_GetItem(res,1);
-  std::string astr=PyString_AsString(result);
-  Py_DECREF(res);
-  PyGILState_Release(gstate);
   if(ierr==0)
   {
     Utils_Locker lck(&_mutexForDftPy);
@@ -1670,7 +2213,7 @@ Engines::PyNode_ptr Engines_Container_i::createPyNode(const char* nodeName, cons
  *
  */
 //=============================================================================
-Engines::PyNode_ptr  Engines_Container_i::getDefaultPyNode(const char *nodeName)
+Engines::PyNode_ptr Abstract_Engines_Container_i::getDefaultPyNode(const char *nodeName)
 {
   Utils_Locker lck(&_mutexForDftPy);
   std::map<std::string,Engines::PyNode_var>::iterator it(_dftPyNode.find(nodeName));
@@ -1693,31 +2236,31 @@ Engines::PyNode_ptr  Engines_Container_i::getDefaultPyNode(const char *nodeName)
  * \return the PyScriptNode
  */
 //=============================================================================
-Engines::PyScriptNode_ptr Engines_Container_i::createPyScriptNode(const char* nodeName, const char* code)
+Engines::PyScriptNode_ptr Abstract_Engines_Container_i::createPyScriptNode(const char* nodeName, const char* code)
 {
   Engines::PyScriptNode_var node= Engines::PyScriptNode::_nil();
-
-  PyGILState_STATE gstate = PyGILState_Ensure();
-  PyObject *res = PyObject_CallMethod(_pyCont,
-    (char*)"create_pyscriptnode",
-    (char*)"ss",
-    nodeName,
-    code);
-  if(res==NULL)
-  {
-    //internal error
-    PyErr_Print();
-    PyGILState_Release(gstate);
-    SALOME::ExceptionStruct es;
-    es.type = SALOME::INTERNAL_ERROR;
-    es.text = "can not create a python node";
-    throw SALOME::SALOME_Exception(es);
+  long ierr(-1);
+  std::string astr;
+  {
+    AutoGIL gstate;
+    AutoPyRef res = PyObject_CallMethod(_pyCont,
+      (char*)"create_pyscriptnode",
+      (char*)"ss",
+      nodeName,
+      code);
+    if( res.isNull() )
+    {
+      //internal error
+      PyErr_Print();
+      SALOME::ExceptionStruct es;
+      es.type = SALOME::INTERNAL_ERROR;
+      es.text = "can not create a python node";
+      throw SALOME::SALOME_Exception(es);
+    }
+    ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
+    PyObject* result=PyTuple_GetItem(res,1);
+    astr = PyUnicode_AsUTF8(result);
   }
-  long ierr=PyInt_AsLong(PyTuple_GetItem(res,0));
-  PyObject* result=PyTuple_GetItem(res,1);
-  std::string astr=PyString_AsString(result);
-  Py_DECREF(res);
-  PyGILState_Release(gstate);
 
   if(ierr==0)
   {
@@ -1736,8 +2279,6 @@ Engines::PyScriptNode_ptr Engines_Container_i::createPyScriptNode(const char* no
         oldNode->UnRegister();
       (*it).second=node;
     }
-    if(!CORBA::is_nil(node))
-      node->Register();
     return node._retn();
   }
   else
@@ -1749,12 +2290,45 @@ Engines::PyScriptNode_ptr Engines_Container_i::createPyScriptNode(const char* no
   }
 }
 
+void Abstract_Engines_Container_i::removePyScriptNode(const char *nodeName)
+{
+  std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
+  if(it==_dftPyScriptNode.end())
+    {
+      std::ostringstream oss; oss << "Engines_Container_i::removePyScriptNode : node \"" << nodeName << "\" is not map !";
+      SALOME::ExceptionStruct es;
+      es.type = SALOME::INTERNAL_ERROR;
+      es.text = oss.str().c_str();
+      throw SALOME::SALOME_Exception(es);
+    }
+  (*it).second->UnRegister();
+  _dftPyScriptNode.erase(it);
+}
+
+void Abstract_Engines_Container_i::cleanAllPyScripts()
+{
+  for(std::map<std::string,Engines::PyNode_var>::iterator it=_dftPyNode.begin();it!=_dftPyNode.end();it++)
+    {
+      Engines::PyNode_var tmpVar((*it).second);
+      if(!CORBA::is_nil(tmpVar))
+        tmpVar->UnRegister();
+    }
+  _dftPyNode.clear();
+  for(std::map<std::string,Engines::PyScriptNode_var>::iterator it=_dftPyScriptNode.begin();it!=_dftPyScriptNode.end();it++)
+    {
+      Engines::PyScriptNode_var tmpVar((*it).second);
+      if(!CORBA::is_nil(tmpVar))
+        tmpVar->UnRegister();
+    }
+  _dftPyScriptNode.clear();
+}
+
 //=============================================================================
 /*! \brief Retrieves the last created PyScriptNode instance with createPyScriptNode.
  *
  */
 //=============================================================================
-Engines::PyScriptNode_ptr Engines_Container_i::getDefaultPyScriptNode(const char *nodeName)
+Engines::PyScriptNode_ptr Abstract_Engines_Container_i::getDefaultPyScriptNode(const char *nodeName)
 {
   Utils_Locker lck(&_mutexForDftPy);
   std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
@@ -1830,28 +2404,86 @@ int findpathof(const std::string& path, std::string& pth, const std::string& fil
   return found;
 }
 
-void Engines_Container_i::registerTemporaryFile( const std::string& fileName )
+void Abstract_Engines_Container_i::registerTemporaryFile( const std::string& fileName )
 {
   _tmp_files.remove( fileName );
   _tmp_files.push_back( fileName );
 }
 
-void Engines_Container_i::unregisterTemporaryFile( const std::string& fileName )
+void Abstract_Engines_Container_i::unregisterTemporaryFile( const std::string& fileName )
 {
   _tmp_files.remove( fileName );
 }
 
-void Engines_Container_i::clearTemporaryFiles()
+void Abstract_Engines_Container_i::clearTemporaryFiles()
 {
   std::list<std::string>::const_iterator it;
   for ( it = _tmp_files.begin(); it != _tmp_files.end(); ++it ) {
-#ifdef WIN32
-    std::string command = "del /F /P";
+#if defined(WIN32) && defined(UNICODE)
+       std::wstring aFile = Kernel_Utils::utf8_decode_s(*it);
+       std::wstring command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? L"rd /Q \"" : L"del /F /Q \"";
+       command += aFile;
+       command += L"\" 2>NUL";
+       _wsystem(command.c_str());
+#else
+#if defined(WIN32)
+       std::string aFile = *it;
+       std::string command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? "rd /Q \"" : "del /F /Q \"";
+       command += aFile;
+       command += "\" 2>NUL";
 #else
-    std::string command = "rm -rf ";
+       std::string command = "rm -rf ";
+       command += *it;
+#endif
+       system(command.c_str());
 #endif
-    command += *it;
-    system( command.c_str() );
   }
   _tmp_files.clear();
 }
+
+static Engines_Container_SSL_i *_container_singleton_ssl = nullptr;
+
+static Engines::Container_var _container_ref_singleton_ssl;
+
+Abstract_Engines_Container_SSL_i *KERNEL::getContainerSA()
+{
+  if(!_container_singleton_ssl)
+  {
+    CORBA::ORB_var orb = KERNEL::GetRefToORB();
+    CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
+    PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);
+    PortableServer::POAManager_var pman = poa->the_POAManager();
+    CORBA::PolicyList policies;
+    policies.length(0);
+    //
+    constexpr int ARGC = 4;
+    constexpr const char *ARGV[ARGC] = {"Container","FactoryServer","toto",nullptr};
+    std::unique_ptr<char*[]> argv( new char *[ARGC+1] );
+    std::vector< std::unique_ptr<char[]> > argvv(ARGC);
+    argv[ARGC] = nullptr;
+    for(int i = 0 ; i < ARGC ; ++i)
+    {
+      if(ARGV[i])
+      {
+        argvv[i].reset( new char[strlen(ARGV[i])+1] );
+        strcpy(argvv[i].get(),ARGV[i]);
+        argv[i] = argvv[i].get();
+      }
+      else
+        argv[i] = nullptr;
+    }
+    SALOME_Fake_NamingService ns;
+    _container_singleton_ssl = new Engines_Container_SSL_i(orb,poa,(char *)"FactoryServer",2,argv.get(),&ns,false);
+    PortableServer::ObjectId * cont_id = _container_singleton_ssl->getCORBAId();
+    //
+    CORBA::Object_var zeRef = poa->id_to_reference(*cont_id);
+    _container_ref_singleton_ssl = Engines::Container::_narrow(zeRef);
+  }
+  return _container_singleton_ssl;
+}
+
+Engines::Container_var KERNEL::getContainerRefSA()
+{
+  getContainerSA();
+  return _container_ref_singleton_ssl;
+}