@@ -634,43 +634,8 @@ int main(int argc, char* argv[])
634634 sleep (1 ); // otherwise wait until server is initialized
635635 }
636636
637- auto internalfork = getenv (" ALICE_SIMFORKINTERNAL" );
638- if (internalfork) {
639- // forking will be done internally to profit from copy-on-write
640- nworkers = 1 ;
641- }
642- for (int id = 0 ; id < nworkers; ++id) {
643- // the workers
644- std::stringstream workerlogss;
645- workerlogss << getWorkerLogName () << id;
646-
647- // the workers
648- std::stringstream workerss;
649- workerss << " worker" << id;
650-
651- pid = fork ();
652- if (pid == 0 ) {
653- int fd = open (workerlogss.str ().c_str (), O_RDWR | O_CREAT , S_IRUSR | S_IWUSR );
654- dup2 (fd, 1 ); // make stdout go to file
655- dup2 (fd, 2 ); // make stderr go to file - you may choose to not do this
656- // or perhaps send stderr to another file
657- close (fd); // fd no longer needed - the dup'ed handles are sufficient
658-
659- const std::string name (" o2-sim-device-runner" );
660- const std::string path = installpath + " /" + name;
661-
662- execl (path.c_str (), name.c_str (), " --control" , " static" , " --id" , workerss.str ().c_str (), " --config-key" ,
663- " worker" , " --mq-config" , localconfig.c_str (), " --severity" , " info" , (char *)nullptr );
664- return 0 ;
665- } else {
666- gChildProcesses .push_back (pid);
667- setpgid (pid, pid); // the worker processes will form their own group
668- std::cout << " Spawning sim worker " << id << " on PID " << pid
669- << " ; Redirect output to " << workerlogss.str () << " \n " ;
670- }
671- }
672-
673- // the hit merger
637+ int mergerpid = -1 ;
638+ // the hit merger, spawned before the workers so that it listens when they send hits
674639 int pipe_mergerdriver_fd[2 ];
675640 if (pipe (pipe_mergerdriver_fd) != 0 ) {
676641 perror (" problem in creating pipe" );
@@ -679,6 +644,7 @@ int main(int argc, char* argv[])
679644 pid = fork ();
680645
681646 std::atomic<bool > shutdown_initiated = false ;
647+ std::function<bool (std::vector<int > const &)> finishCallback;
682648 if (pid == 0 ) {
683649 int fd = open (getMergerLogName ().c_str (), O_RDWR | O_CREAT , S_IRUSR | S_IWUSR );
684650 dup2 (fd, 1 ); // make stdout go to file
@@ -696,12 +662,13 @@ int main(int argc, char* argv[])
696662 std::cout << " Spawning hit merger on PID " << pid << " ; Redirect output to " << getMergerLogName () << " \n " ;
697663 setpgid (pid, pid);
698664 gChildProcesses .push_back (pid);
665+ mergerpid = pid;
699666 close (pipe_mergerdriver_fd[1 ]);
700667
701668 // A simple callback that determines if the simulation is complete and triggers
702669 // a shutdown of all child processes. This appears to be more robust than leaving
703670 // that decision upon the children (sometimes there are problems with that).
704- auto finishCallback = [&shutdown_initiated, &conf, &externalpublishchannel](std::vector<int > const & v) {
671+ finishCallback = [&shutdown_initiated, &conf, &externalpublishchannel](std::vector<int > const & v) {
705672 std::stringstream str;
706673 str << " EVENT " << v.back () << " FINISHED " << gAskedEvents << " " << v.size ();
707674 o2::simpubsub::publishMessage (externalpublishchannel, o2::simpubsub::simStatusString (" O2SIM" , " INFO" , str.str ()));
@@ -723,13 +690,48 @@ int main(int argc, char* argv[])
723690 }
724691 return true ;
725692 };
693+ }
726694
727- launchThreadMonitoringEvents (pipe_mergerdriver_fd[0 ], " EVENT FINISHED : " , gFinishedEvents , finishCallback);
695+ auto internalfork = getenv (" ALICE_SIMFORKINTERNAL" );
696+ if (internalfork) {
697+ // forking will be done internally to profit from copy-on-write
698+ nworkers = 1 ;
728699 }
700+ for (int id = 0 ; id < nworkers; ++id) {
701+ // the workers
702+ std::stringstream workerlogss;
703+ workerlogss << getWorkerLogName () << id;
729704
730- // wait on merger (which when exiting completes the workflow)
731- auto mergerpid = gChildProcesses .back ();
705+ // the workers
706+ std::stringstream workerss;
707+ workerss << " worker" << id;
708+
709+ pid = fork ();
710+ if (pid == 0 ) {
711+ int fd = open (workerlogss.str ().c_str (), O_RDWR | O_CREAT , S_IRUSR | S_IWUSR );
712+ dup2 (fd, 1 ); // make stdout go to file
713+ dup2 (fd, 2 ); // make stderr go to file - you may choose to not do this
714+ // or perhaps send stderr to another file
715+ close (fd); // fd no longer needed - the dup'ed handles are sufficient
716+
717+ const std::string name (" o2-sim-device-runner" );
718+ const std::string path = installpath + " /" + name;
719+
720+ execl (path.c_str (), name.c_str (), " --control" , " static" , " --id" , workerss.str ().c_str (), " --config-key" ,
721+ " worker" , " --mq-config" , localconfig.c_str (), " --severity" , " info" , (char *)nullptr );
722+ return 0 ;
723+ } else {
724+ gChildProcesses .push_back (pid);
725+ setpgid (pid, pid); // the worker processes will form their own group
726+ std::cout << " Spawning sim worker " << id << " on PID " << pid
727+ << " ; Redirect output to " << workerlogss.str () << " \n " ;
728+ }
729+ }
732730
731+ // monitor the merger only once all child pids are known to the shutdown callback
732+ launchThreadMonitoringEvents (pipe_mergerdriver_fd[0 ], " EVENT FINISHED : " , gFinishedEvents , finishCallback);
733+
734+ // wait on merger (which when exiting completes the workflow)
733735 int status, cpid;
734736 // wait just blocks and waits until any child returns; but we make sure to wait until merger is here
735737 bool errored = false ;
0 commit comments