1
2 /*
3 * File BFNTMainLoop.cpp.
4 *
5 * This file is part of the source code of the software program
6 * Vampire. It is protected by applicable
7 * copyright laws.
8 *
9 * This source code is distributed under the licence found here
10 * https://vprover.github.io/license.html
11 * and in the source directory
12 *
13 * In summary, you are allowed to use Vampire for non-commercial
14 * purposes but not allowed to distribute, modify, copy, create derivatives,
15 * or use in competitions.
16 * For other uses of Vampire please contact developers for a different
17 * licence, which we will make an effort to provide.
18 */
19 /**
20 * @file BFNTMainLoop.cpp
21 * Implements class BFNTMainLoop.
22 */
23
24 #include <cerrno>
25 #include <csignal>
26
27 #include "Lib/Portability.hpp"
28
29 #include <sys/types.h>
30 #include <sys/wait.h>
31
32 #include "Lib/Environment.hpp"
33 #include "Lib/Int.hpp"
34 #include "Lib/Metaiterators.hpp"
35 #include "Lib/ScopedPtr.hpp"
36 #include "Lib/System.hpp"
37 #include "Lib/Timer.hpp"
38
39 #include "Lib/Sys/Multiprocessing.hpp"
40
41 #include "Kernel/Clause.hpp"
42 #include "Kernel/Problem.hpp"
43 #include "Kernel/Unit.hpp"
44
45 #include "Shell/Property.hpp"
46 #include "Shell/TPTPPrinter.hpp"
47 #include "Shell/UIHelper.hpp"
48
49 #include "Statistics.hpp"
50
51 #include "BFNTMainLoop.hpp"
52
53 #define BFNT_CHILD_RESULT_SAT 0
54 #define BFNT_CHILD_RESULT_UNSAT 6
55 #define BFNT_CHILD_RESULT_UNKNOWN 7
56
57 namespace Shell
58 {
59
BFNTMainLoop(Problem & prb,const Options & opt)60 BFNTMainLoop::BFNTMainLoop(Problem& prb, const Options& opt)
61 : MainLoop(prb, opt),
62 _childOpts(opt),
63 _bfnt(prb.getProperty())
64 {
65 CALL("BFNTMainLoop::BFNTMainLoop");
66
67 //this is important, otherwise we'd start creating new and new processes
68 // -- the child process would also run BFNT therefore also attemps to run
69 //BFNT-running children.
70 _childOpts.setBfnt(false);
71 }
72
73
init()74 void BFNTMainLoop::init()
75 {
76 CALL("BFNTMainLoop::init");
77
78 _hasSorts = _prb.getProperty()->hasNonDefaultSorts();
79 if(_hasSorts) {
80 return;
81 }
82
83 //Putting problem units into the BFNT convertor here may result into
84 //one clause appearing in multiple Problem objects. In _prb and then in
85 //child problems created by the spawed processes. Normally we wouldn't
86 //want this to happen, but in the _prb object we do not use the clauses
87 //any more after this point, and the child problems are isolated from each
88 //other in different processes.
89 _bfnt.apply(_prb.units());
90 }
91
92 /**
93 * Run the child process that does proving on the flattenned problem
94 *
95 * Result statuses of the process:
96 * BFNT_CHILD_RESULT_SAT
97 * BFNT_CHILD_RESULT_UNSAT
98 * BFNT_CHILD_RESULT_UNKNOWN
99 */
runChild(size_t modelSize)100 void BFNTMainLoop::runChild(size_t modelSize)
101 {
102 CALL("BFNTMainLoop::runChild");
103
104 ScopedPtr<Problem> childPrb(_bfnt.createProblem(modelSize));
105
106 ScopedPtr<MainLoop> childMainLoop(MainLoop::createFromOptions(*childPrb, _childOpts));
107 MainLoopResult innerRes = childMainLoop->run();
108 innerRes.updateStatistics();
109
110 if(env.options->mode()!=Options::Mode::SPIDER) {
111 if(innerRes.terminationReason==Statistics::SATISFIABLE || innerRes.terminationReason==Statistics::TIME_LIMIT) {
112 env.beginOutput();
113 env.statistics->print(env.out());
114 env.endOutput();
115 }
116 }
117
118 if(env.options->mode()!=Options::Mode::SPIDER && innerRes.terminationReason==Statistics::SATISFIABLE) {
119 env.beginOutput();
120 UIHelper::outputSatisfiableResult(env.out());
121 env.endOutput();
122 UIHelper::satisfiableStatusWasAlreadyOutput = true;
123 }
124
125 switch(innerRes.terminationReason) {
126 case Statistics::SATISFIABLE:
127 exit(BFNT_CHILD_RESULT_SAT);
128 case Statistics::REFUTATION:
129 exit(BFNT_CHILD_RESULT_UNSAT);
130 default:
131 exit(BFNT_CHILD_RESULT_UNKNOWN);
132 }
133 exit(BFNT_CHILD_RESULT_UNKNOWN);
134 }
135
136
spawnChild(size_t modelSize)137 MainLoopResult BFNTMainLoop::spawnChild(size_t modelSize)
138 {
139 CALL("BFNTMainLoop::spawnChild");
140
141 pid_t childPid=Multiprocessing::instance()->fork();
142
143 if(!childPid) {
144 runChild(modelSize);
145 ASSERTION_VIOLATION;
146 }
147
148
149 System::ignoreSIGINT();
150
151 int status;
152 errno=0;
153 pid_t res=waitpid(childPid, &status, 0);
154 if(res==-1) {
155 SYSTEM_FAIL("Error in waiting for forked process.",errno);
156 }
157
158 System::heedSIGINT();
159
160 Timer::syncClock();
161
162 if(res!=childPid) {
163 INVALID_OPERATION("Invalid waitpid return value: "+Int::toString(res)+" pid of forked Vampire: "+Int::toString(childPid));
164 }
165
166 ASS(!WIFSTOPPED(status));
167
168 if( (WIFSIGNALED(status) && WTERMSIG(status)==SIGINT) ||
169 (WIFEXITED(status) && WEXITSTATUS(status)==VAMP_RESULT_STATUS_SIGINT) ) {
170 //if the forked Vampire was terminated by SIGINT (Ctrl+C), we also terminate
171 //(3 is the return value for this case; see documentation for the
172 //@b vampireReturnValue global variable)
173
174 raise(SIGINT);
175 }
176
177 if(WIFEXITED(status)) {
178 switch(WEXITSTATUS(status)) {
179 case BFNT_CHILD_RESULT_SAT:
180 UIHelper::satisfiableStatusWasAlreadyOutput = true;
181 return MainLoopResult(Statistics::SATISFIABLE);
182 case BFNT_CHILD_RESULT_UNSAT:
183 return MainLoopResult(Statistics::REFUTATION);
184
185 case VAMP_RESULT_STATUS_OTHER_SIGNAL:
186 case VAMP_RESULT_STATUS_UNHANDLED_EXCEPTION:
187 INVALID_OPERATION("error in the child process");
188
189 case BFNT_CHILD_RESULT_UNKNOWN:
190 default: //under default will fall timeout
191 return MainLoopResult(Statistics::UNKNOWN);
192 }
193 }
194 else {
195 return MainLoopResult(Statistics::UNKNOWN);
196 }
197 }
198
199
runImpl()200 MainLoopResult BFNTMainLoop::runImpl()
201 {
202 CALL("BFNTMainLoop::runImpl");
203
204 if(_hasSorts) {
205 return MainLoopResult(Statistics::UNKNOWN);
206 }
207
208
209 env.timer->makeChildrenIncluded();
210
211 size_t modelSize = 1;
212 for(;;) {
213 Timer::syncClock();
214 if(env.timeLimitReached()) { return MainLoopResult(Statistics::TIME_LIMIT); }
215 env.statistics->maxBFNTModelSize = modelSize;
216 MainLoopResult childResult = spawnChild(modelSize);
217
218 if(childResult.terminationReason == Statistics::SATISFIABLE) {
219 return childResult;
220 }
221
222 modelSize++;
223 }
224 }
225
226 }
227