|
6 | 6 | * |
7 | 7 | */ |
8 | 8 |
|
| 9 | +#include <atomic> |
9 | 10 | #include <cassert> |
10 | 11 | #include <cerrno> |
| 12 | +#include <chrono> |
11 | 13 | #include <csignal> |
12 | 14 | #include <cstdio> |
13 | 15 | #include <cstdlib> |
|
20 | 22 | #include <sys/time.h> |
21 | 23 | #include <sys/types.h> |
22 | 24 | #include <sys/wait.h> |
| 25 | +#ifdef __linux__ |
| 26 | +#include <sys/syscall.h> |
| 27 | +#endif |
| 28 | +#include <thread> |
23 | 29 | #include <unistd.h> |
24 | 30 | #include <vector> |
25 | 31 |
|
26 | 32 | static int pid; |
27 | | -static volatile sig_atomic_t timedOut; |
28 | 33 |
|
29 | 34 | static void cleanUp(int /*dummy*/) { |
30 | 35 | kill(pid, SIGKILL); |
31 | 36 | exit(0); |
32 | 37 | } |
33 | 38 |
|
34 | | -static void alarmHandler(int /*dummy*/) { timedOut = 1; } |
35 | | - |
36 | 39 | extern void initWatcher(); |
37 | 40 | extern ssize_t calculateStaticMemoryUsage(const std::string &); |
38 | 41 | extern ssize_t getMemoryRLimit(ssize_t memoryLimitInMB); |
@@ -155,41 +158,50 @@ auto main(int argc, char *argv[]) -> int { |
155 | 158 | pid = fork(); |
156 | 159 |
|
157 | 160 | if (pid > 0) { |
158 | | - // Parent process |
159 | 161 | signal(SIGINT, cleanUp); |
160 | 162 | signal(SIGABRT, cleanUp); |
161 | 163 | signal(SIGTERM, cleanUp); |
162 | 164 |
|
163 | | - struct sigaction sa; |
164 | | - sa.sa_handler = alarmHandler; |
165 | | - sigemptyset(&sa.sa_mask); |
166 | | - sa.sa_flags = 0; |
167 | | - sigaction(SIGALRM, &sa, nullptr); |
168 | | - |
169 | 165 | long long wallClockMs = timeLimitMs + extraTimeMs; |
170 | | - struct itimerval timer; |
171 | | - timer.it_value.tv_sec = wallClockMs / 1000; |
172 | | - timer.it_value.tv_usec = (wallClockMs % 1000) * 1000; |
173 | | - timer.it_interval = {0, 0}; |
174 | | - setitimer(ITIMER_REAL, &timer, nullptr); |
175 | 166 |
|
176 | | - struct rusage usage{}; |
177 | | - int status = 0; |
| 167 | + int childPfd = -1; |
| 168 | +#ifdef __linux__ |
| 169 | + childPfd = syscall(SYS_pidfd_open, pid, 0); |
| 170 | +#endif |
178 | 171 |
|
179 | | - if (wait4(pid, &status, 0, &usage) == -1) { |
180 | | - if (errno == EINTR && timedOut) { |
181 | | - kill(pid, SIGKILL); |
182 | | - wait4(pid, nullptr, 0, nullptr); |
183 | | - printf("-1\n-1\n"); |
184 | | - return RS_TLE; |
| 172 | + auto timedOut = std::make_shared<std::atomic<bool>>(false); |
| 173 | + auto done = std::make_shared<std::atomic<bool>>(false); |
| 174 | + |
| 175 | + std::thread([=]() { |
| 176 | + std::this_thread::sleep_for(std::chrono::milliseconds(wallClockMs)); |
| 177 | + if (!*done) { |
| 178 | + *timedOut = true; |
| 179 | +#ifdef __linux__ |
| 180 | + if (childPfd >= 0) |
| 181 | + syscall(SYS_pidfd_send_signal, childPfd, SIGKILL, NULL, 0); |
| 182 | + else |
| 183 | +#endif |
| 184 | + kill(pid, SIGKILL); |
185 | 185 | } |
| 186 | + }).detach(); |
| 187 | + |
| 188 | + struct rusage usage{}; |
| 189 | + int status; |
| 190 | + |
| 191 | + while (wait4(pid, &status, 0, &usage) == -1) { |
| 192 | + if (errno == EINTR) |
| 193 | + continue; |
186 | 194 | printf("-1\n-1\n"); |
187 | 195 | perror("wait4"); |
188 | 196 | return RS_FAIL; |
189 | 197 | } |
190 | 198 |
|
191 | | - struct itimerval disable = {{0, 0}, {0, 0}}; |
192 | | - setitimer(ITIMER_REAL, &disable, nullptr); |
| 199 | + *done = true; |
| 200 | + |
| 201 | + if (*timedOut) { |
| 202 | + printf("-1\n-1\n"); |
| 203 | + return RS_TLE; |
| 204 | + } |
193 | 205 |
|
194 | 206 | if (WIFEXITED(status)) { |
195 | 207 | long long timeUsedMs = |
|
0 commit comments