fix(judger): 完善浮点数时限功能

ref: 986c7aa4ed

Co-authored-by: Kaifeng Lyu <vfleaking@163.com>
This commit is contained in:
Baoshuo Ren 2022-11-28 17:33:11 +08:00
parent d7aea4cbbc
commit 2e53a2733f
Signed by: baoshuo
GPG Key ID: 00CB9680AB29F51A
2 changed files with 47 additions and 21 deletions

View File

@ -22,6 +22,11 @@
std::string escapeshellarg(int arg) { std::string escapeshellarg(int arg) {
return std::to_string(arg); return std::to_string(arg);
} }
std::string escapeshellarg(double arg) {
std::ostringstream sout;
sout << std::setprecision(15) << arg;
return sout.str();
}
std::string escapeshellarg(const std::string &arg) { std::string escapeshellarg(const std::string &arg) {
std::string res = "'"; std::string res = "'";
for (char c : arg) { for (char c : arg) {
@ -391,21 +396,30 @@ namespace runp {
} }
}; };
itimerval double_to_itimerval(const double &tl) { /**
struct itimerval val; * @brief convert a time t to timeval. Assume t <= 1000. Accurate to ms.
*
* @param t time in double
* @return timeval
*/
timeval double_to_timeval(const double &t) {
long tl = round(t * 1000);
long tl_sec = tl / 1000;
long tl_usec = tl % 1000 * 1000;
return {tl_sec, tl_usec};
}
long tl_sec = (long)tl; /**
long tl_usec = (long)((tl - floor(tl)) * 1000 + 100) * 1000; * @brief convert a time t to timespec. Assume t <= 1000. Accurate to ms.
*
if (tl_usec >= 1'000'000l) { * @param t time in double
tl_sec++; * @return timespec
tl_usec -= 1'000'000l; */
} timespec double_to_timespec(const double &t) {
long tl = round(t * 1000);
val.it_value = {tl_sec, tl_usec}; long tl_sec = tl / 1000;
val.it_interval = {0, 100 * 1000}; long tl_nsec = tl % 1000 * 1'000'000;
return {tl_sec, tl_nsec};
return val;
} }
} }

View File

@ -51,10 +51,10 @@ error_t run_program_argp_parse_opt (int key, char *arg, struct argp_state *state
switch (key) { switch (key) {
case 'T': case 'T':
config->limits.time = stod(arg); config->limits.time = round(stod(arg) * 1000) / 1000;
break; break;
case 'R': case 'R':
config->limits.real_time = stod(arg); config->limits.real_time = round(stod(arg) * 1000) / 1000;
break; break;
case 'M': case 'M':
config->limits.memory = atoi(arg); config->limits.memory = atoi(arg);
@ -202,7 +202,16 @@ void set_limit(int r, int rcur, int rmax = -1) {
} }
void set_user_cpu_time_limit(double tl) { void set_user_cpu_time_limit(double tl) {
itimerval val = runp::double_to_itimerval(tl); itimerval val;
val.it_value = runp::double_to_timeval(tl);
val.it_interval = {0, 100'000};
val.it_value.tv_usec += 100'000;
if (val.it_value.tv_usec >= 1'000'000) {
val.it_value.tv_sec++;
val.it_value.tv_usec -= 1'000'000;
}
setitimer(ITIMER_VIRTUAL, &val, NULL); setitimer(ITIMER_VIRTUAL, &val, NULL);
} }
@ -302,7 +311,7 @@ struct rusage *ruse0p = NULL;
bool has_real_TLE() { bool has_real_TLE() {
struct timeval elapsed; struct timeval elapsed;
timersub(&end_time, &start_time, &elapsed); timersub(&end_time, &start_time, &elapsed);
return elapsed.tv_sec >= run_program_config.limits.real_time; return elapsed.tv_sec + elapsed.tv_usec / 1'000'000. >= run_program_config.limits.real_time;
} }
int rp_children_pos(pid_t pid) { int rp_children_pos(pid_t pid) {
@ -628,9 +637,12 @@ void dispatch_event(run_event&& e) {
if (rp_timer_pid == -1) { if (rp_timer_pid == -1) {
runp::result(runp::RS_JGF, "error code: FKFAL2").dump_and_exit(); // fork failed runp::result(runp::RS_JGF, "error code: FKFAL2").dump_and_exit(); // fork failed
} else if (rp_timer_pid == 0) { } else if (rp_timer_pid == 0) {
struct timespec ts; struct timespec ts = runp::double_to_timespec(run_program_config.limits.real_time);
ts.tv_sec = run_program_config.limits.real_time; ts.tv_nsec += 100'000'000;
ts.tv_nsec = 100 * 1000000; if (ts.tv_nsec >= 1'000'000'000) {
ts.tv_sec += 1;
ts.tv_nsec -= 1'000'000'000;
}
nanosleep(&ts, NULL); nanosleep(&ts, NULL);
exit(0); exit(0);
} }