Rosetta 3.5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
JobDistributor.cc
Go to the documentation of this file.
1 // -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
2 // vi: set ts=2 noet:
3 //
4 // (c) Copyright Rosetta Commons Member Institutions.
5 // (c) This file is part of the Rosetta software suite and is made available under license.
6 // (c) The Rosetta software is developed by the contributing members of the Rosetta Commons.
7 // (c) For more information, see http://www.rosettacommons.org. Questions about this can be
8 // (c) addressed to University of Washington UW TechTransfer, email: license@u.washington.edu.
9 
10 /// @file protocols/jd2/JobDistributor.cc
11 /// @brief August 2008 job distributor as planned at RosettaCon08 - Base class
12 /// @author Andrew Leaver-Fay
13 /// @author Steven Lewis smlewi@gmail.com
14 /// @author Mike Tyka
15 /// @author Oliver Lange
16 
17 // Unit headers
19 
20 // Package headers
29 #include <protocols/jd2/Parser.hh>
30 #include <protocols/jd2/Job.hh>
33 
34 // Project headers
35 #include <core/pose/Pose.hh>
36 
37 #include <protocols/moves/Mover.hh>
39 #ifdef GL_GRAPHICS
41 #endif
42 
44 
45 // Utility headers
46 #include <basic/options/option.hh>
47 #include <utility/exit.hh>
48 #include <basic/Tracer.hh>
49 #include <utility/excn/Exceptions.hh>
50 // AUTO-REMOVED #include <ctime>
51 
52 #include <basic/prof.hh>
53 #include <basic/datacache/BasicDataCache.hh>
54 #ifdef BOINC
55 #include <protocols/boinc/boinc.hh>
56 #endif
57 
58 // option key includes
59 #include <basic/options/keys/run.OptionKeys.gen.hh>
60 #include <basic/options/keys/jd2.OptionKeys.gen.hh>
61 #include <basic/options/keys/out.OptionKeys.gen.hh>
62 
63 #include <utility/vector1.hh>
64 #include <csignal>
65 
66 #ifdef WIN32
67 #include <iterator>
68 #endif
69 
70 namespace protocols
71 {
72 namespace jd2
73 {
74 static basic::Tracer tr("protocols.jd2.JobDistributor");
75 } //jd2
76 } //protocols
77 
78 //multithreaded case requires special pointers
79 #ifdef MULTITHREADED
80 
81 #include <boost/thread/tss.hpp>
82 
83 namespace protocols
84 {
85  namespace jd2
86  {
87  boost::thread_specific_pointer< JobDistributor > jd_ptr;
88 
89  JobDistributor *
91  {
92  if ( jd_ptr.get() == 0 )
93  {
95  }
96  return jd_ptr.get();
97  }
98 
99  } //jd2
100 } //protocols
101 
102 //non-multithreaded case behaves like a singleton
103 #else
104 
105 namespace protocols
106 {
107 namespace jd2
108 {
109 
110 JobDistributor * JobDistributor::instance_ = 0; //this pointer starts null
111 //JobDistributorDestroyer JobDistributor::destroyer_;
112 
113 JobDistributor *
115 {
116  if (instance_ == 0)
117  {
119  // destroyer_.set_job_distributor(instance_);
120  }
121  return instance_;
122 }
123 
124 } //jd2
125 } //protocols
126 
127 #endif
128 
129 namespace protocols
130 {
131 namespace jd2
132 {
133 
135  // job_inputter_( JobDistributorFactory::create_job_inputter() ),
136  // non-NULL starting state for this pointer; this makes calls to the
137  // JobDistributor safe even when not inside go() (of course you will get a
138  // stupid object, but at least it won't segfault). This object deliberately
139  // goes away once it's not used.
140  current_job_(JD2_BOGUS_JOB), current_job_id_(0), last_completed_job_(0), current_batch_id_(
141  0)
142 {
143  init_jd();
144 }
145 
147  // job_inputter_( JobDistributorFactory::create_job_inputter() ),
148  // non-NULL starting state for this pointer; this makes calls to the
149  // JobDistributor safe even when not inside go() (of course you will get a
150  // stupid object, but at least it won't segfault). This object deliberately
151  // goes away once it's not used.
152  current_job_(JD2_BOGUS_JOB), current_job_id_(0), last_completed_job_(0), current_batch_id_(
153  0)
154 {
155  if (!empty)
156  {
157  init_jd();
158  }
159  else
160  {
161  job_inputter_ = NULL;
164  }
165 }
166 
168 {
169  instance_ = this; //important so that calls to get_instance in JobInputters or JobOutputters don't lead to a infinite recursion
170 
171  // are there batches?
173  if (batches_.size() > 0)
174  {
175  tr.Debug << "batches present... " << std::endl;
176  current_batch_id_ = 1;
178  }
179  else
180  { //no batches...
181  try{
183  } catch (utility::excn::EXCN_Base & excn) {
184  basic::Error()
185  << "ERROR: Exception caught by JobDistributor while trying to initialize the JobInputter of type '"
187  job_inputter_->input_source())
188  << "'" << std::endl;
189  basic::Error()
190  << excn << std::endl;
191  utility_exit();
192  }
193  }
194 
195  // get jobs
196  try {
197  job_inputter_->fill_jobs(jobs_);
198  } catch (utility::excn::EXCN_Base & excn) {
199  basic::Error()
200  << "ERROR: Exception caught by JobDistributor while trying to fill the input jobs with JobInputter of type type '"
202  job_inputter_->input_source())
203  << "'" << std::endl;
204  basic::Error()
205  << excn << std::endl;
206  utility_exit();
207  }
208 
209  // have to initialize these AFTER BatchJobInputter->fill_jobs since a new batch might change options
212 }
213 
214 /// @details read -run:batches and put it into batches_ vector.
216 {
217  if (basic::options::option[basic::options::OptionKeys::run::batches].user())
218  {
219  //typedef utility::vector1< utility::file::FileName >::const_iterator iterator
221  basic::options::option[basic::options::OptionKeys::run::batches]);
222  std::copy(fns.begin(), fns.end(), std::back_inserter(batches_));
223  }
224 }
225 
226 /// @details restart job-distribution from beginning -- useful if you need a second pass over decoys...
228 {
229  jobs_.clear();
230  current_job_id_ = 0;
233  current_batch_id_ = 0;
234  init_jd();
235 }
236 
237 ///WARNING WARNING! SINGLETONS' DESTRUCTORS ARE NEVER CALLED IN MINI! DO NOT TRY TO PUT THINGS IN THIS FUNCTION!
238 ///here's a nice link explaining why: http://www.research.ibm.com/designpatterns/pubs/ph-jun96.txt
240 {
241 }
242 
244 {
245  go_main(mover);
246 }
247 
249 {
250  job_outputter_ = jo;
251  go(mover);
252 }
253 
255 {
256  using namespace basic::options;
257  time_t const allstarttime = time(NULL);
258  core::Size tried_jobs(0); //did we try any jobs?
259 
260  protocols::moves::MoverOP mover_copy(mover);
261  std::string last_inner_job_tag;
262  core::Size last_batch_id = 0; //this will trigger a mover->fresh_instance if we run with batches
263  core::Size retries_this_job(0);
264  bool first_job(true);
265 
266  bool using_parser(false);
267  if (parser_)
268  { //if not NULL, we have a parser
269  using_parser = true;
270  tr.Info
271  << "Parser is present. Input mover will be overwritten with whatever the parser creates."
272  << std::endl;
273  }PROF_START( basic::JD2);
274  core::pose::Pose pose;
275 #ifdef BOINC_GRAPHICS
276  // attach boinc graphics pose observer
277  protocols::boinc::Boinc::attach_graphics_current_pose_observer( pose );
278 #endif
279  while (obtain_new_job())
280  {
281  ++tried_jobs; //yes, we tried at least one job
282 
283  //timing information
284  time_t const jobstarttime = time(NULL);
285  core::Size const elapsedtime(jobstarttime - allstarttime);
286 
287  if ((option[OptionKeys::run::maxruntime].user())
288  && (option[OptionKeys::run::maxruntime]() > 0)
289  && (option[OptionKeys::run::maxruntime]() < int(elapsedtime)))
290  {
291 
292  basic::Error() << "Run terminating because runtime of "
293  << elapsedtime << " s exceeded maxruntime of "
294  << option[OptionKeys::run::maxruntime]() << " s "
295  << std::endl;
296  break; //let it clean up in case there's useful prof information or something
297  }
298 
299  // setup profiling
300  evaluation::TimeEvaluatorOP run_time(NULL);
301  if (!option[OptionKeys::run::no_prof_info_in_silentout])
302  {
303  job_outputter_->add_evaluation(run_time =
304  new evaluation::TimeEvaluator); //just don't use this in integration tests!
305  }
306 
307  tr.Debug << "Starting job " << job_outputter_->output_name(current_job_)
308  << std::endl; //x seconds?
309 
310  //Get a copy of the starting pose - this must be done early because the pose is read in on first use, we need to
311  //guaruntee it's been read in before the Parser gets a stab at it
312  pose.data().clear();
313  try
314  {
315  // Can we add the PyMOL mover here?
316  if (option[OptionKeys::run::show_simulation_in_pymol].user()
317  && option[OptionKeys::run::show_simulation_in_pymol].value()
318  > 0.0)
319  {
321  pose,
322  option[OptionKeys::run::keep_pymol_simulation_history](),
323  option[OptionKeys::run::show_simulation_in_pymol].value());
324  }
325  job_inputter_->pose_from_job(pose, current_job_);
326 
327 #ifdef BOINC_GRAPHICS
328  // attach boinc graphics pose observer
329  // do it here because pose_from_job may replace the pose conformation
330  protocols::boinc::Boinc::attach_graphics_current_pose_observer( pose );
331 #endif
332 
333  } catch (utility::excn::EXCN_Base& excn)
334  {
335  basic::Error()
336  << "ERROR: Exception caught by JobDistributor while trying to get pose from job "
337  << "'" << job_outputter_->output_name(current_job_) << "'" << std::endl
338  << excn << std::endl;
339  basic::Error()
340  << "Treating failure as bad input; canceling similar jobs"
341  << std::endl;
343  job_failed(pose, false);
344  pose = core::pose::Pose();
345  continue;
346  }
347 
348  //These if statements determine whether a new creation of the mover is appropriate
349  bool reinitialize_new_input(false);
350  bool new_input(false);
351  if (current_job_->input_tag() != last_inner_job_tag)
352  {
353  //this means we have just changed inputs - the next pdb on -l, etc
354  tr.Debug << "new input detected, is: " << current_job_->input_tag()
355  << ", last was: " << last_inner_job_tag << std::endl;
356  last_inner_job_tag = current_job_->input_tag();
357  new_input = true;
358  retries_this_job = 0;
359 
360  //do we need to reinitialize because of the new input? - yes if mover says, or cmdline says
361  if (mover
362  && (mover->reinitialize_for_new_input()
363  || option[OptionKeys::run::reinitialize_mover_for_new_input]))
364  {
365  reinitialize_new_input = true;
366  } //if we need to reinitialize
367 
368  } //if the input pose is about to change
369 
370  if (option[OptionKeys::jd2::delete_old_poses].user())
371  {
372  //to improve jd2 memory performance, we will delete the last
373  //input's starting pose. (Previous to this, jd2 never deleted
374  //input poses and would accumulate memory over large input sets
375  //- not a memory leak but certainly a nasty spot in the
376  //basement.) SML 8/7/09
377 
378  //This was applied in r32237 but it had problems with special
379  //uses of the job distributor and it was reverted. This should
380  //probably be applied by default, once the issues with the
381  //special uses are worked out.
382 
383  if (!first_job && last_completed_job_ != 0)
384  {
385  tr.Debug << "deleting pose from job " << last_completed_job_ <<std::endl;
386  jobs_[last_completed_job_]->inner_job_nonconst()->set_pose(
387  NULL);
388  }
389  }
390  //delete pointer to pose of last input; if that was last pointer
391  //to pose (and it should have been) this will free the memory
392 
393 
394  if (current_batch_id() != last_batch_id)
395  {
396  tr.Debug << "new batch detected: get fresh instance from mover"
397  << std::endl;
398  new_input = true;
399  reinitialize_new_input = true;
400  last_batch_id = current_batch_id();
401  }
402 
403  //for regular movers, reinitialize if desired
404  if (!using_parser
405  && (reinitialize_new_input || mover->reinitialize_for_each_job()
406  || option[OptionKeys::run::reinitialize_mover_for_each_job]))
407  {
408  tr.Trace << "reinitializing the mover" << std::endl;
409  PROF_STOP( basic::JD2);
410  PROF_START( basic::JD2_INIT_MOVER);
411  mover_copy = mover->fresh_instance();
412  PROF_STOP( basic::JD2_INIT_MOVER);
413  PROF_START( basic::JD2);
414  }
415  else if (using_parser)
416  { //call the parser
417  tr.Trace << "Allowing the Parser to create a new Mover if desired"
418  << std::endl;
419  try
420  {
421  parser_->generate_mover_from_job(current_job_, mover_copy,
422  new_input);
423  } catch (utility::excn::EXCN_Base& excn)
424  {
425  basic::Error()
426  << "ERROR: Exception caught by JobDistributor while trying to get pose from job "
427  << job_outputter_->output_name(current_job_) << excn
428  << std::endl;
429  basic::Error()
430  << "Treating failure as bad input; canceling similar jobs"
431  << std::endl;
433  job_failed(pose, false);
434  continue;
435  }
436  //the Parser might have modified the starting pose (with constraints) - so we'll refresh our copy
437  job_inputter_->pose_from_job(pose, current_job_);
438 
439 #ifdef BOINC_GRAPHICS
440  // attach boinc graphics pose observer
441  // do it here because pose_from_job may replace the pose conformation
442  protocols::boinc::Boinc::attach_graphics_current_pose_observer( pose );
443 #endif
444 #ifdef GL_GRAPHICS
445  //nonboinc viewer
446  protocols::viewer::add_conformation_viewer( pose.conformation(), "start_pose" );
447 #endif
448 
449  }
450  else
451  {
452  tr.Trace << "not reinitializing mover" << std::endl;
453  //mover_copy = mover; //This breaks when reinitializing only on new input, because non-reinitializing cycles will
454  //revert to the wrong place. If a mover_copy = something is desireable for all options, we need a second
455  //mover_copy.
456  }
457 
458  //use the mover
459  mover_copy->reset_status();
460  // clear old string info from previous apply calls
461  mover_copy->clear_info();
462  if (run_time)
463  run_time->reset(); //reset clock of TimeEvaluator
464 
465  // notify JobOutputter of starting pose, for comparison purposes and/or as interface for initializing evaluators. (Currently does nothing in the base class.)
466  job_outputter_->starting_pose(pose);
467 
469  PROF_STOP( basic::JD2);
470  try
471  {
472  if (basic::options::option[basic::options::OptionKeys::out::std_IO_exit_error_code]()
473  > 0)
474  std::cout.exceptions(std::ios_base::badbit);
475 
476  tr.Debug << "run mover... " << std::endl;
477  mover_copy->set_current_tag(
478  job_outputter_->output_name(current_job_));
479  mover_copy->apply(pose);
480  status = mover_copy->get_last_move_status();
481  // Job collects (optional) string info from the mover.
482  // This info may be output later by a JobOutputter.
483  current_job_->add_strings(mover_copy->info());
484 
485  } catch (std::ios_base::failure& ex)
486  {
487  std::cerr << "std::IO error detected... exiting..." << std::endl; // We can not longer use Tracer's at this point
488  std::exit(
489  basic::options::option[basic::options::OptionKeys::out::std_IO_exit_error_code]()); // Using pure exit instead of utility_exit_with_status to avoid recursion
490 
491  } catch (utility::excn::EXCN_BadInput& excn)
492  {
493  tr.Error
494  << "\n\n[ERROR] Exception caught by JobDistributor for job "
495  << job_outputter_->output_name(current_job_) << excn
496  << std::endl;
498 
499  } catch (utility::excn::EXCN_Base& excn)
500  {
501  tr.Error
502  << "\n\n[ERROR] Exception caught by JobDistributor for job "
503  << job_outputter_->output_name(current_job_) << excn
504  << std::endl;
506  }
507  std::cout.exceptions(std::ios_base::goodbit); // Disabling std::IO exceptions
508 
509  PROF_START( basic::JD2);
510  core::Size jobtime(time(NULL) - jobstarttime);
511 
513  PROF_START( basic::JD2_OUTPUT);
514  // check cases: SUCCESS, FAIL_RETRY, FAIL_DO_NOT_RETRY, FAIL_BAD_INPUT
515  if (status == protocols::moves::MS_SUCCESS)
516  {
518  job_succeeded(pose, jobtime);
519  // tr.Info << job_outputter_->output_name( current_job_ ) << " reported success in " << jobtime << " seconds" << std::endl;
520  }
521  else if (status == protocols::moves::FAIL_RETRY)
522  {
523  using namespace basic::options::OptionKeys::jd2;
524  ++retries_this_job;
525  if (option[ntrials].user()
526  && (retries_this_job >= (core::Size) option[ntrials].value()))
527  {
528  //this represents too many FAIL_RETRY - we will roll over into FAIL_DO_NOT_RETRY
529  tr.Warning << job_outputter_->output_name(current_job_)
530  << " reported failure " << retries_this_job
531  << " times and will no longer retry (permanent failure)"
532  << std::endl;
533  job_failed(pose, false /* will not retry */);
534  }
535  else
536  {
538  tr.Warning << job_outputter_->output_name(current_job_)
539  << " reported failure and will retry" << std::endl;
540  job_failed(pose, true /* will retry */);
541  }
542  }
543  else if (status == protocols::moves::FAIL_DO_NOT_RETRY)
544  {
545  tr.Warning << job_outputter_->output_name(current_job_)
546  << " reported failure and will NOT retry" << std::endl;
547  job_failed(pose, false /* will not retry */);
548  }
549  else if (status == protocols::moves::FAIL_BAD_INPUT)
550  {
551  tr.Warning << job_outputter_->output_name(current_job_)
552  << " reported that its input was bad and will not retry"
553  << std::endl;
555  job_failed(pose, false /*will not retry */);
556  }
559  PROF_STOP( basic::JD2_OUTPUT);
560  basic::prof_show();
561  first_job = false; //we've finished one by now, and are no longer on the first job edge case
562  }PROF_STOP( basic::JD2);
564  if (batches_.size())
565  {
566  tr.Info << jobs_.size() << " jobs in last batch... in total ";
567  }
568  else
569  {
570  tr.Info << jobs_.size() << " jobs considered, ";
571  }
572  tr.Info << tried_jobs << " jobs attempted in "
573  << (time(NULL) - allstarttime) << " seconds" << std::endl;
574  if (tried_jobs == 0)
575  tr.Info << "no jobs were attempted, did you forget to pass -overwrite?"
576  << std::endl;
577  job_outputter_->flush(); //This call forces out any unprinted data
578  basic::prof_show();
579 }
580 
582 {
583  return current_job_;
584 }
585 
587 {
588  return job_outputter()->output_name(current_job());
589 }
590 
592 {
593  return job_outputter_;
594 }
595 
596 /// @brief The input source for the current JobInputter.
598 {
599  return job_inputter_->input_source();
600 }
601 
602 bool JobDistributor::obtain_new_job(bool reconsider_current_job)
603 {
604  if (reconsider_current_job)
605  --current_job_id_;
606 
607  if (batches_.size() == 0
609  { //batches can be cancelled during computation
610  current_job_id_ = get_new_job_id(); //if no batches are present, or current batch still valid
611  }
612  else
613  {
614  current_job_id_ = 0; //batch got cancelled... jump to end of batch....
615  }
616 
617  if (current_job_id_ == 0)
618  {
619  if (next_batch())
620  { //query if there is a new batch to run after this one has finished
621  current_job_id_ = 0;
622  return obtain_new_job(); //set to first job of new batch... --- if batch is already computed fully this migh call next_batch() !
623  }
624  return false;
625  }
626  else if (current_job_id_ <= jobs_.size())
627  {
629  return true;
630  }
631  else
632  {
633  utility_exit_with_message(
634  "JobDistributor: nonexistent job returned in obtain_new_job()");
635  return false;
636  }
637 }
638 
640 {
641  job_outputter_->final_pose(current_job_, pose);
642  //current_job_->set_completed();
644  return;
645 }
646 
647 /// @details no-op implementation in the base class
649  bool /*will_retry*/)
650 {
651 }
652 
654  core::Real run_time)
655 {
656  jobs_[job_id]->set_completed();
657  tr.Info << job_outputter_->output_name(jobs_[job_id])
658  << " reported success in " << run_time << " seconds" << std::endl;
659  // tr.Info << "completed job: " << job_outputter_->output_name( jobs_[ job_id ] ) << std::endl;
660 }
661 
663 {
664  jobs_[job_id]->set_bad();
665 }
666 
668 {
669 }
670 
672 {
673 }
674 
676 {
677 }
678 
679 //This next line prevents accumulation of state within the Job object - should it be within another function?
681 {
682  jobs_[current_job_id_] = current_job_->copy_without_output(); //is this unsafe? should be its own function? MT: It is now!
683 }
684 
686 {
687 }
688 
690 {
691 }
692 
693 //////////////////////protected accessor functions////////////////////
695 {
696  return current_job_id_;
697 }
698 
699 Jobs const &
701 {
702  return jobs_;
703 }
704 
705 // Jobs &
706 // JobDistributor::get_jobs() { return jobs_; }
707 
709 {
710  return job_inputter_;
711 }
712 
714 {
715  //dummy default implementation
716 }
717 
719 {
720  return parser_;
721 }
722 
723 /////////////////////////batch stuff //////////////////////////
725 {
726  if (current_batch_id_ && batches_.size() > 0
727  && current_batch_id_ <= batches_.size())
728  {
729  return batches_[current_batch_id_];
730  }
731  else
732  {
734  }
735 }
736 
738 {
739  if (current_batch_id_ == setting)
740  return;
741  current_batch_id_ = setting;
742  if (current_batch_id_ > batches_.size())
743  batch_underflow();
744  if (current_batch_id_ > batches_.size())
745  {
746  tr.Error << "[ERROR] illegeal attempt to set batch_id to " << setting
747  << " where we have only " << batches_.size() << " batches"
748  << std::endl;
749  utility_exit_with_message("wrong batch_id");
750  }
751  load_new_batch();
752 }
753 
755 {
757 
758  if (current_batch_id_ > batches_.size())
759  batch_underflow();
760  if (current_batch_id_ > batches_.size())
761  { //still no new batches.
762  tr.Info << "no more batches to process... " << std::endl;
763  return false;
764  }
765 
766  //skip BOGUS_BATCHES ..
767  while (current_batch_id_ <= batches_.size()
770 
771  //if ended on BOGUS_BATCH
773  {
774  tr.Trace << "last batch is CANCELLED: run next_batch()" << std::endl;
775  return next_batch();
776  }
777 
778  runtime_assert( current_batch_id_ <= batches_.size());
779  load_new_batch();
780  return true;
781 }
782 
783 /// @detail add new batch to end of batch list... this might be called asynchronous... ie. while we are still in the middle of
784 /// a current batch, or while we are in non-batch mode
786 {
787  while (id > batches_.size())
788  {
790  }
791  if (id > 0)
792  {
793  batches_[id] = batch;
794  }
795  else
796  {
797  batches_.push_back(batch);
798  }
799 }
800 
801 /// @detail restart JobDistributor with a new batch the BatchJobInputter loads
802 /// new flags and sets global options after this we reload Factory dependent
803 /// Objects (e.g., JobInputter and JobOutputter )
805 {
806  runtime_assert( current_batch_id_ <= batches_.size());
807  //paranoid
808 
809  jobs_.clear();
810  current_job_id_ = 0;
812 
813  //remaking job_inputter has the advantage, that we will also get one, if
814  //this is the first batch!
815  job_inputter_ = NULL; //triggers destructor --> restores options
816  tr.Info << "start batch " << batches_[current_batch_id_] << std::endl;
818 
819  job_inputter_->fill_jobs(jobs_);
820  // have to initialize these AFTER BatchJobInputter->fill_jobs an new batch
821  // might change options
822 
823  // should we copy the old-evaluators --- of course only if new options don't
824  // change to a different silent-file or score-file
825  // evaluation::PoseEvaluators const& evaluations( job_outputter->evaluators() );
826 
829 }
830 
831 /// @brief Movers (or derived classes) may ask for the JobOutputter
832 void JobDistributor::set_job_outputter(const JobOutputterOP &new_job_outputter)
833 {
834  job_outputter_ = new_job_outputter;
835 }
836 
837 // // JobDistributorDestroyer functions
838 // JobDistributorDestroyer::JobDistributorDestroyer(JobDistributor* jd) {
839 // jd_ = jd;
840 // }
841 
842 // JobDistributorDestroyer::~JobDistributorDestroyer() {
843 // delete jd_;
844 // }
845 // void JobDistributorDestroyer::set_job_distributor(JobDistributor* jd) {
846 // jd_ = jd;
847 // }
848 
849 /// @details Default callback function for signal handling
851 {
852  std::cout << "Got some signal... It is:" << signal_ << std::endl;
853  if (signal_ == SIGINT)
854  std::cout << "Ctrl-c was pressed!" << std::endl;
855  if (signal_ == SIGABRT)
856  std::cout << "Process was aborted!" << std::endl;
857  if (signal_ == SIGTERM)
858  std::cout << "Process was terminated!" << std::endl;
859 
860 #ifndef WIN32
861  if (signal_ == SIGKILL)
862  std::cout << "Process was SIGKILL!" << std::endl;
863  if (signal_ == SIGQUIT)
864  std::cout << "Process was SIGQUIT!" << std::endl;
865 #endif
866 
868  get_instance()->job_outputter_->flush(); //This call forces out any unprinted but finished data
870 
871  //utility_exit_with_status(1);
872  std::exit(1); // Using pure exit instead of utility_exit_with_status to avoid recursion when compile with EXIT_THROWS_EXCEPTION
873 }
874 
875 /// @details Setting up callback function that will be call when our process is about to terminate.
876 // /@details This will allow us to exit propely (clean up in_progress_files/tmp files if any).
878 {
879  // Soooo many way to kill... wait - there is no special signal for HS with SVD? - lame...
880  signal(SIGINT, signal_fn);
881  signal(SIGABRT, signal_fn);
882  signal(SIGTERM, signal_fn);
883 
884 #ifndef WIN32
885  signal(SIGKILL, signal_fn);
886  signal(SIGQUIT, signal_fn);
887 #endif
888 }
889 
890 /// @details Set signal handler back to default state.
892 {
893  signal(SIGINT, SIG_DFL);
894  signal(SIGABRT, SIG_DFL);
895  signal(SIGTERM, SIG_DFL);
896 #ifndef WIN32
897  signal(SIGKILL, SIG_DFL);
898  signal(SIGQUIT, SIG_DFL);
899 #endif
900 }
901 
902 } //jd2
903 } //protocols