source: src/Jobs/JobMarket/SystemCommandJob.cpp@ c3de51

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since c3de51 was c3de51, checked in by Frederik Heber <heber@…>, 11 years ago

Added FragmentJob, ..Result, JobId, SystemCommandJob, and types from JobMarket.

  • taken over from version v1.1.4 with disclaimer adapted.
  • changed include paths to JobMarket -> Jobs/JobMarket.
  • these files are only used when no HAVE_JOBMARKET is defined.
  • SystemCommandJob had Info, causing extra Chronos entry.
  • Property mode set to 100644
File size: 6.9 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2014 Frederik Heber. All rights reserved.
5 *
6 *
7 * This file is part of MoleCuilder.
8 *
9 * MoleCuilder is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * MoleCuilder is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23/*
24 * SystemCommandJob.cpp
25 *
26 * Originally taken from my JobMarket project at 1.1.4.
27 *
28 * Created on: Feb 5, 2012
29 * Author: heber
30 */
31
32// include config.h
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include <boost/iostreams/device/file_descriptor.hpp>
38#include <boost/iostreams/stream.hpp>
39
40#include "CodePatterns/MemDebug.hpp"
41
42// include headers that implement a archive in simple text format
43// otherwise BOOST_CLASS_EXPORT_IMPLEMENT has no effect
44#include <boost/archive/text_oarchive.hpp>
45#include <boost/archive/text_iarchive.hpp>
46
47#ifdef HAVE_JOBMARKET
48#include "JobMarket/Jobs/SystemCommandJob.hpp"
49#else
50#include "Jobs/JobMarket/SystemCommandJob.hpp"
51#endif
52
53#include <cstdio>
54#include <cstdlib>
55#include <fcntl.h>
56#include <fstream>
57#include <iostream>
58#include <string>
59#include <streambuf>
60#include <boost/filesystem.hpp>
61
62#include "CodePatterns/Chronos.hpp"
63#include "CodePatterns/Info.hpp"
64#include "CodePatterns/Log.hpp"
65#include "CodePatterns/toString.hpp"
66
67/** Constructor for class SystemCommandJob.
68 *
69 */
70SystemCommandJob::SystemCommandJob() :
71 FragmentJob(JobId::IllegalJob)
72{}
73
74/** Constructor for class SystemCommandJob.
75 *
76 * \param _command command to execute
77 * \param _outputfile configuration file for solver
78 * \param _JobId unique id of this job
79 */
80SystemCommandJob::SystemCommandJob(const std::string &_command, const std::string &_outputfile, const JobId_t _JobId) :
81 FragmentJob(_JobId),
82 command(_command),
83 outputfile(_outputfile)
84{}
85
86/** Destructor for class SystemCommandJob.
87 *
88 */
89SystemCommandJob::~SystemCommandJob()
90{}
91
92/** Work routine of this SystemCommandJob.
93 *
94 * This function encapsulates all the work that has to be done to generate
95 * a FragmentResult. Hence, the FragmentWorker does not need to know anything
96 * about the operation: it just receives it and executes this function.
97 *
98 * We obtain FragmentResult::exitflag from std::system's return value and
99 * FragmentResult::result from the contents of the piped output file.
100 *
101 * \return result of this job
102 */
103FragmentResult::ptr SystemCommandJob::Work()
104{
105// Info info((std::string(__FUNCTION__)+std::string(", id #")+toString(getId())).c_str());
106
107 // the following is taken from http://stackoverflow.com/questions/2746168/how-to-construct-a-c-fstream-from-a-posix-file-descriptor
108 char tmpTemplate[24];
109 strncpy(tmpTemplate, "/tmp/XXXXXX_", 14);
110 const std::string idstring(toString(getId()));
111 const size_t idlength = idstring.length();
112 ASSERT(idlength <= 8,
113 "SystemCommandJob::Work() - the id contains more than 8 digits.");
114 strcat(tmpTemplate, toString(getId()).c_str());
115 const int fd = mkstemps(tmpTemplate, idlength+1);
116
117 // write outputfile to temporary file
118 LOG(2, "DEBUG: Temporary file is " << tmpTemplate << ".");
119 std::ofstream output(tmpTemplate);
120 ASSERT(output.is_open(),
121 "SystemCommandJob::Work() - the temporary file could not be opened.");
122 output << outputfile << std::endl;
123
124 // fork into subprocess and launch command
125 const std::string WorkName = std::string("Work #")+idstring;
126 Chronos::getInstance().startTiming(WorkName);
127 FragmentResult::ptr s;
128 {
129 // open process
130 std::string command_args = command+std::string(" ")+tmpTemplate;
131 LOG(1, "INFO: Executing '" << command_args << "'.");
132 FILE *stdoutstream = NULL;
133 while (stdoutstream == NULL) {
134 stdoutstream = popen(command_args.c_str(), "r");
135 if (stdoutstream == NULL) {
136 ELOG(2, "File descriptors are full, waiting for 1 sec...");
137 sleep(1);
138 }
139 }
140
141 int exitflag;
142 // read stdout from process
143 const int fd = fileno(stdoutstream);
144 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
145 boost::iostreams::stream<boost::iostreams::file_descriptor_source> stdoutfile(fd, boost::iostreams::never_close_handle);
146 stdoutfile.set_auto_close(false); // https://svn.boost.org/trac/boost/ticket/3517
147 std::istreambuf_iterator<char> beginiter = (std::istreambuf_iterator<char>(stdoutfile));
148 std::string resultstring( beginiter, std::istreambuf_iterator<char>());
149
150 // construct result
151 LOG(2, "DEBUG: First 50 characters of output: " << resultstring.substr(0,50));
152 s = extractResult(resultstring);
153
154 // end process
155 if ((exitflag = pclose(stdoutstream)) == -1)
156 ELOG(0, "pclose error");
157
158 if (exitflag != 0)
159 ELOG(1, "Job " << getId() << " failed on executing: " << command_args);
160 s->exitflag = exitflag;
161 }
162 Chronos::getInstance().endTiming(WorkName);
163
164 // close temporary file and remove it
165 output.close();
166 boost::filesystem::path tmpPath(tmpTemplate);
167 if (boost::filesystem::exists(boost::filesystem::status(tmpPath))) {
168 LOG(2, "DEBUG: Removing " << tmpPath.string());
169 boost::filesystem::remove(tmpPath);
170 }
171 // close temporary file!
172 close(fd);
173
174 // obtain timing and place in FragmentResult
175 s->time_Work = Chronos::getInstance().getTime(WorkName);
176 LOG(1, "INFO: Work() required " << s->time_Work << " seconds to complete.");
177
178 // return result
179 return s;
180}
181
182/** Default function for result extraction is just copy.
183 *
184 * @param resultstring output of system command
185 * @return copy of \a resultstring
186 */
187FragmentResult::ptr SystemCommandJob::extractResult(const std::string &resultstring)
188{
189 return FragmentResult::ptr (new FragmentResult(getId(), resultstring) );
190}
191
192
193/** Comparator for class SystemCommandJob.
194 * \param other instance to compare to
195 * \return every member variable is the same, else - is not
196 */
197bool SystemCommandJob::operator==(const SystemCommandJob &other) const
198{
199 if (command != other.command) {
200 LOG(1, "INFO: command's of two SystemCommandJobs differ: " << command << " != " << other.command << ".");
201 return false;
202 }
203 if (outputfile != other.outputfile) {
204 LOG(1, "INFO: outputfile's of two SystemCommandJobs differ: " << outputfile << " != " << other.outputfile << ".");
205 return false;
206 }
207 return (dynamic_cast<const FragmentJob &>(*this) == dynamic_cast<const FragmentJob &>(other));
208}
209
210// we need to explicitly instantiate the serialization functions as
211// its is only serialized through its base class FragmentJob
212BOOST_CLASS_EXPORT_IMPLEMENT(SystemCommandJob)
Note: See TracBrowser for help on using the repository browser.