diff --git a/judger/uoj_judger/include/uoj_judger.h b/judger/uoj_judger/include/uoj_judger.h index d449242..ac4c6f0 100644 --- a/judger/uoj_judger/include/uoj_judger.h +++ b/judger/uoj_judger/include/uoj_judger.h @@ -633,6 +633,23 @@ int conf_int(const string &key, int num, const int &val) { int conf_int(const string &key) { return conf_int(key, 0); } +double conf_double(const string &key, const double &val) { + if (config.count(key) == 0) { + return val; + } + return stod(config[key]); +} +double conf_double(const string &key, int num, const double &val) { + ostringstream sout; + sout << key << "_" << num; + if (config.count(sout.str()) == 0) { + return conf_double(key, val); + } + return stod(config[sout.str()]); +} +double conf_double(const string &key) { + return conf_double(key, 0); +} string conf_file_name_with_num(string s, int num) { ostringstream name; if (num < 0) { @@ -664,10 +681,10 @@ runp::limits_t conf_run_limit(string pre, const int &num, const runp::limits_t & pre += "_"; } runp::limits_t limits; - limits.time = conf_int(pre + "time_limit", num, val.time); + limits.time = conf_double(pre + "time_limit", num, val.time); limits.memory = conf_int(pre + "memory_limit", num, val.memory); limits.output = conf_int(pre + "output_limit", num, val.output); - limits.real_time = conf_int(pre + "real_time_limit", num, val.real_time); + limits.real_time = conf_double(pre + "real_time_limit", num, val.real_time); limits.stack = conf_int(pre + "stack_limit", num, val.stack); return limits; } diff --git a/judger/uoj_judger/include/uoj_judger_v2.h b/judger/uoj_judger/include/uoj_judger_v2.h index e8f1598..cc1222b 100644 --- a/judger/uoj_judger/include/uoj_judger_v2.h +++ b/judger/uoj_judger/include/uoj_judger_v2.h @@ -501,6 +501,23 @@ int conf_int(const string &key, int num, const int &val) { int conf_int(const string &key) { return conf_int(key, 0); } +double conf_double(const string &key, const double &val) { + if (uconfig.count(key) == 0) { + return val; + } + return stod(uconfig[key]); +} +double conf_double(const string &key, int num, const double &val) { + ostringstream sout; + sout << key << "_" << num; + if (uconfig.count(sout.str()) == 0) { + return conf_double(key, val); + } + return stod(uconfig[sout.str()]); +} +double conf_double(const string &key) { + return conf_double(key, 0); +} string conf_file_name_with_num(string s, int num) { ostringstream name; if (num < 0) { @@ -530,10 +547,10 @@ runp::limits_t conf_run_limit(string pre, const int &num, const runp::limits_t & pre += "_"; } runp::limits_t limits; - limits.time = conf_int(pre + "time_limit", num, val.time); + limits.time = conf_double(pre + "time_limit", num, val.time); limits.memory = conf_int(pre + "memory_limit", num, val.memory); limits.output = conf_int(pre + "output_limit", num, val.output); - limits.real_time = conf_int(pre + "real_time_limit", num, val.real_time); + limits.real_time = conf_double(pre + "real_time_limit", num, val.real_time); limits.stack = conf_int(pre + "stack_limit", num, val.real_time); return limits; } diff --git a/judger/uoj_judger/include/uoj_run.h b/judger/uoj_judger/include/uoj_run.h index c2f35b1..4cc9047 100644 --- a/judger/uoj_judger/include/uoj_run.h +++ b/judger/uoj_judger/include/uoj_run.h @@ -1,3 +1,4 @@ +#include #include #include #include @@ -7,6 +8,7 @@ #include #include #include +#include #define UOJ_GCC "/usr/bin/gcc-11" #define UOJ_GPLUSPLUS "/usr/bin/g++-11" @@ -20,6 +22,11 @@ std::string escapeshellarg(int 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 res = "'"; for (char c : arg) { @@ -133,14 +140,14 @@ namespace runp { fs::path run_path; struct limits_t { - int time; + double time; int memory; int output; - int real_time; + double real_time; int stack; limits_t() = default; - limits_t(const int &_time, const int &_memory, const int &_output) + limits_t(const double &_time, const int &_memory, const int &_output) : time(_time), memory(_memory), output(_output), real_time(-1), stack(-1) { } }; @@ -388,6 +395,32 @@ namespace runp { } } }; + + /** + * @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}; + } + + /** + * @brief convert a time t to timespec. Assume t <= 1000. Accurate to ms. + * + * @param t time in double + * @return timespec + */ + timespec double_to_timespec(const double &t) { + long tl = round(t * 1000); + long tl_sec = tl / 1000; + long tl_nsec = tl % 1000 * 1'000'000; + return {tl_sec, tl_nsec}; + } } namespace runp::interaction { diff --git a/judger/uoj_judger/run/run_program.cpp b/judger/uoj_judger/run/run_program.cpp index d6135dc..e39c936 100644 --- a/judger/uoj_judger/run/run_program.cpp +++ b/judger/uoj_judger/run/run_program.cpp @@ -51,10 +51,10 @@ error_t run_program_argp_parse_opt (int key, char *arg, struct argp_state *state switch (key) { case 'T': - config->limits.time = atoi(arg); + config->limits.time = round(stod(arg) * 1000) / 1000; break; case 'R': - config->limits.real_time = atoi(arg); + config->limits.real_time = round(stod(arg) * 1000) / 1000; break; case 'M': config->limits.memory = atoi(arg); @@ -201,10 +201,17 @@ void set_limit(int r, int rcur, int rmax = -1) { } } -void set_user_cpu_time_limit(int tl) { - struct itimerval val; - val.it_value = {tl, 100 * 1000}; - val.it_interval = {0, 100 * 1000}; +void set_user_cpu_time_limit(double 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); } @@ -304,7 +311,7 @@ struct rusage *ruse0p = NULL; bool has_real_TLE() { struct timeval 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) { @@ -630,9 +637,12 @@ void dispatch_event(run_event&& e) { if (rp_timer_pid == -1) { runp::result(runp::RS_JGF, "error code: FKFAL2").dump_and_exit(); // fork failed } else if (rp_timer_pid == 0) { - struct timespec ts; - ts.tv_sec = run_program_config.limits.real_time; - ts.tv_nsec = 100 * 1000000; + struct timespec ts = runp::double_to_timespec(run_program_config.limits.real_time); + ts.tv_nsec += 100'000'000; + if (ts.tv_nsec >= 1'000'000'000) { + ts.tv_sec += 1; + ts.tv_nsec -= 1'000'000'000; + } nanosleep(&ts, NULL); exit(0); } diff --git a/judger/uoj_judger/run/run_program_sandbox.h b/judger/uoj_judger/run/run_program_sandbox.h index 27dbfd4..ff9ea6a 100644 --- a/judger/uoj_judger/run/run_program_sandbox.h +++ b/judger/uoj_judger/run/run_program_sandbox.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include