1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 * BatchManager_Local.cxx :
25 * Auteur : Ivan DUTKA-MALEN - EDF R&D
26 * Mail : mailto:ivan.dutka-malen@der.edf.fr
27 * Date : Thu Nov 6 10:17:22 2003
38 #include <sys/types.h>
42 # include <sys/wait.h>
50 #include "Batch_IOMutex.hxx"
51 #include "Batch_BatchManager_Local.hxx"
59 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()
60 #ifndef WIN32 //TODO: porting of following functionality
61 ,_thread_id_id_association()
64 pthread_mutex_init(&_threads_mutex, NULL);
65 pthread_mutex_init(&_thread_id_id_association_mutex, NULL);
66 pthread_cond_init(&_thread_id_id_association_cond, NULL);
70 BatchManager_Local::~BatchManager_Local()
72 pthread_mutex_destroy(&_threads_mutex);
73 pthread_mutex_destroy(&_thread_id_id_association_mutex);
74 pthread_cond_destroy(&_thread_id_id_association_cond);
77 // Methode pour le controle des jobs : soumet un job au gestionnaire
78 const JobId BatchManager_Local::submitJob(const Job & job)
80 Job_Local jobLocal = job;
82 pthread_t thread_id = submit(jobLocal);
85 oss << getIdByThread_id(thread_id);
87 JobId id(this, oss.str());
92 // Methode pour le controle des jobs : retire un job du gestionnaire
93 void BatchManager_Local::deleteJob(const JobId & jobid)
97 istringstream iss(jobid.getReference());
100 // On retrouve le thread_id du thread
103 // @@@ --------> SECTION CRITIQUE <-------- @@@
104 pthread_mutex_lock(&_threads_mutex);
105 if (_threads.find(id) != _threads.end())
106 thread_id = _threads[id].thread_id;
107 pthread_mutex_unlock(&_threads_mutex);
108 // @@@ --------> SECTION CRITIQUE <-------- @@@
113 // Methode pour le controle des jobs : suspend un job en file d'attente
114 void BatchManager_Local::holdJob(const JobId & jobid)
117 istringstream iss(jobid.getReference());
120 UNDER_LOCK( cout << "BatchManager is sending HOLD command to the thread " << id << endl );
122 // On introduit une commande dans la queue du thread
123 // @@@ --------> SECTION CRITIQUE <-------- @@@
124 pthread_mutex_lock(&_threads_mutex);
125 if (_threads.find(id) != _threads.end())
126 _threads[id].command_queue.push(HOLD);
127 pthread_mutex_unlock(&_threads_mutex);
128 // @@@ --------> SECTION CRITIQUE <-------- @@@
131 // Methode pour le controle des jobs : relache un job suspendu
132 void BatchManager_Local::releaseJob(const JobId & jobid)
135 istringstream iss(jobid.getReference());
138 UNDER_LOCK( cout << "BatchManager is sending RELEASE command to the thread " << id << endl );
140 // On introduit une commande dans la queue du thread
141 // @@@ --------> SECTION CRITIQUE <-------- @@@
142 pthread_mutex_lock(&_threads_mutex);
143 if (_threads.find(id) != _threads.end())
144 _threads[id].command_queue.push(RELEASE);
145 pthread_mutex_unlock(&_threads_mutex);
146 // @@@ --------> SECTION CRITIQUE <-------- @@@
150 // Methode pour le controle des jobs : modifie un job en file d'attente
151 void BatchManager_Local::alterJob(const JobId & jobid, const Parametre & param, const Environnement & env)
155 // Methode pour le controle des jobs : modifie un job en file d'attente
156 void BatchManager_Local::alterJob(const JobId & jobid, const Parametre & param)
158 alterJob(jobid, param, Environnement());
161 // Methode pour le controle des jobs : modifie un job en file d'attente
162 void BatchManager_Local::alterJob(const JobId & jobid, const Environnement & env)
164 alterJob(jobid, Parametre(), env);
169 // Methode pour le controle des jobs : renvoie l'etat du job
170 JobInfo BatchManager_Local::queryJob(const JobId & jobid)
173 istringstream iss(jobid.getReference());
179 //UNDER_LOCK( cout << "JobInfo BatchManager_Local::queryJob(const JobId & jobid) : AVANT section critique" << endl );
180 // @@@ --------> SECTION CRITIQUE <-------- @@@
181 pthread_mutex_lock(&_threads_mutex);
182 param = _threads[id].param;
183 env = _threads[id].env;
184 pthread_mutex_unlock(&_threads_mutex);
185 // @@@ --------> SECTION CRITIQUE <-------- @@@
186 //UNDER_LOCK( cout << "JobInfo BatchManager_Local::queryJob(const JobId & jobid) : APRES section critique" << endl );
188 JobInfo_Local ji(param, env);
194 // Methode pour le controle des jobs : teste si un job est present en machine
195 bool BatchManager_Local::isRunning(const JobId & jobid)
198 istringstream iss(jobid.getReference());
203 //UNDER_LOCK( cout << "JobInfo BatchManager_Local::queryJob(const JobId & jobid) : AVANT section critique" << endl );
204 // @@@ --------> SECTION CRITIQUE <-------- @@@
205 pthread_mutex_lock(&_threads_mutex);
206 status = _threads[id].status;
207 pthread_mutex_unlock(&_threads_mutex);
208 // @@@ --------> SECTION CRITIQUE <-------- @@@
209 //UNDER_LOCK( cout << "JobInfo BatchManager_Local::queryJob(const JobId & jobid) : APRES section critique" << endl );
211 return (status == RUNNING);
215 // Methode d'execution d'un job
216 pthread_t BatchManager_Local::submit(const Job_Local & job)
218 // L'id du thread a creer
219 pthread_t thread_id =
226 // Les attributs du thread a sa creation
227 pthread_attr_t thread_attr;
228 pthread_attr_init(&thread_attr);
229 pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
231 ThreadAdapter * p_ta = new ThreadAdapter(*this, job);
233 // Creation du thread qui va executer la commande systeme qu'on lui passe
234 int rc = pthread_create(&thread_id,
237 static_cast<void *>(p_ta));
241 // Liberation des zones memoire maintenant inutiles occupees par les attributs du thread
242 pthread_attr_destroy(&thread_attr);
248 // Methode de destruction d'un job
249 void BatchManager_Local::cancel(pthread_t thread_id)
251 pthread_cancel(thread_id);
255 // Fabrique un identifiant unique pour les threads puisque le thread_id n'est pas unique
256 // au cours du temps (il peut etre reutilise lorsqu'un thread se termine)
257 // ATTENTION : cette methode est uniquement protegee par la section critique de l'association
258 // Thread_id / Id (_thread_id_id_association_mutex)
259 BatchManager_Local::Id BatchManager_Local::nextId()
263 //UNDER_LOCK( cout << "BatchManager_Local::Id BatchManager_Local::nextId() : Id = " << nextId << endl );
268 // Retourne l'Id enregistre dans l'association Thread_id / Id et le detruit immediatement
269 BatchManager_Local::Id BatchManager_Local::getIdByThread_id(pthread_t thread_id)
273 // @@@ --------> SECTION CRITIQUE <-------- @@@
274 pthread_mutex_lock(&_thread_id_id_association_mutex);
275 #ifndef WIN32 //TODO: porting of following functionality
276 while (_thread_id_id_association.find(thread_id) == _thread_id_id_association.end())
277 pthread_cond_wait(&_thread_id_id_association_cond, &_thread_id_id_association_mutex);
279 id = _thread_id_id_association[thread_id];
280 _thread_id_id_association.erase(thread_id);
283 pthread_mutex_unlock(&_thread_id_id_association_mutex);
284 // @@@ --------> SECTION CRITIQUE <-------- @@@
286 //UNDER_LOCK( cout << "BatchManager_Local::Id BatchManager_Local::getIdByThread_id(pthread_t thread_id) : Id = " << id << " - thread_id = " << thread_id << endl );
291 // Associe un Thread_id a un Id nouvellement cree
292 BatchManager_Local::Id BatchManager_Local::registerThread_id(pthread_t thread_id)
296 // @@@ --------> SECTION CRITIQUE <-------- @@@
297 pthread_mutex_lock(&_thread_id_id_association_mutex);
298 #ifndef WIN32 //TODO: porting of following functionality
299 if (_thread_id_id_association.find(thread_id) == _thread_id_id_association.end()) {
300 id = _thread_id_id_association[thread_id] = nextId();
301 pthread_cond_signal(&_thread_id_id_association_cond);
304 UNDER_LOCK( cerr << "ERROR : Pthread Inconstency. Two threads own the same thread_id." << endl );
307 pthread_mutex_unlock(&_thread_id_id_association_mutex);
308 // @@@ --------> SECTION CRITIQUE <-------- @@@
310 //UNDER_LOCK( cout << "BatchManager_Local::Id BatchManager_Local::registerThread_id(pthread_t thread_id) : Id = " << id << " - thread_id = " << thread_id << endl );
315 // Constructeur de la classe ThreadAdapter
316 BatchManager_Local::ThreadAdapter::ThreadAdapter(BatchManager_Local & bm, const Job_Local & job) :
324 // Methode d'execution du thread
325 void * BatchManager_Local::ThreadAdapter::run(void * arg)
327 #ifndef WIN32 //TODO: porting of following functionality
328 // On bloque tous les signaux pour ce thread
330 sigfillset(&setmask);
331 pthread_sigmask(SIG_BLOCK, &setmask, NULL);
333 // On autorise la terminaison differee du thread
334 // (ces valeurs sont les valeurs par defaut mais on les force par precaution)
335 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
336 pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
338 // On enregistre la fonction de suppression du fils en cas d'arret du thread
339 // Cette fontion sera automatiquement appelee lorsqu'une demande d'annulation
340 // sera prise en compte par pthread_testcancel()
342 pthread_cleanup_push(BatchManager_Local::kill_child_on_exit, static_cast<void *> (&child));
343 pthread_cleanup_push(BatchManager_Local::delete_on_exit, arg);
345 ThreadAdapter * p_ta = static_cast<ThreadAdapter *>(arg);
350 // Le code retour cumule (ORed) de tous les appels
351 // Nul en cas de reussite de l'ensemble des operations
354 // Cette table contient la liste des fichiers a detruire a la fin du processus
355 std::vector<string> files_to_delete;
359 // On copie les fichiers d'entree pour le fils
360 const Parametre param = p_ta->_job.getParametre();
361 Parametre::const_iterator it;
363 // On initialise la variable workdir a la valeur du Current Working Directory
369 getcwd(cwd, PATH_MAX);
371 string workdir = cwd;
374 if ( (it = param.find(WORKDIR)) != param.end() ) {
375 workdir = static_cast<string>( (*it).second );
378 string executionhost = string(param[EXECUTIONHOST]);
380 if ( (it = param.find(INFILE)) != param.end() ) {
381 Versatile V = (*it).second;
382 Versatile::iterator Vit;
384 for(Vit=V.begin(); Vit!=V.end(); Vit++) {
385 CoupleType cpt = *static_cast< CoupleType * >(*Vit);
387 string local = cp.getLocal();
388 string remote = cp.getRemote();
390 string copy_cmd = p_ta->getBatchManager().copy_command("", local, executionhost, workdir + "/" + remote);
391 UNDER_LOCK( cout << "Copying : " << copy_cmd << endl );
393 if (system(copy_cmd.c_str()) ) {
397 // On enregistre le fichier comme etant a detruire
398 files_to_delete.push_back(workdir + "/" + remote);
409 //Using CreateThread instead fork() POSIX function
411 // On forke/exec un nouveau process pour pouvoir controler le fils
412 // (plus finement qu'avec un appel system)
413 // int rc = system(commande.c_str());
415 if (child < 0) { // erreur
416 UNDER_LOCK( cerr << "Fork impossible (rc=" << child << ")" << endl );
418 } else if (child > 0) { // pere
428 // On copie les fichiers de sortie du fils
429 if ( (it = param.find(OUTFILE)) != param.end() ) {
430 Versatile V = (*it).second;
431 Versatile::iterator Vit;
433 for(Vit=V.begin(); Vit!=V.end(); Vit++) {
434 CoupleType cpt = *static_cast< CoupleType * >(*Vit);
436 string local = cp.getLocal();
437 string remote = cp.getRemote();
439 string copy_cmd = p_ta->getBatchManager().copy_command(executionhost, workdir + "/" + remote, "", local);
440 UNDER_LOCK( cout << "Copying : " << copy_cmd << endl );
442 if (system(copy_cmd.c_str()) ) {
446 // On enregistre le fichier comme etant a detruire
447 files_to_delete.push_back(workdir + "/" + remote);
453 // On efface les fichiers d'entree et de sortie du fils si les copies precedentes ont reussi
454 // ou si la creation du fils n'a pu avoir lieu
455 if ( (rc == 0) || (child < 0) ) {
456 std::vector<string>::const_iterator it;
457 for(it=files_to_delete.begin(); it!=files_to_delete.end(); it++) {
458 string remove_cmd = p_ta->getBatchManager().remove_command(executionhost, *it);
459 UNDER_LOCK( cout << "Removing : " << remove_cmd << endl );
460 system(remove_cmd.c_str());
466 // On retire la fonction de nettoyage de la memoire
467 pthread_cleanup_pop(0);
469 // On retire la fonction de suppression du fils
470 pthread_cleanup_pop(0);
474 // On invoque la fonction de nettoyage de la memoire
477 UNDER_LOCK( cout << "Father is leaving" << endl );
486 void BatchManager_Local::ThreadAdapter::pere(pid_t child)
488 #ifndef WIN32 //TODO: porting of following functionality
489 time_t child_starttime = time(NULL);
491 // On enregistre le fils dans la table des threads
492 pthread_t thread_id = pthread_self();
493 Id id = _bm.registerThread_id(thread_id);
495 Parametre param = _job.getParametre();
496 Environnement env = _job.getEnvironnement();
498 ostringstream thread_id_sst;
500 param[ID] = thread_id_sst.str();
501 param[STATE] = "Running";
504 // @@@ --------> SECTION CRITIQUE <-------- @@@
505 pthread_mutex_lock(&_bm._threads_mutex);
506 _bm._threads[id].thread_id = thread_id;
507 _bm._threads[id].pid = child;
508 _bm._threads[id].status = RUNNING;
509 _bm._threads[id].param = param;
510 _bm._threads[id].env = env;
511 _bm._threads[id].command_queue.push(NOP);
512 pthread_mutex_unlock(&_bm._threads_mutex);
513 // @@@ --------> SECTION CRITIQUE <-------- @@@
519 // on boucle en attendant que le fils ait termine
522 pid_t child_wait_rc = waitpid(child, &child_rc, WNOHANG /* | WUNTRACED */);
523 if (child_wait_rc > 0) {
524 if (WIFSTOPPED(child_rc)) {
525 // NOTA : pour rentrer dans cette section, il faut que le flag WUNTRACED
526 // soit positionne dans l'appel a waitpid ci-dessus. Ce flag est couramment
527 // desactive car s'il est possible de detecter l'arret d'un process, il est
528 // plus difficile de detecter sa reprise.
530 // Le fils est simplement stoppe
531 // @@@ --------> SECTION CRITIQUE <-------- @@@
532 pthread_mutex_lock(&_bm._threads_mutex);
533 _bm._threads[id].status = STOPPED;
534 _bm._threads[id].param[STATE] = "Stopped";
535 pthread_mutex_unlock(&_bm._threads_mutex);
536 // @@@ --------> SECTION CRITIQUE <-------- @@@
537 UNDER_LOCK( cout << "Father sees his child is STOPPED : " << child_wait_rc << endl );
541 // Le fils est termine, on sort de la boucle et du if englobant
542 // @@@ --------> SECTION CRITIQUE <-------- @@@
543 pthread_mutex_lock(&_bm._threads_mutex);
544 _bm._threads[id].status = DONE;
545 _bm._threads[id].param[STATE] = "Done";
546 pthread_mutex_unlock(&_bm._threads_mutex);
547 // @@@ --------> SECTION CRITIQUE <-------- @@@
548 UNDER_LOCK( cout << "Father sees his child is DONE : " << child_wait_rc << " (child_rc=" << (WIFEXITED(child_rc) ? WEXITSTATUS(child_rc) : -1) << ")" << endl );
552 else if (child_wait_rc == -1) {
553 // Le fils a disparu ...
554 // @@@ --------> SECTION CRITIQUE <-------- @@@
555 pthread_mutex_lock(&_bm._threads_mutex);
556 _bm._threads[id].status = DEAD;
557 _bm._threads[id].param[STATE] = "Dead";
558 pthread_mutex_unlock(&_bm._threads_mutex);
559 // @@@ --------> SECTION CRITIQUE <-------- @@@
560 UNDER_LOCK( cout << "Father sees his child is DEAD : " << child_wait_rc << " (Reason : " << strerror(errno) << ")" << endl );
566 // On teste si le thread doit etre detruit
567 pthread_testcancel();
571 // On regarde si le fils n'a pas depasse son temps (wallclock time)
572 time_t child_currenttime = time(NULL);
573 time_t child_elapsedtime = child_currenttime - child_starttime;
574 if (param.find(MAXWALLTIME) != param.end()) {
575 int maxwalltime = param[MAXWALLTIME];
576 // cout << "child_starttime = " << child_starttime << endl
577 // << "child_currenttime = " << child_currenttime << endl
578 // << "child_elapsedtime = " << child_elapsedtime << endl
579 // << "maxwalltime = " << maxwalltime << endl
580 // << "int(maxwalltime * 1.1) = " << int(maxwalltime * 1.1) << endl;
581 if (child_elapsedtime > int(maxwalltime * 1.1) ) { // On se donne 10% de marge avant le KILL
582 UNDER_LOCK( cout << "Father is sending KILL command to the thread " << id << endl );
583 // On introduit une commande dans la queue du thread
584 // @@@ --------> SECTION CRITIQUE <-------- @@@
585 pthread_mutex_lock(&_bm._threads_mutex);
586 if (_bm._threads.find(id) != _bm._threads.end())
587 _bm._threads[id].command_queue.push(KILL);
588 pthread_mutex_unlock(&_bm._threads_mutex);
589 // @@@ --------> SECTION CRITIQUE <-------- @@@
592 } else if (child_elapsedtime > maxwalltime ) {
593 UNDER_LOCK( cout << "Father is sending TERM command to the thread " << id << endl );
594 // On introduit une commande dans la queue du thread
595 // @@@ --------> SECTION CRITIQUE <-------- @@@
596 pthread_mutex_lock(&_bm._threads_mutex);
597 if (_bm._threads.find(id) != _bm._threads.end())
598 _bm._threads[id].command_queue.push(TERM);
599 pthread_mutex_unlock(&_bm._threads_mutex);
600 // @@@ --------> SECTION CRITIQUE <-------- @@@
606 // On regarde s'il y a quelque chose a faire dans la queue de commande
607 // @@@ --------> SECTION CRITIQUE <-------- @@@
608 pthread_mutex_lock(&_bm._threads_mutex);
609 if (_bm._threads.find(id) != _bm._threads.end()) {
610 while (_bm._threads[id].command_queue.size() > 0) {
611 Commande cmd = _bm._threads[id].command_queue.front();
612 _bm._threads[id].command_queue.pop();
616 UNDER_LOCK( cout << "Father does nothing to his child" << endl );
620 UNDER_LOCK( cout << "Father is sending SIGSTOP signal to his child" << endl );
621 kill(child, SIGSTOP);
625 UNDER_LOCK( cout << "Father is sending SIGCONT signal to his child" << endl );
626 kill(child, SIGCONT);
630 UNDER_LOCK( cout << "Father is sending SIGTERM signal to his child" << endl );
631 kill(child, SIGTERM);
635 UNDER_LOCK( cout << "Father is sending SIGKILL signal to his child" << endl );
636 kill(child, SIGKILL);
648 pthread_mutex_unlock(&_bm._threads_mutex);
649 // @@@ --------> SECTION CRITIQUE <-------- @@@
651 // On fait une petite pause pour ne pas surcharger inutilement le processeur
663 void BatchManager_Local::ThreadAdapter::fils()
665 #ifndef WIN32 //TODO: porting of following functionality
666 Parametre param = _job.getParametre();
667 Parametre::iterator it;
671 // On se place dans le repertoire de travail
672 if ( (it = param.find(WORKDIR)) != param.end() ) {
673 string workdir = static_cast<string>( (*it).second );
674 chdir(workdir.c_str());
680 // EXECUTABLE is MANDATORY, if missing, we exit with failure notification
681 char * execpath = NULL;
682 if (param.find(EXECUTABLE) != param.end()) {
683 string executable = _bm.exec_command(param);
684 execpath = new char [executable.size() + 1];
685 strncpy(execpath, executable.c_str(), executable.size() + 1);
688 string debug_command = execpath;
690 string name = (param.find(NAME) != param.end()) ? param[NAME] : param[EXECUTABLE];
693 if (param.find(ARGUMENTS) != param.end()) {
694 Versatile V = param[ARGUMENTS];
696 argv = new char * [V.size() + 2]; // 1 pour name et 1 pour le NULL terminal
698 argv[0] = new char [name.size() + 1];
699 strncpy(argv[0], name.c_str(), name.size() + 1);
701 debug_command += string(" # ") + argv[0];
704 for(Versatile::const_iterator it=V.begin(); it!=V.end(); it++, i++) {
705 StringType argt = * static_cast<StringType *>(*it);
707 argv[i] = new char [arg.size() + 1];
708 strncpy(argv[i], arg.c_str(), arg.size() + 1);
709 debug_command += string(" # ") + argv[i];
712 // assert (i == V.size() + 1)
717 UNDER_LOCK( cout << "*** debug_command = " << debug_command << endl );
721 Environnement env = _job.getEnvironnement();
726 envp = new char * [env.size() + 1]; // 1 pour le NULL terminal
728 for(Environnement::const_iterator it=env.begin(); it!=env.end(); it++, i++) {
729 const string & key = (*it).first;
730 const string & value = (*it).second;
732 oss << key << "=" << value;
733 envp[i] = new char [oss.str().size() + 1];
734 strncpy(envp[i], oss.str().c_str(), oss.str().size() + 1);
737 // assert (i == env.size())
744 // On positionne les limites systeme imposees au fils
745 if (param.find(MAXCPUTIME) != param.end()) {
746 int maxcputime = param[MAXCPUTIME];
748 limit.rlim_cur = maxcputime;
749 limit.rlim_max = int(maxcputime * 1.1);
750 setrlimit(RLIMIT_CPU, &limit);
753 if (param.find(MAXDISKSIZE) != param.end()) {
754 int maxdisksize = param[MAXDISKSIZE];
756 limit.rlim_cur = maxdisksize * 1024;
757 limit.rlim_max = int(maxdisksize * 1.1) * 1024;
758 setrlimit(RLIMIT_FSIZE, &limit);
761 if (param.find(MAXRAMSIZE) != param.end()) {
762 int maxramsize = param[MAXRAMSIZE];
764 limit.rlim_cur = maxramsize * 1024;
765 limit.rlim_max = int(maxramsize * 1.1) * 1024;
766 setrlimit(RLIMIT_AS, &limit);
771 // On cree une session pour le fils de facon a ce qu'il ne soit pas
772 // detruit lorsque le shell se termine (le shell ouvre une session et
773 // tue tous les process appartenant a la session en quittant)
777 // On ferme les descripteurs de fichiers standards
778 //close(STDIN_FILENO);
779 //close(STDOUT_FILENO);
780 //close(STDERR_FILENO);
783 // On execute la commande du fils
784 execve(execpath, argv, envp);
786 // No need to deallocate since nothing happens after a successful exec
788 // Normalement on ne devrait jamais arriver ici
789 ofstream file_err("error.log");
790 UNDER_LOCK( file_err << "Echec de l'appel a execve" << endl );
792 } catch (GenericException & e) {
794 std::cerr << "Caught exception : " << e.type << " : " << e.message << std::endl;
804 void BatchManager_Local::kill_child_on_exit(void * p_pid)
807 //TODO: porting of following functionality
808 pid_t child = * static_cast<pid_t *>(p_pid);
811 kill(child, SIGTERM);
813 // Nota : on pourrait aussi faire a la suite un kill(child, SIGKILL)
814 // mais cette option n'est pas implementee pour le moment, car il est
815 // preferable de laisser le process fils se terminer normalement et seul.
819 void BatchManager_Local::delete_on_exit(void * arg)
821 ThreadAdapter * p_ta = static_cast<ThreadAdapter *>(arg);