be506a51882d6f80655857bca1cb2398eb0ce312
[cvc5.git] / src / main / time_limit.cpp
1 /********************* */
2 /*! \file time_limit.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Gereon Kremer
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
8 ** in the top-level source directory and their institutional affiliations.
9 ** All rights reserved. See the file COPYING in the top-level source
10 ** directory for licensing information.\endverbatim
11 **
12 ** \brief Implementation of time limits.
13 **
14 ** Implementation of time limits that are imposed by the --tlimit option.
15 **/
16
17 #include "time_limit.h"
18
19 #if defined(__MINGW32__) || defined(__MINGW64__)
20 #include <windows.h>
21 #else
22 #include <signal.h>
23 #include <sys/time.h>
24 #endif
25
26 #include <cerrno>
27 #include <cstring>
28
29 #include "signal_handlers.h"
30
31 namespace CVC4 {
32 namespace main {
33
34 #if defined(__MINGW32__) || defined(__MINGW64__)
35 void CALLBACK win_timeout_handler(LPVOID lpArg,
36 DWORD dwTimerLowValue,
37 DWORD dwTimerHighValue)
38 {
39 signal_handlers::timeout_handler();
40 }
41 #else
42 void posix_timeout_handler(int sig, siginfo_t* info, void*)
43 {
44 signal_handlers::timeout_handler();
45 }
46 #endif
47
48 void install_time_limit(const Options& opts)
49 {
50 unsigned long ms = opts.getCumulativeTimeLimit();
51 // Skip if no time limit shall be set.
52 if (ms == 0) return;
53
54 #if defined(__MINGW32__) || defined(__MINGW64__)
55 HANDLE hTimer = CreateWaitableTimer(nullptr, true, TEXT("CVC4::Timeout"));
56 if (hTimer == nullptr)
57 {
58 throw Exception(std::string("CreateWaitableTimer() failure: ")
59 + std::to_string(GetLastError()));
60 }
61 LARGE_INTEGER liDueTime;
62 liDueTime.LowPart = (DWORD)(ms & 0xFFFFFFFF);
63 liDueTime.HighPart = 0;
64 if (!SetWaitableTimer(
65 hTimer, &liDueTime, 0, win_timeout_handler, nullptr, false))
66 {
67 throw Exception(std::string("SetWaitableTimer() failure: ")
68 + std::to_string(GetLastError()));
69 }
70 #else
71 // Install a signal handler for SIGALRM
72 struct sigaction sact;
73 sact.sa_sigaction = posix_timeout_handler;
74 sact.sa_flags = SA_SIGINFO;
75 sigemptyset(&sact.sa_mask);
76 if (sigaction(SIGALRM, &sact, NULL))
77 {
78 throw Exception(std::string("sigaction(SIGALRM) failure: ")
79 + strerror(errno));
80 }
81
82 // Check https://linux.die.net/man/2/setitimer
83 // Then time is up, the kernel will send a SIGALRM
84 struct itimerval timerspec;
85 timerspec.it_value.tv_sec = ms / 1000;
86 timerspec.it_value.tv_usec = (ms % 1000) * 1000;
87 timerspec.it_interval.tv_sec = 0;
88 timerspec.it_interval.tv_usec = 0;
89 // Argument 1: which timer to set, we want the real time
90 // Argument 2: timer configuration, relative to current time
91 // Argument 3: old timer configuration, we don't want to know
92 if (setitimer(ITIMER_REAL, &timerspec, nullptr))
93 {
94 throw Exception(std::string("timer_settime() failure: ") + strerror(errno));
95 }
96 #endif
97 }
98
99 } // namespace main
100 } // namespace CVC4