As a first step within this project, this PR provides a new implementation that backs --tlimit. It uses setitimer (as timer_settime is not available on MacOS) to make the OS send a signal after the given wall clock time has passed.
In more detail, this PR:
removes the current handling of --tlimit (TlimitListener and its integration in the NodeManager)
adds a new TimeLimitListener that lives in src/main
uses TimeLimitListener directly in runCvc4()
adds a signal handler for SIGALRM (that also uses the existing timeout_handler)
interactive_shell.cpp
interactive_shell.h
main.h
+ time_limit.cpp
+ time_limit.h
util.cpp
)
#include "main/command_executor.h"
#include "main/interactive_shell.h"
#include "main/main.h"
+#include "main/time_limit.h"
#include "options/options.h"
#include "options/set_language.h"
#include "parser/parser.h"
// Parse the options
vector<string> filenames = Options::parseOptions(&opts, argc, argv);
+ install_time_limit(opts);
+
string progNameStr = opts.getBinaryName();
progName = &progNameStr;
--- /dev/null
+#include "time_limit.h"
+
+#include <sys/time.h>
+
+#include <cerrno>
+#include <cstring>
+
+namespace CVC4 {
+namespace main {
+
+void install_time_limit(const Options& opts)
+{
+ unsigned long ms = opts.getCumulativeTimeLimit();
+ if (ms == 0) return;
+
+ // Check https://linux.die.net/man/2/setitimer
+ struct itimerval timerspec;
+ timerspec.it_value.tv_sec = ms / 1000;
+ timerspec.it_value.tv_usec = (ms % 1000) * 1000;
+ timerspec.it_interval.tv_sec = 0;
+ timerspec.it_interval.tv_usec = 0;
+ // Argument 1: which timer to set, we want the real time
+ // Argument 2: timer configuration, relative to current time
+ // Argument 3: old timer configuration, we don't want to know
+ if (setitimer(ITIMER_REAL, &timerspec, nullptr))
+ {
+ throw Exception(std::string("timer_settime() failure: ") + strerror(errno));
+ }
+}
+
+} // namespace main
+} // namespace CVC4
--- /dev/null
+#ifndef CVC4__MAIN__TIME_LIMIT_H
+#define CVC4__MAIN__TIME_LIMIT_H
+
+#include "options/options.h"
+
+namespace CVC4 {
+namespace main {
+
+/**
+ * Installs an overall wall-clock time limit for the solver binary.
+ * It retrieves the time limit and creates a POSIX timer (via setitimer()).
+ * This timer signals its expiration with an SIGALRM that is handled by
+ * timeout_handler() in util.cpp.
+ */
+
+void install_time_limit(const Options& opts);
+
+} // namespace main
+} // namespace CVC4
+
+#endif /* CVC4__MAIN__TIME_LIMIT_H */
void* cvc4StackBase;
#endif /* HAVE_SIGALTSTACK */
-/** Handler for SIGXCPU, i.e., timeout. */
+/** Handler for SIGXCPU and SIGALRM, i.e., timeout. */
void timeout_handler(int sig, siginfo_t* info, void*) {
safe_print(STDERR_FILENO, "CVC4 interrupted by timeout.\n");
print_statistics();
throw Exception(string("sigaction(SIGXCPU) failure: ") + strerror(errno));
}
+ struct sigaction act2b;
+ act2b.sa_sigaction = timeout_handler;
+ act2b.sa_flags = SA_SIGINFO;
+ sigemptyset(&act2b.sa_mask);
+ if(sigaction(SIGALRM, &act2b, NULL)) {
+ throw Exception(string("sigaction(SIGALRM) failure: ") + strerror(errno));
+ }
+
struct sigaction act3;
act3.sa_sigaction = ill_handler;
act3.sa_flags = SA_SIGINFO;
bool getStatsHideZeros() const;
bool getStrictParsing() const;
int getTearDownIncremental() const;
+ unsigned long getCumulativeTimeLimit() const;
bool getVersion() const;
const std::string& getForceLogicString() const;
int getVerbosity() const;
return (*this)[options::tearDownIncremental];
}
+unsigned long Options::getCumulativeTimeLimit() const {
+ return (*this)[options::cumulativeMillisecondLimit];
+}
+
bool Options::getVersion() const{
return (*this)[options::version];
}
type = "unsigned long"
handler = "limitHandler"
read_only = true
- help = "enable time limiting (give milliseconds)"
+ help = "enable time limiting of wall clock time (give milliseconds)"
[[option]]
name = "perCallMillisecondLimit"