SALOME_ExternalServerLauncher.idl
SALOME_LogManager.idl
SALOME_Embedded_NamingService.idl
+ SALOME_Locker.idl
${CMAKE_CURRENT_BINARY_DIR}/Calcium_Ports.idl
)
SALOME_ContainerManager.cxx
Salome_file_i.cxx
SALOME_CPythonHelper.cxx
+ SALOME_LockMasterImpl.cxx
+ SALOME_LockServantImpl.cxx
)
ADD_LIBRARY(SalomeContainer ${SalomeContainer_SOURCES})
#include <SALOMEconfig.h>
#include CORBA_SERVER_HEADER(SALOME_Component)
#include CORBA_SERVER_HEADER(SALOME_PyNode)
+#include CORBA_SERVER_HEADER(SALOME_Locker)
#include <iostream>
#include <signal.h>
--- /dev/null
+// Copyright (C) 2024 CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SALOME_LockMasterImpl.hxx"
+#include "SALOME_LockServantImpl.hxx"
+
+#include "SALOME_KernelORB.hxx"
+
+#include <string>
+#include <map>
+
+static std::map<std::string,Engines::LockServant_var> _uniqueLockObj;
+
+Engines::LockServant_ptr SALOME::LockMasterImpl::getLockerFor(const char *key)
+{
+ std::string keyCpp(key);
+ auto it = _uniqueLockObj.find( keyCpp );
+ Engines::LockServant_var ret;
+ if( it != _uniqueLockObj.end() )
+ ret = it->second;
+ else
+ {
+ SALOME::LockServantImpl *serv = new SALOME::LockServantImpl;
+ ret = serv->_this();
+ serv->_remove_ref();
+ _uniqueLockObj[keyCpp] = ret;
+ }
+ return Engines::LockServant::_duplicate( ret );
+}
+
+Engines::RendezVousServant_ptr SALOME::LockMasterImpl::buildRendezVous(CORBA::Long nbClients)
+{
+ SALOME::RendezVousServantImpl *serv = new SALOME::RendezVousServantImpl(nbClients);
+ Engines::RendezVousServant_var ret = serv->_this();
+ serv->_remove_ref();
+ return Engines::RendezVousServant::_duplicate( ret );
+}
--- /dev/null
+// Copyright (C) 2024 CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#pragma once
+
+#include "SALOME_Container.hxx"
+
+#include <SALOMEconfig.h>
+
+#include CORBA_SERVER_HEADER(SALOME_Locker)
+
+namespace SALOME
+{
+ class CONTAINER_EXPORT LockMasterImpl : public virtual POA_Engines::LockMaster
+ {
+ public:
+ LockMasterImpl() = default;
+ Engines::LockServant_ptr getLockerFor(const char *key) override;
+ Engines::RendezVousServant_ptr buildRendezVous(CORBA::Long nbClients) override;
+ };
+}
--- /dev/null
+// Copyright (C) 2024 CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#include "SALOME_LockServantImpl.hxx"
+
+#include <stdexcept>
+
+#include <iostream>
+
+void SALOME::LockServantImpl::acquire()
+{
+ _mutex.lock();
+}
+
+void SALOME::LockServantImpl::release()
+{
+ _mutex.unlock();
+}
+
+SALOME::RendezVousServantImpl::RendezVousServantImpl(unsigned int nbOfClientsToWait):_nb_clients(nbOfClientsToWait)
+{
+ if( _nb_clients == 0 )
+ throw std::runtime_error("RendezVousServantImpl is supposed to be >= 1!");
+ _promise.resize( _nb_clients-1 );
+}
+
+void SALOME::RendezVousServantImpl::acquire()
+{
+ bool waitOrRelease = false;
+ {
+ std::lock_guard<std::mutex> lock(_mutex);
+ waitOrRelease = _nb_clients <= 1;
+ if( _nb_clients != 0)
+ _nb_clients--;
+ }
+ if( !waitOrRelease )//wait
+ _promise[_nb_clients-1].get_future().wait();
+ else//relase
+ {
+ for(auto& it : _promise)
+ it.set_value();
+ }
+}
--- /dev/null
+// Copyright (C) 2024 CEA, EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+#pragma once
+
+#include "SALOME_Container.hxx"
+
+#include <SALOMEconfig.h>
+
+#include CORBA_SERVER_HEADER(SALOME_Locker)
+
+#include <mutex>
+#include <future>
+#include <vector>
+
+namespace SALOME
+{
+ class CONTAINER_EXPORT LockServantImpl : public virtual POA_Engines::LockServant
+ {
+ public:
+ LockServantImpl() = default;
+ void acquire() override;
+ void release() override;
+ private:
+ std::mutex _mutex;
+ };
+
+ class CONTAINER_EXPORT RendezVousServantImpl : public virtual POA_Engines::RendezVousServant
+ {
+ public:
+ RendezVousServantImpl(unsigned int nbOfClientsToWait);
+ void acquire() override;
+ private:
+ std::vector< std::promise<void> > _promise;
+ std::mutex _mutex;
+ unsigned int _nb_clients;
+ };
+}
### end of check effectivity of manipulation locally
cp = pylauncher.GetRequestForGiveContainer("localhost","gg")
- cont = salome.cm.GiveContainer(cp)
- pyscript = cont.createPyScriptNode("testScript","""
+ with salome.ContainerLauncherCM(cp) as cont:
+ pyscript = cont.createPyScriptNode("testScript","""
import salome
salome.salome_init()
machines = salome.rm.ListAllResourceEntriesInCatalog()
structure = { machine : salome.rm.GetResourceDefinition( machine ) for machine in machines }
""") # retrieve the content remotely and then return it back to current process
+ import SALOME_PyNode
+ import pickle
+ poa = salome.orb.resolve_initial_references("RootPOA")
+ obj = SALOME_PyNode.SenderByte_i(poa,pickle.dumps( ([],{}) ))
+ id_o = poa.activate_object(obj)
+ refPtr = poa.id_to_reference(id_o)
+ #
+ pyscript.executeFirst(refPtr)
+ ret = pyscript.executeSecond(["structure"])
+ ret = ret[0]
+ retPy = pickle.loads( SALOME_PyNode.SeqByteReceiver(ret).data() )
+
+ self.assertTrue( len(localStructure) == len(retPy) )
+ self.assertTrue( "zFakeHost" in [elt for elt in localStructure])
+ self.assertTrue( localStructure["zFakeHost"].applipath == "/home/appli/fakeappli")
+ self.assertTrue( "zzFakeHost" in [elt for elt in localStructure])
+ self.assertTrue( localStructure["zzFakeHost"].applipath == "/home/appli/zzfakeappli")
+ for k in localStructure:
+ a = pylauncher.FromEngineResourceDefinitionToCPP( localStructure[k] )
+ self.assertTrue( isinstance(a,pylauncher.ResourceDefinition_cpp) )
+ b = pylauncher.FromEngineResourceDefinitionToCPP( retPy[k] )
+ self.assertTrue( isinstance(b,pylauncher.ResourceDefinition_cpp) )
+ self.assertTrue( a==b ) #<- key point is here
+ a1 = pylauncher.ToEngineResourceDefinitionFromCPP( a )
+ b1 = pylauncher.ToEngineResourceDefinitionFromCPP( b )
+ a2 = pylauncher.FromEngineResourceDefinitionToCPP( a1 )
+ b2 = pylauncher.FromEngineResourceDefinitionToCPP( b1 )
+ self.assertTrue( a2==b2 )
+
+ def testMultiProcessCriticalSection0(self):
+ """
+ [EDF30382] : Synchro mecanism to ease test of extreme situations
+ """
+ from datetime import datetime
+ from threading import Thread
+ import contextlib
import SALOME_PyNode
- import pickle
- poa = salome.orb.resolve_initial_references("RootPOA")
- obj = SALOME_PyNode.SenderByte_i(poa,pickle.dumps( ([],{}) ))
- id_o = poa.activate_object(obj)
- refPtr = poa.id_to_reference(id_o)
- #
- pyscript.executeFirst(refPtr)
- ret = pyscript.executeSecond(["structure"])
- ret = ret[0]
- retPy = pickle.loads( SALOME_PyNode.SeqByteReceiver(ret).data() )
-
- assert( len(localStructure) == len(retPy) )
- for k in localStructure:
- a = pylauncher.FromEngineResourceDefinitionToCPP( localStructure[k] )
- self.assertTrue( isinstance(a,pylauncher.ResourceDefinition_cpp) )
- b = pylauncher.FromEngineResourceDefinitionToCPP( retPy[k] )
- self.assertTrue( isinstance(b,pylauncher.ResourceDefinition_cpp) )
- self.assertTrue( a==b ) #<- key point is here
- a1 = pylauncher.ToEngineResourceDefinitionFromCPP( a )
- b1 = pylauncher.ToEngineResourceDefinitionFromCPP( b )
- a2 = pylauncher.FromEngineResourceDefinitionToCPP( a1 )
- b2 = pylauncher.FromEngineResourceDefinitionToCPP( b1 )
- self.assertTrue( a2==b2 )
- cont.Shutdown()
+ import time
+
+ def func(pyscript,b):
+ poa = salome.orb.resolve_initial_references("RootPOA")
+ obj = SALOME_PyNode.SenderByte_i(poa,pickle.dumps( (["b"],{"b":b} ) )) ; id_o = poa.activate_object(obj) ; refPtr = poa.id_to_reference(id_o)
+ pyscript.executeFirst(refPtr)
+ ret = pyscript.executeSecond([])
+ retPy = [ pickle.loads( SALOME_PyNode.SeqByteReceiver( elt ).data() ) for elt in ret]
+ return retPy
+
+ salome.salome_init()
+ rmcpp = pylauncher.RetrieveRMCppSingleton()
+ hostname = "localhost"
+ cps = [ pylauncher.GetRequestForGiveContainer(hostname,contName) for contName in ["container_test_lock","container_test_lock_2"]]
+ with contextlib.ExitStack() as stack:
+ conts = [stack.enter_context(salome.ContainerLauncherCM(cp)) for cp in cps] # Context Manager to automatically cleanup launched containers
+ b = salome.Barrier(3)
+ pyscript = conts[0].createPyScriptNode("testScript","""
+from datetime import datetime
+import salome
+import time
+time.sleep( 2.0 )
+b.barrier()
+print("go barrier")
+print("after barrier T0 : {}".format(datetime.now()))
+with salome.LockGuardCM("SSD"):
+ print("Start CS T0 : {}".format(datetime.now()))
+ time.sleep(5)
+ print("End CS T0 : {}".format(datetime.now()))
+""")
+ pyscript2 = conts[1].createPyScriptNode("testScript","""
+from datetime import datetime
+import salome
+import time
+time.sleep( 4.0 )
+b.barrier()
+print("go barrier")
+print("after barrier T1 : {}".format(datetime.now()))
+with salome.LockGuardCM("SSD"):
+ print("Start CS T1 : {}".format(datetime.now()))
+ time.sleep(5)
+ print("End CS T1 : {}".format(datetime.now()))
+""")
+ ts = [Thread( target=func, args=(ps,b) ) for ps in [pyscript,pyscript2]]
+ [t.start() for t in ts]
+ st0 = datetime.now()
+ time.sleep( 1.0 )
+ b.barrier() # wait everybody
+ print("go barrier")
+ print("after barrier Master : {}".format(datetime.now()))
+ with salome.LockGuardCM("SSD"):
+ print("In critical section")
+ [t.join() for t in ts]
+ zedelt = datetime.now() - st0
+ assert( zedelt.total_seconds() > 14.0 ) # expected max(1,2,4)+5+5 = 14s
+ pass
+ pass
+
if __name__ == '__main__':
salome.standalone()
# sys.setdlopenflags(flags)
# pass
-orb, lcc, naming_service, cm, sg, esm, dsm, logm, modulcat, rm = None,None,None,None,None,None,None,None,None,None
+orb, lcc, naming_service, cm, sg, esm, dsm, logm, modulcat, rm, lm = None,None,None,None,None,None,None,None,None,None,None
myStudy, myStudyName = None,None
salome_initial=True
A Fake NamingService is created storing reference of all servants in the current process.
"""
salome_init_without_session_common(path,embedded)
- global lcc,cm,dsm,esm,rm,logm
+ global lcc,cm,dsm,esm,rm,logm,lm
import KernelLauncher
cm = KernelLauncher.myContainerManager()
type(cm).SetOverrideEnvForContainersSimple = ContainerManagerSetOverrideEnvForContainersSimple
# create a FactoryServer Container servant
import KernelContainer
KernelContainer.myContainer()
+ lm = KernelLauncher.myLockMaster()
# activate poaManager to accept co-localized CORBA calls.
from KernelSDS import GetDSMInstance
import sys
lcc is pointing to the FakeNamingService above.
"""
salome_init_without_session_common(path,embedded)
- global lcc,cm,dsm,esm,rm,logm
+ global lcc,cm,dsm,esm,rm,logm,lm
import CORBA
orb=CORBA.ORB_init([''])
import Engines
import KernelBasis
+ import KernelLauncher
nsAbroad = orb.string_to_object( KernelBasis.getIOROfEmbeddedNS() )
import SALOME
cm = orb.string_to_object( nsAbroad.Resolve(CM_NAME_IN_NS).decode() )
#
logm = orb.string_to_object( nsAbroad.Resolve(LOGM_NAME_IN_NS).decode() )
naming_service.Register(logm,LOGM_NAME_IN_NS)
+ #
+ lm = orb.string_to_object( nsAbroad.Resolve(KernelLauncher.GetLockMasterEntryInNS()).decode() )
+ naming_service.Register(lm,KernelLauncher.GetLockMasterEntryInNS())
def salome_init_with_session(path=None, embedded=False):
"""
logging.warning("in LogManagerGetLatestMonitoringDumpFile an unexpected situation araises.")
return ""
+class Barrier:
+ def __init__(self, nbClients):
+ import CORBA
+ orb=CORBA.ORB_init([''])
+ self._ior = orb.object_to_string( lm.buildRendezVous( nbClients ) )
+ def barrier(self):
+ import CORBA
+ import Engines
+ orb=CORBA.ORB_init([''])
+ rvPtr = orb.string_to_object( self._ior )
+ rvPtr.acquire()
+
+class LockGuardCM:
+ def __init__(self, key):
+ if lm is None:
+ raise RuntimeError("SALOME has not been initialized !")
+ self._lock = lm.getLockerFor( key )
+ def __enter__(self):
+ self._lock.acquire()
+ def __exit__(self,exctype, exc, tb):
+ self._lock.release()
+
+class ContainerLauncherCM:
+ def __init__(self, cp, aggressiveShutdown = False):
+ """
+ :param cp: Engines.ContainerParameters instance specifying the request where the container will be launched
+ :param aggressiveShutdown:
+ """
+ self._cp = cp
+ self.aggressiveShutdown = aggressiveShutdown
+ def __enter__(self):
+ self._cont = cm.GiveContainer(self._cp)
+ return self._cont
+ def __exit__(self,exctype, exc, tb):
+ if not self.aggressiveShutdown:
+ self._cont.Shutdown()
+ else:
+ try:# we are in aggressive situation the following call is not expected to return normally
+ self._cont.ShutdownNow()
+ except:
+ pass
+
#to expose all objects to pydoc
__all__ = dir()
#include "SALOME_ExternalServerLauncher.hxx"
#include "SALOME_LogManager.hxx"
#include "SALOME_CPythonHelper.hxx"
+#include "SALOME_LockMasterImpl.hxx"
#include <cstring>
#include <sstream>
static Engines::LogManager_var LogManagerInstanceSingleton;
static SALOME::ExternalServerLauncher_var ExternalServerLauncherSingleton;
+static Engines::LockMaster_var LockMasterSingleton;
+static const char LockMasterEntryInNS[] = "/LockMaster";
std::string RetrieveInternalInstanceOfLocalCppResourcesManager()
{
CORBA::String_var ior = orb->object_to_string(LogManagerInstanceSingleton);
return std::string(ior.in());
}
+
+std::string GetLockMasterEntryInNS()
+{
+ return std::string( LockMasterEntryInNS );
+}
+
+std::string GetLockMasterInstance()
+{
+ CORBA::ORB_ptr orb = KERNEL::getORB();
+ if( CORBA::is_nil(LockMasterSingleton) )
+ {
+ SALOME_Fake_NamingService ns;
+ SALOME::LockMasterImpl *serv = new SALOME::LockMasterImpl;
+ {
+ CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
+ PortableServer::POA_var root_poa = PortableServer::POA::_narrow(obj);
+ //
+ CORBA::PolicyList policies;
+ policies.length(1);
+ PortableServer::POAManager_var pman = root_poa->the_POAManager();
+ PortableServer::ThreadPolicy_var threadPol(root_poa->create_thread_policy(PortableServer::SINGLE_THREAD_MODEL));
+ policies[0] = PortableServer::ThreadPolicy::_duplicate(threadPol);
+ PortableServer::POA_var safePOA = root_poa->create_POA("SingleThreadPOAForLockMaster",pman,policies);
+ threadPol->destroy();
+ //
+ PortableServer::ObjectId_var id(safePOA->activate_object(serv));
+ CORBA::Object_var lmPtr(safePOA->id_to_reference(id));
+ LockMasterSingleton = Engines::LockMaster::_narrow( lmPtr );
+ }
+ serv->_remove_ref();
+ ns.Register(LockMasterSingleton,LockMasterEntryInNS);
+ }
+ CORBA::String_var ior = orb->object_to_string( LockMasterSingleton );
+ return std::string(ior.in());
+}
std::string GetContainerManagerInstance();
std::string GetResourcesManagerInstance();
std::string GetExternalServerInstance();
-std::string GetLogManagerInstance();
\ No newline at end of file
+std::string GetLogManagerInstance();
+std::string GetLockMasterEntryInNS();
+std::string GetLockMasterInstance();
std::string GetResourcesManagerInstance();
std::string GetExternalServerInstance();
std::string GetLogManagerInstance();
+ std::string GetLockMasterEntryInNS();
+ std::string GetLockMasterInstance();
}
%pythoncode %{
import CORBA
orb=CORBA.ORB_init([''])
return orb.string_to_object(GetLogManagerInstance())
+
+def myLockMaster():
+ import Engines
+ import CORBA
+ orb=CORBA.ORB_init([''])
+ return orb.string_to_object(GetLockMasterInstance())
%}