+// Copyright (C) 2005 OPEN CASCADE, CEA, EDF R&D, LEG
+// PRINCIPIA R&D, EADS CCR, Lip6, BV, CEDRAT
+// 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.
+//
+// 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
+//
- * BatchManager_Local.cxx :
- *
- * Auteur : Ivan DUTKA-MALEN - EDF R&D
- * Mail : mailto:ivan.dutka-malen@der.edf.fr
- * Date : Thu Nov 6 10:17:22 2003
- * Projet : Salome 2
- *
- */
+* BatchManager_Local.cxx :
+*
+* Auteur : Ivan DUTKA-MALEN - EDF R&D
+* Mail : mailto:ivan.dutka-malen@der.edf.fr
+* Date : Thu Nov 6 10:17:22 2003
+* Projet : Salome 2
+*
+*/
- BatchManager_Local::BatchManager_Local(const FactBatchManager * parent, const char * host) throw(InvalidArgumentException,ConnexionFailureException) : BatchManager(parent, host), _connect(0), _threads_mutex(), _threads(), _thread_id_id_association_mutex(), _thread_id_id_association_cond(), _thread_id_id_association()
+ BatchManager_Local::BatchManager_Local(const FactBatchManager * parent, const char * host) throw(InvalidArgumentException,ConnexionFailureException) : BatchManager(parent, host), _connect(0), _threads_mutex(), _threads(), _thread_id_id_association_mutex(), _thread_id_id_association_cond()
+#ifndef WIN32 //TODO: porting of following functionality
+ ,_thread_id_id_association()
+#endif
while (_thread_id_id_association.find(thread_id) == _thread_id_id_association.end())
pthread_cond_wait(&_thread_id_id_association_cond, &_thread_id_id_association_mutex);
id = _thread_id_id_association[thread_id];
_thread_id_id_association.erase(thread_id);
while (_thread_id_id_association.find(thread_id) == _thread_id_id_association.end())
pthread_cond_wait(&_thread_id_id_association_cond, &_thread_id_id_association_mutex);
id = _thread_id_id_association[thread_id];
_thread_id_id_association.erase(thread_id);
// On autorise la terminaison differee du thread
// (ces valeurs sont les valeurs par defaut mais on les force par precaution)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
// On autorise la terminaison differee du thread
// (ces valeurs sont les valeurs par defaut mais on les force par precaution)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
- CoupleType cpt = *static_cast< CoupleType * >(*Vit);
- Couple cp = cpt;
- string local = cp.getLocal();
- string remote = cp.getRemote();
-
- string copy_cmd = p_ta->getBatchManager().copy_command("", local, executionhost, workdir + "/" + remote);
- UNDER_LOCK( cout << "Copying : " << copy_cmd << endl );
-
- if (system(copy_cmd.c_str()) ) {
- // Echec de la copie
- rc |= 1;
- } else {
- // On enregistre le fichier comme etant a detruire
- files_to_delete.push_back(workdir + "/" + remote);
- }
+ CoupleType cpt = *static_cast< CoupleType * >(*Vit);
+ Couple cp = cpt;
+ string local = cp.getLocal();
+ string remote = cp.getRemote();
+
+ string copy_cmd = p_ta->getBatchManager().copy_command("", local, executionhost, workdir + "/" + remote);
+ UNDER_LOCK( cout << "Copying : " << copy_cmd << endl );
+
+ if (system(copy_cmd.c_str()) ) {
+ // Echec de la copie
+ rc |= 1;
+ } else {
+ // On enregistre le fichier comme etant a detruire
+ files_to_delete.push_back(workdir + "/" + remote);
+ }
- CoupleType cpt = *static_cast< CoupleType * >(*Vit);
- Couple cp = cpt;
- string local = cp.getLocal();
- string remote = cp.getRemote();
-
- string copy_cmd = p_ta->getBatchManager().copy_command(executionhost, workdir + "/" + remote, "", local);
- UNDER_LOCK( cout << "Copying : " << copy_cmd << endl );
-
- if (system(copy_cmd.c_str()) ) {
- // Echec de la copie
- rc |= 1;
- } else {
- // On enregistre le fichier comme etant a detruire
- files_to_delete.push_back(workdir + "/" + remote);
- }
+ CoupleType cpt = *static_cast< CoupleType * >(*Vit);
+ Couple cp = cpt;
+ string local = cp.getLocal();
+ string remote = cp.getRemote();
+
+ string copy_cmd = p_ta->getBatchManager().copy_command(executionhost, workdir + "/" + remote, "", local);
+ UNDER_LOCK( cout << "Copying : " << copy_cmd << endl );
+
+ if (system(copy_cmd.c_str()) ) {
+ // Echec de la copie
+ rc |= 1;
+ } else {
+ // On enregistre le fichier comme etant a detruire
+ files_to_delete.push_back(workdir + "/" + remote);
+ }
- string remove_cmd = p_ta->getBatchManager().remove_command(executionhost, *it);
- UNDER_LOCK( cout << "Removing : " << remove_cmd << endl );
- system(remove_cmd.c_str());
+ string remove_cmd = p_ta->getBatchManager().remove_command(executionhost, *it);
+ UNDER_LOCK( cout << "Removing : " << remove_cmd << endl );
+ system(remove_cmd.c_str());
- if (WIFSTOPPED(child_rc)) {
- // NOTA : pour rentrer dans cette section, il faut que le flag WUNTRACED
- // soit positionne dans l'appel a waitpid ci-dessus. Ce flag est couramment
- // desactive car s'il est possible de detecter l'arret d'un process, il est
- // plus difficile de detecter sa reprise.
-
- // Le fils est simplement stoppe
- // @@@ --------> SECTION CRITIQUE <-------- @@@
- pthread_mutex_lock(&_bm._threads_mutex);
- _bm._threads[id].status = STOPPED;
- _bm._threads[id].param[STATE] = "Stopped";
- pthread_mutex_unlock(&_bm._threads_mutex);
- // @@@ --------> SECTION CRITIQUE <-------- @@@
- UNDER_LOCK( cout << "Father sees his child is STOPPED : " << child_wait_rc << endl );
-
- }
- else {
- // Le fils est termine, on sort de la boucle et du if englobant
- // @@@ --------> SECTION CRITIQUE <-------- @@@
- pthread_mutex_lock(&_bm._threads_mutex);
- _bm._threads[id].status = DONE;
- _bm._threads[id].param[STATE] = "Done";
- pthread_mutex_unlock(&_bm._threads_mutex);
- // @@@ --------> SECTION CRITIQUE <-------- @@@
- UNDER_LOCK( cout << "Father sees his child is DONE : " << child_wait_rc << " (child_rc=" << (WIFEXITED(child_rc) ? WEXITSTATUS(child_rc) : -1) << ")" << endl );
- break;
- }
+ if (WIFSTOPPED(child_rc)) {
+ // NOTA : pour rentrer dans cette section, il faut que le flag WUNTRACED
+ // soit positionne dans l'appel a waitpid ci-dessus. Ce flag est couramment
+ // desactive car s'il est possible de detecter l'arret d'un process, il est
+ // plus difficile de detecter sa reprise.
+
+ // Le fils est simplement stoppe
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+ pthread_mutex_lock(&_bm._threads_mutex);
+ _bm._threads[id].status = STOPPED;
+ _bm._threads[id].param[STATE] = "Stopped";
+ pthread_mutex_unlock(&_bm._threads_mutex);
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+ UNDER_LOCK( cout << "Father sees his child is STOPPED : " << child_wait_rc << endl );
+
+ }
+ else {
+ // Le fils est termine, on sort de la boucle et du if englobant
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+ pthread_mutex_lock(&_bm._threads_mutex);
+ _bm._threads[id].status = DONE;
+ _bm._threads[id].param[STATE] = "Done";
+ pthread_mutex_unlock(&_bm._threads_mutex);
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+ UNDER_LOCK( cout << "Father sees his child is DONE : " << child_wait_rc << " (child_rc=" << (WIFEXITED(child_rc) ? WEXITSTATUS(child_rc) : -1) << ")" << endl );
+ break;
+ }
- // Le fils a disparu ...
- // @@@ --------> SECTION CRITIQUE <-------- @@@
- pthread_mutex_lock(&_bm._threads_mutex);
- _bm._threads[id].status = DEAD;
- _bm._threads[id].param[STATE] = "Dead";
- pthread_mutex_unlock(&_bm._threads_mutex);
- // @@@ --------> SECTION CRITIQUE <-------- @@@
- UNDER_LOCK( cout << "Father sees his child is DEAD : " << child_wait_rc << " (Reason : " << strerror(errno) << ")" << endl );
- break;
+ // Le fils a disparu ...
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+ pthread_mutex_lock(&_bm._threads_mutex);
+ _bm._threads[id].status = DEAD;
+ _bm._threads[id].param[STATE] = "Dead";
+ pthread_mutex_unlock(&_bm._threads_mutex);
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+ UNDER_LOCK( cout << "Father sees his child is DEAD : " << child_wait_rc << " (Reason : " << strerror(errno) << ")" << endl );
+ break;
- int maxwalltime = param[MAXWALLTIME];
- // cout << "child_starttime = " << child_starttime << endl
- // << "child_currenttime = " << child_currenttime << endl
- // << "child_elapsedtime = " << child_elapsedtime << endl
- // << "maxwalltime = " << maxwalltime << endl
- // << "int(maxwalltime * 1.1) = " << int(maxwalltime * 1.1) << endl;
- if (child_elapsedtime > int(maxwalltime * 1.1) ) { // On se donne 10% de marge avant le KILL
- UNDER_LOCK( cout << "Father is sending KILL command to the thread " << id << endl );
- // On introduit une commande dans la queue du thread
- // @@@ --------> SECTION CRITIQUE <-------- @@@
- pthread_mutex_lock(&_bm._threads_mutex);
- if (_bm._threads.find(id) != _bm._threads.end())
- _bm._threads[id].command_queue.push(KILL);
- pthread_mutex_unlock(&_bm._threads_mutex);
- // @@@ --------> SECTION CRITIQUE <-------- @@@
-
-
- } else if (child_elapsedtime > maxwalltime ) {
- UNDER_LOCK( cout << "Father is sending TERM command to the thread " << id << endl );
- // On introduit une commande dans la queue du thread
- // @@@ --------> SECTION CRITIQUE <-------- @@@
- pthread_mutex_lock(&_bm._threads_mutex);
- if (_bm._threads.find(id) != _bm._threads.end())
- _bm._threads[id].command_queue.push(TERM);
- pthread_mutex_unlock(&_bm._threads_mutex);
- // @@@ --------> SECTION CRITIQUE <-------- @@@
- }
+ int maxwalltime = param[MAXWALLTIME];
+ // cout << "child_starttime = " << child_starttime << endl
+ // << "child_currenttime = " << child_currenttime << endl
+ // << "child_elapsedtime = " << child_elapsedtime << endl
+ // << "maxwalltime = " << maxwalltime << endl
+ // << "int(maxwalltime * 1.1) = " << int(maxwalltime * 1.1) << endl;
+ if (child_elapsedtime > int(maxwalltime * 1.1) ) { // On se donne 10% de marge avant le KILL
+ UNDER_LOCK( cout << "Father is sending KILL command to the thread " << id << endl );
+ // On introduit une commande dans la queue du thread
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+ pthread_mutex_lock(&_bm._threads_mutex);
+ if (_bm._threads.find(id) != _bm._threads.end())
+ _bm._threads[id].command_queue.push(KILL);
+ pthread_mutex_unlock(&_bm._threads_mutex);
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+
+
+ } else if (child_elapsedtime > maxwalltime ) {
+ UNDER_LOCK( cout << "Father is sending TERM command to the thread " << id << endl );
+ // On introduit une commande dans la queue du thread
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+ pthread_mutex_lock(&_bm._threads_mutex);
+ if (_bm._threads.find(id) != _bm._threads.end())
+ _bm._threads[id].command_queue.push(TERM);
+ pthread_mutex_unlock(&_bm._threads_mutex);
+ // @@@ --------> SECTION CRITIQUE <-------- @@@
+ }
- while (_bm._threads[id].command_queue.size() > 0) {
- Commande cmd = _bm._threads[id].command_queue.front();
- _bm._threads[id].command_queue.pop();
-
- switch (cmd) {
- case NOP:
- UNDER_LOCK( cout << "Father does nothing to his child" << endl );
- break;
-
- case HOLD:
- UNDER_LOCK( cout << "Father is sending SIGSTOP signal to his child" << endl );
- kill(child, SIGSTOP);
- break;
-
- case RELEASE:
- UNDER_LOCK( cout << "Father is sending SIGCONT signal to his child" << endl );
- kill(child, SIGCONT);
- break;
-
- case TERM:
- UNDER_LOCK( cout << "Father is sending SIGTERM signal to his child" << endl );
- kill(child, SIGTERM);
- break;
-
- case KILL:
- UNDER_LOCK( cout << "Father is sending SIGKILL signal to his child" << endl );
- kill(child, SIGKILL);
- break;
-
- case ALTER:
- break;
-
- default:
- break;
- }
- }
-
+ while (_bm._threads[id].command_queue.size() > 0) {
+ Commande cmd = _bm._threads[id].command_queue.front();
+ _bm._threads[id].command_queue.pop();
+
+ switch (cmd) {
+ case NOP:
+ UNDER_LOCK( cout << "Father does nothing to his child" << endl );
+ break;
+
+ case HOLD:
+ UNDER_LOCK( cout << "Father is sending SIGSTOP signal to his child" << endl );
+ kill(child, SIGSTOP);
+ break;
+
+ case RELEASE:
+ UNDER_LOCK( cout << "Father is sending SIGCONT signal to his child" << endl );
+ kill(child, SIGCONT);
+ break;
+
+ case TERM:
+ UNDER_LOCK( cout << "Father is sending SIGTERM signal to his child" << endl );
+ kill(child, SIGTERM);
+ break;
+
+ case KILL:
+ UNDER_LOCK( cout << "Father is sending SIGKILL signal to his child" << endl );
+ kill(child, SIGKILL);
+ break;
+
+ case ALTER:
+ break;
+
+ default:
+ break;
+ }
+ }
+
- // On se place dans le repertoire de travail
- if ( (it = param.find(WORKDIR)) != param.end() ) {
- string workdir = static_cast<string>( (*it).second );
- chdir(workdir.c_str());
- }
+ // On se place dans le repertoire de travail
+ if ( (it = param.find(WORKDIR)) != param.end() ) {
+ string workdir = static_cast<string>( (*it).second );
+ chdir(workdir.c_str());
+ }
- // EXECUTABLE is MANDATORY, if missing, we exit with failure notification
- char * execpath = NULL;
- if (param.find(EXECUTABLE) != param.end()) {
- string executable = _bm.exec_command(param);
- execpath = new char [executable.size() + 1];
- strncpy(execpath, executable.c_str(), executable.size() + 1);
- } else exit(1);
+ // EXECUTABLE is MANDATORY, if missing, we exit with failure notification
+ char * execpath = NULL;
+ if (param.find(EXECUTABLE) != param.end()) {
+ string executable = _bm.exec_command(param);
+ execpath = new char [executable.size() + 1];
+ strncpy(execpath, executable.c_str(), executable.size() + 1);
+ } else exit(1);
- int i = 1;
- for(Versatile::const_iterator it=V.begin(); it!=V.end(); it++, i++) {
- StringType argt = * static_cast<StringType *>(*it);
- string arg = argt;
- argv[i] = new char [arg.size() + 1];
- strncpy(argv[i], arg.c_str(), arg.size() + 1);
- debug_command += string(" # ") + argv[i];
+ int i = 1;
+ for(Versatile::const_iterator it=V.begin(); it!=V.end(); it++, i++) {
+ StringType argt = * static_cast<StringType *>(*it);
+ string arg = argt;
+ argv[i] = new char [arg.size() + 1];
+ strncpy(argv[i], arg.c_str(), arg.size() + 1);
+ debug_command += string(" # ") + argv[i];
+ }
+
+ // assert (i == V.size() + 1)
+ argv[i] = NULL;
+ char ** envp = NULL;
+ if(env.size() > 0) {
+ envp = new char * [env.size() + 1]; // 1 pour le NULL terminal
+ int i = 0;
+ for(Environnement::const_iterator it=env.begin(); it!=env.end(); it++, i++) {
+ const string & key = (*it).first;
+ const string & value = (*it).second;
+ ostringstream oss;
+ oss << key << "=" << value;
+ envp[i] = new char [oss.str().size() + 1];
+ strncpy(envp[i], oss.str().c_str(), oss.str().size() + 1);
+ }
- char ** envp = NULL;
- if(env.size() > 0) {
- envp = new char * [env.size() + 1]; // 1 pour le NULL terminal
- int i = 0;
- for(Environnement::const_iterator it=env.begin(); it!=env.end(); it++, i++) {
- const string & key = (*it).first;
- const string & value = (*it).second;
- ostringstream oss;
- oss << key << "=" << value;
- envp[i] = new char [oss.str().size() + 1];
- strncpy(envp[i], oss.str().c_str(), oss.str().size() + 1);
+ // assert (i == env.size())
+ envp[i] = NULL;
- // On positionne les limites systeme imposees au fils
- if (param.find(MAXCPUTIME) != param.end()) {
- int maxcputime = param[MAXCPUTIME];
- struct rlimit limit;
- limit.rlim_cur = maxcputime;
- limit.rlim_max = int(maxcputime * 1.1);
- setrlimit(RLIMIT_CPU, &limit);
- }
+ if (param.find(MAXDISKSIZE) != param.end()) {
+ int maxdisksize = param[MAXDISKSIZE];
+ struct rlimit limit;
+ limit.rlim_cur = maxdisksize * 1024;
+ limit.rlim_max = int(maxdisksize * 1.1) * 1024;
+ setrlimit(RLIMIT_FSIZE, &limit);
+ }
- if (param.find(MAXDISKSIZE) != param.end()) {
- int maxdisksize = param[MAXDISKSIZE];
- struct rlimit limit;
- limit.rlim_cur = maxdisksize * 1024;
- limit.rlim_max = int(maxdisksize * 1.1) * 1024;
- setrlimit(RLIMIT_FSIZE, &limit);
- }
+ if (param.find(MAXRAMSIZE) != param.end()) {
+ int maxramsize = param[MAXRAMSIZE];
+ struct rlimit limit;
+ limit.rlim_cur = maxramsize * 1024;
+ limit.rlim_max = int(maxramsize * 1.1) * 1024;
+ setrlimit(RLIMIT_AS, &limit);
+ }
// Nota : on pourrait aussi faire a la suite un kill(child, SIGKILL)
// mais cette option n'est pas implementee pour le moment, car il est
// preferable de laisser le process fils se terminer normalement et seul.
// Nota : on pourrait aussi faire a la suite un kill(child, SIGKILL)
// mais cette option n'est pas implementee pour le moment, car il est
// preferable de laisser le process fils se terminer normalement et seul.