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

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 d6a7b9 was d6a7b9, checked in by Frederik Heber <heber@…>, 11 years ago

Specifying executable and suffix in SystemCommandJob with MPQCCommandFragmentController.

  • Property mode set to 100644
File size: 7.0 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 * \param _suffix possible suffix for temporary filenames, may be left empty
80 */
81SystemCommandJob::SystemCommandJob(
82 const std::string &_command,
83 const std::string &_outputfile,
84 const JobId_t _JobId,
85 const std::string &_suffix) :
86 FragmentJob(_JobId),
87 command(_command),
88 suffix(_suffix),
89 outputfile(_outputfile)
90{}
91
92/** Destructor for class SystemCommandJob.
93 *
94 */
95SystemCommandJob::~SystemCommandJob()
96{}
97
98/** Work routine of this SystemCommandJob.
99 *
100 * This function encapsulates all the work that has to be done to generate
101 * a FragmentResult. Hence, the FragmentWorker does not need to know anything
102 * about the operation: it just receives it and executes this function.
103 *
104 * We obtain FragmentResult::exitflag from std::system's return value and
105 * FragmentResult::result from the contents of the piped output file.
106 *
107 * \return result of this job
108 */
109FragmentResult::ptr SystemCommandJob::Work()
110{
111// Info info((std::string(__FUNCTION__)+std::string(", id #")+toString(getId())).c_str());
112
113 // the following is taken from http://stackoverflow.com/questions/2746168/how-to-construct-a-c-fstream-from-a-posix-file-descriptor
114 char tmpTemplate[24];
115 strncpy(tmpTemplate, "/tmp/XXXXXX_", 14);
116 const std::string idstring(toString(getId()));
117 const size_t idlength = idstring.length();
118 ASSERT(idlength <= 8,
119 "SystemCommandJob::Work() - the id contains more than 8 digits.");
120 strcat(tmpTemplate, toString(getId()).c_str());
121 const int fd = mkstemps(tmpTemplate, idlength+1);
122
123 // write outputfile to temporary file
124 LOG(2, "DEBUG: Temporary file is " << tmpTemplate << ".");
125 std::ofstream output(tmpTemplate);
126 ASSERT(output.is_open(),
127 "SystemCommandJob::Work() - the temporary file could not be opened.");
128 output << outputfile << std::endl;
129 output.close();
130
131 // fork into subprocess and launch command
132 const std::string WorkName = std::string("Work #")+idstring;
133 Chronos::getInstance().startTiming(WorkName);
134 FragmentResult::ptr s;
135 {
136 // open process
137 std::string command_args = command+std::string(" ")+tmpTemplate;
138 LOG(1, "INFO: Executing '" << command_args << "'.");
139 FILE *stdoutstream = NULL;
140 while (stdoutstream == NULL) {
141 stdoutstream = popen(command_args.c_str(), "r");
142 if (stdoutstream == NULL) {
143 ELOG(2, "File descriptors are full, waiting for 1 sec...");
144 sleep(1);
145 }
146 }
147
148 int exitflag;
149 // read stdout from process
150 const int fd = fileno(stdoutstream);
151 fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
152 boost::iostreams::stream<boost::iostreams::file_descriptor_source> stdoutfile(fd, boost::iostreams::never_close_handle);
153 stdoutfile.set_auto_close(false); // https://svn.boost.org/trac/boost/ticket/3517
154 std::istreambuf_iterator<char> beginiter = (std::istreambuf_iterator<char>(stdoutfile));
155 std::string resultstring( beginiter, std::istreambuf_iterator<char>());
156
157 // construct result
158 LOG(2, "DEBUG: First 50 characters of output: " << resultstring.substr(0,50));
159 s = extractResult(resultstring);
160
161 // end process
162 if ((exitflag = pclose(stdoutstream)) == -1)
163 ELOG(0, "pclose error");
164
165 if (exitflag != 0)
166 ELOG(1, "Job " << getId() << " failed on executing: " << command_args);
167 s->exitflag = exitflag;
168 }
169 Chronos::getInstance().endTiming(WorkName);
170
171 // close temporary file and remove it
172 boost::filesystem::path tmpPath(tmpTemplate);
173 if (boost::filesystem::exists(boost::filesystem::status(tmpPath))) {
174 LOG(2, "DEBUG: Removing " << tmpPath.string());
175 boost::filesystem::remove(tmpPath);
176 }
177 // close temporary file!
178 close(fd);
179
180 // obtain timing and place in FragmentResult
181 s->time_Work = Chronos::getInstance().getTime(WorkName);
182 LOG(1, "INFO: Work() required " << s->time_Work << " seconds to complete.");
183
184 // return result
185 return s;
186}
187
188/** Default function for result extraction is just copy.
189 *
190 * @param resultstring output of system command
191 * @return copy of \a resultstring
192 */
193FragmentResult::ptr SystemCommandJob::extractResult(const std::string &resultstring)
194{
195 return FragmentResult::ptr (new FragmentResult(getId(), resultstring) );
196}
197
198
199/** Comparator for class SystemCommandJob.
200 * \param other instance to compare to
201 * \return every member variable is the same, else - is not
202 */
203bool SystemCommandJob::operator==(const SystemCommandJob &other) const
204{
205 if (command != other.command) {
206 LOG(1, "INFO: command's of two SystemCommandJobs differ: " << command << " != " << other.command << ".");
207 return false;
208 }
209 if (outputfile != other.outputfile) {
210 LOG(1, "INFO: outputfile's of two SystemCommandJobs differ: " << outputfile << " != " << other.outputfile << ".");
211 return false;
212 }
213 return (dynamic_cast<const FragmentJob &>(*this) == dynamic_cast<const FragmentJob &>(other));
214}
215
216// we need to explicitly instantiate the serialization functions as
217// its is only serialized through its base class FragmentJob
218BOOST_CLASS_EXPORT_IMPLEMENT(SystemCommandJob)
Note: See TracBrowser for help on using the repository browser.