void work(int newsockfd, struct sockaddr_in cli_addr) { if (newsockfd < 0) { FM_LOG_WARNING("ERROR on accept"); return; } FM_LOG_NOTICE("connect from %s:%d", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port)); char buffer[BUFF_SIZE]; bzero(buffer, BUFF_SIZE); ssize_t n = read(newsockfd, buffer, BUFF_SIZE); if (n < 0) FM_LOG_WARNING("ERROR reading from socket"); FM_LOG_NOTICE("Here is the password: %s", buffer); if (check_password(oj_config.password, buffer)) { FM_LOG_DEBUG("Authentication Ok."); n = write(newsockfd, "Authentication Ok.", 18); if (n < 0) FM_LOG_WARNING("ERROR writing to socket"); bzero(buffer, BUFF_SIZE); n = read(newsockfd, buffer, BUFF_SIZE); if (n <= 0) { FM_LOG_WARNING("ERROR reading from socket"); close(newsockfd); return; } FM_LOG_NOTICE("Here is the message: %s(%d)", buffer, n); oj_solution_t oj_solution{}; if (parse_arguments(buffer, oj_solution) < 0) { FM_LOG_WARNING("Missing some parameters."); n = write(newsockfd, "Missing some parameters.", 24); if (n < 0) FM_LOG_WARNING("ERROR writing to socket"); close(newsockfd); return; } else { n = write(newsockfd, "I got your request.", 19); if (n < 0) FM_LOG_WARNING("ERROR writing to socket"); close(newsockfd); ProcessQueue.push(oj_solution); return; } } else { FM_LOG_WARNING("Authentication Failed."); n = write(newsockfd, "Authentication Failed.", 22); if (n < 0) FM_LOG_WARNING("ERROR writing to socket"); } close(newsockfd); }
void check_pid() { pid_t otherpid; FM_LOG_NOTICE("pid file: %s", PID_FILE); pfh = pidfile_open(PID_FILE, 0644, &otherpid); if (pfh == nullptr) { if (errno == EEXIST) { FM_LOG_FATAL("Daemon already running, pid: %jd", (intmax_t) otherpid); exit(EXIT_FAILURE); } /* If we cannot create pidfile from other reasons, only warn. */ FM_LOG_WARNING("Cannot open or create pidfile"); } }
void prepare_files(const char *filename, char *infile, char *outfile, char *userfile) { size_t namelen = strlen(filename) - 3; char fname[PATH_SIZE]; strncpy(fname, filename, namelen); fname[namelen] = 0; snprintf(infile, PATH_SIZE, "%s/%s.in", oj_solution.data_dir, fname); snprintf(outfile, PATH_SIZE, "%s/%s.out", oj_solution.data_dir, fname); snprintf(userfile, PATH_SIZE, "%s/%s.out", oj_solution.work_dir, fname); char buff[PATH_SIZE]; snprintf(buff, PATH_SIZE, "%s/%s.in", oj_solution.work_dir, fname); if (symlink(infile, buff) == -1) { FM_LOG_NOTICE("make symlink for %s failed: %s", buff, strerror(errno)); } FM_LOG_DEBUG("std input file: %s", infile); FM_LOG_DEBUG("std output file: %s", outfile); FM_LOG_DEBUG("user output file: %s", userfile); }
int log_open(const char* filename) { if (log_opened == 1) { fprintf(stderr, "logger: log already opened\n"); return 0; } int len = strlen(filename); log_filename = (char *)malloc(sizeof(char) * len + 1); strcpy(log_filename, filename); log_fp = fopen(log_filename, "a"); if (log_fp == NULL) { fprintf(stderr, "log_file: %s", log_filename); perror("can't not open log file"); exit(1); } atexit(log_close); log_opened = 1; log_extra_info[0] = 0; FM_LOG_NOTICE("log_open"); return 1; }
void parse_arguments(int argc, char *argv[]) { int opt; while ((opt = getopt(argc, argv, "s:p:t:m:l:w:d:D:j:c:")) != -1) { switch (opt) { case 's': // Solution ID oj_solution.sid = atoi(optarg); break; case 'p': // Problem ID oj_solution.pid = atoi(optarg); break; case 'l': // Language ID oj_solution.lang = atoi(optarg); break; case 'j': // judge type oj_solution.judge_type = atoi(optarg); break; case 't': // Time limit oj_solution.time_limit = (unsigned int) atoi(optarg); break; case 'm': // Memory limit oj_solution.memory_limit = (unsigned int) atoi(optarg); break; case 'w': case 'd': // Work directory if (realpath(optarg, work_dir_root) == nullptr) { fprintf(stderr, "resolve work dir failed:%s\n", strerror(errno)); exit(EXIT_BAD_PARAM); } break; case 'D': // Data directory if (realpath(optarg, data_dir_root) == nullptr) { fprintf(stderr, "resolve data dir failed: %s\n", strerror(errno)); exit(EXIT_BAD_PARAM); } break; case 'c': // Contest ID oj_solution.cid = atoi(optarg); break; default: fprintf(stderr, "unknown option provided: -%c %s\n", opt, optarg); exit(EXIT_BAD_PARAM); } } char buff[PATH_SIZE]; snprintf(buff, PATH_SIZE, "%s/oj-judge.log", work_dir_root); check_and_rename_log(buff); log_open(buff); check_arguments(); snprintf(oj_solution.work_dir, PATH_SIZE, "%s/%d", work_dir_root, oj_solution.sid); snprintf(oj_solution.data_dir, PATH_SIZE, "%s/%d", data_dir_root, oj_solution.pid); char source_file[PATH_SIZE]; snprintf(source_file, PATH_SIZE, "%s/Main.%s", oj_solution.work_dir, lang_ext[oj_solution.lang]); if (access(source_file, F_OK) == -1) { FM_LOG_FATAL("Source code file is missing."); exit(EXIT_NO_SOURCE_CODE); } if (oj_solution.lang == LANG_JAVA) { oj_solution.memory_limit *= java_memory_factor; oj_solution.time_limit *= java_time_factor; } else if (oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) { oj_solution.memory_limit *= python_memory_factor; oj_solution.time_limit *= python_time_factor; } else if (oj_solution.lang == LANG_KOTLIN) { oj_solution.memory_limit *= kotlin_memory_factor; oj_solution.time_limit *= kotlin_time_factor; } snprintf(buff, PATH_SIZE, "%s/last", work_dir_root); unlink(buff); if (symlink(oj_solution.work_dir, buff) == -1) { FM_LOG_NOTICE("make symlink for %s failed: %s", buff, strerror(errno)); } print_solution(); }
bool judge(const char *input_file, const char *output_file_std, const char *stdout_file_executive, const char *stderr_file_executive) { rusage rused{}; pid_t executor = fork(); // create a child process for executor if (executor < 0) { FM_LOG_FATAL("fork executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE); } else if (executor == 0) { // child process log_add_info("executor"); off_t fsize = file_size(output_file_std); // io redirect, must before set_security_option() io_redirect(input_file, stdout_file_executive, stderr_file_executive); // chroot & setuid set_security_option(); // set memory, time and file size limit etc. set_limit(fsize); // must after set_security_option() FM_LOG_DEBUG("time limit: %d, time limit addtion: %d", oj_solution.time_limit, time_limit_addtion); uint64_t real_time_limit = oj_solution.time_limit + time_limit_addtion; // time fix // set real time alarm if (EXIT_SUCCESS != malarm(ITIMER_REAL, real_time_limit)) { FM_LOG_FATAL("malarm for executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE); } FM_LOG_TRACE("begin execute"); if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) < 0) { FM_LOG_FATAL("Trace executor failed: %s", strerror(errno)); exit(EXIT_PRE_JUDGE_PTRACE); } // load program if (oj_solution.lang == LANG_JAVA) { print_executor(EXEC_J); execvp(EXEC_J[0], (char *const *) EXEC_J); } else if (oj_solution.lang == LANG_KOTLIN) { print_executor(EXEC_KT); execvp(EXEC_KT[0], (char *const *) EXEC_KT); } else if (oj_solution.lang == LANG_PYTHON27) { print_executor(EXEC_PY27); #ifdef FAST_JUDGE execvp(EXEC_PY27[0], (char * const *) EXEC_PY27); #else execv(EXEC_PY27[0], (char *const *) EXEC_PY27); #endif } else if (oj_solution.lang == LANG_PYTHON3) { print_executor(EXEC_PY3); #ifdef FAST_JUDGE execvp(EXEC_PY3[0], (char * const *) EXEC_PY3); #else execv(EXEC_PY3[0], (char *const *) EXEC_PY3); #endif } else { execl("./Main", "./Main", NULL); } // exec error FM_LOG_FATAL("exec error"); exit(EXIT_PRE_JUDGE_EXECLP); } else { // Judger int status = 0; user_regs_struct regs{}; stderr = freopen("error.txt", "a+", stderr); init_syscalls(oj_solution.lang); while (true) { if (wait4(executor, &status, 0, &rused) < 0) { FM_LOG_FATAL("wait4 executor failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } if (WIFEXITED(status)) { if ((oj_solution.lang != LANG_JAVA && oj_solution.lang != LANG_KOTLIN) || WEXITSTATUS(status) == EXIT_SUCCESS) { // AC PE WA FM_LOG_TRACE("normal quit"); int result; if (oj_solution.spj) { // use SPJ result = oj_compare_output_spj(input_file, output_file_std, stdout_file_executive, oj_solution.spj_exe_file); } else { // compare file result = oj_compare_output(output_file_std, stdout_file_executive); } // WA if (result == OJ_WA) { oj_solution.result = OJ_WA; } else if (oj_solution.result != OJ_PE) { // previous case is AC oj_solution.result = result; // AC or PE } else /* (oj_solution.result == OJ_PE) */ { // previous case is PE oj_solution.result = OJ_PE; } FM_LOG_NOTICE("case result: %d, problem result: %d", result, oj_solution.result); } else { // not return 0 oj_solution.result = OJ_RE; FM_LOG_NOTICE("abnormal quit, exit_code: %d", WEXITSTATUS(status)); } break; } // RE/TLE/OLE if (WIFSIGNALED(status) || (WIFSTOPPED(status) && WSTOPSIG(status) != SIGTRAP)) { int signo = 0; if (WIFSIGNALED(status)) { signo = WTERMSIG(status); FM_LOG_NOTICE("child process killed by signal %d, %s", signo, strsignal(signo)); } else { signo = WSTOPSIG(status); FM_LOG_NOTICE("child process stopped by signal %d, %s", signo, strsignal(signo)); } switch (signo) { // Ignore case SIGCHLD: oj_solution.result = OJ_AC; break; // TLE case SIGALRM: // alarm() and setitimer(ITIMER_REAL) case SIGVTALRM: // setitimer(ITIMER_VIRTUAL) case SIGXCPU: // exceeds soft processor limit oj_solution.result = OJ_TLE; FM_LOG_TRACE("Time Limit Exceeded: %s", strsignal(signo)); break; // OLE case SIGXFSZ: // exceeds file size limit oj_solution.result = OJ_OLE; FM_LOG_TRACE("Output Limit Exceeded"); break; // RE case SIGSEGV: // segmentation violation case SIGFPE: // any arithmetic exception case SIGBUS: // the process incurs a hardware fault case SIGABRT: // abort() function case SIGKILL: // exceeds hard processor limit default: oj_solution.result = OJ_RE; FILE *fp = fopen(stderr_file_executive, "a+"); if (fp == nullptr) { fprintf(stderr, "%s\n", strsignal(signo)); FM_LOG_WARNING("Runtime Error: %s", strsignal(signo)); } else { fprintf(fp, "%s\n", strsignal(signo)); fclose(fp); } break; } // end of swtich kill(executor, SIGKILL); break; } // end of "if (WIFSIGNALED(status) ...)" oj_solution.memory_usage = std::max(oj_solution.memory_usage, (unsigned long) rused.ru_maxrss); // TODO(power): check why memory exceed too much if (oj_solution.memory_usage > oj_solution.memory_limit) { oj_solution.result = OJ_MLE; kill(executor, SIGKILL); break; } // check syscall if (ptrace(PTRACE_GETREGS, executor, NULL, ®s) < 0) { FM_LOG_FATAL("ptrace(PTRACE_GETREGS) failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } int syscall_id = 0; #ifdef __i386__ syscall_id = (int)regs.orig_eax; #else syscall_id = (int) regs.orig_rax; #endif if (syscall_id > 0 && !is_valid_syscall(syscall_id)) { oj_solution.result = OJ_RF; FM_LOG_FATAL("restricted function, syscall_id: %d", syscall_id); kill(executor, SIGKILL); break; } if (ptrace(PTRACE_SYSCALL, executor, NULL, NULL) < 0) { FM_LOG_FATAL("ptrace(PTRACE_SYSCALL) failed: %s", strerror(errno)); kill(executor, SIGKILL); exit(EXIT_JUDGE); } } // end of while } // end of fork for judge process oj_solution.memory_usage = std::max(oj_solution.memory_usage, (unsigned long) rused.ru_maxrss); if (oj_solution.memory_usage > oj_solution.memory_limit) { oj_solution.result = OJ_MLE; FM_LOG_NOTICE("memory limit exceeded: %d (fault: %d * %d)", oj_solution.memory_usage, rused.ru_minflt, page_size); } oj_solution.time_usage = std::max(oj_solution.time_usage, (unsigned long) rused.ru_utime.tv_sec * 1000 + rused.ru_utime.tv_usec / 1000); if (oj_solution.time_usage > oj_solution.time_limit) { oj_solution.result = OJ_TLE; FM_LOG_TRACE("Time Limit Exceeded"); } if (oj_solution.result != OJ_AC) { if (oj_solution.judge_type == ACM) { FM_LOG_NOTICE("not AC/PE, no need to continue"); } if (oj_solution.result == OJ_TLE) { oj_solution.time_usage = oj_solution.time_limit; } else if (oj_solution.result == OJ_WA) { if (oj_solution.lang == LANG_JAVA) { // TODO: kotlin fix_java_result(stdout_file_executive, stderr_file_executive); } else if ((oj_solution.lang == LANG_PYTHON27 || oj_solution.lang == LANG_PYTHON3) && file_size(stderr_file_executive)) { oj_solution.result = OJ_RE; FM_LOG_TRACE("Runtime Error"); } } return false; } return true; }
int main(int argc, char *argv[], char *envp[]) { log_open(LOG_FILE); FM_LOG_TRACE("---"); check_pid(); int sockfd; socklen_t clilen; struct sockaddr_in serv_addr{}; struct sockaddr_in cli_addr{}; const char *cfg_file; if (argc > 1) { cfg_file = argv[1]; } else { cfg_file = DEFAULT_CFG_FILE; } read_config(cfg_file); FM_LOG_TRACE("read_config"); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { fatal_error("ERROR opening socket"); } FM_LOG_TRACE("socket"); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; if (inet_aton(oj_config.ip, &serv_addr.sin_addr) == 0) { serv_addr.sin_addr.s_addr = INADDR_ANY; } serv_addr.sin_port = htons(oj_config.port); FM_LOG_NOTICE("IP address: %s %s", oj_config.ip, inet_ntoa(serv_addr.sin_addr)); FM_LOG_NOTICE("port: %d %d", oj_config.port, ntohs(serv_addr.sin_port)); int yes = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { fatal_error("setsockopt SO_REUSEADDR failed"); } if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { fatal_error("ERROR on binding"); } FM_LOG_TRACE("bind"); clilen = sizeof(cli_addr); if (listen(sockfd, oj_config.backlog) < 0) { fatal_error("ERROR on listening"); } FM_LOG_NOTICE("listen backlog: %d", oj_config.backlog); if (daemon(0, 0) == -1) { FM_LOG_FATAL("Cannot daemonize"); pidfile_remove(pfh); exit(EXIT_FAILURE); } print_word_dir(); print_user_group(); pidfile_write(pfh); struct sigaction sa{}; sa.sa_handler = signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGTERM, &sa, nullptr) == -1) { // install signal hander for timeout FM_LOG_FATAL("cannot handle SIGTERM"); exit(EXIT_FAILURE); } else { FM_LOG_DEBUG("set signal_handler"); } for (int i = 0; i < oj_config.thread_num; i++) { std::thread t(ThreadWork); t.detach(); } FM_LOG_NOTICE("thread count: %d", oj_config.thread_num); std::thread(SendWork).detach(); while (isRunning) { int newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd != -1) { work(newsockfd, cli_addr); } } pidfile_remove(pfh); close(sockfd); return 0; }
void send_multi_result(char *file_path, oj_solution_t &oj_solution) { FM_LOG_TRACE("send_multi_result"); CURL *curl; CURLM *multi_handle; int still_running = 1; struct curl_httppost *formpost = nullptr; struct curl_httppost *lastptr = nullptr; struct curl_slist *headerlist = nullptr; static const char buf[] = "Expect:"; const size_t size = 25; char data[size] = {0}; curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "sid", CURLFORM_COPYCONTENTS, oj_solution.sid, CURLFORM_END); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "token", CURLFORM_COPYCONTENTS, oj_solution.token, CURLFORM_END); snprintf(data, size, "%d", oj_solution.cid); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "cid", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.result); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "result", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.time_usage); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "time", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.memory_usage); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "memory", CURLFORM_COPYCONTENTS, data, CURLFORM_END); snprintf(data, size, "%d", oj_solution.test); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "test", CURLFORM_COPYCONTENTS, data, CURLFORM_END); if (file_path != NULL && access(file_path, F_OK) != -1) { truncate_upload_file(file_path); FM_LOG_NOTICE("will upload error file %s", file_path); curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "error", CURLFORM_FILE, file_path, CURLFORM_END); } FM_LOG_TRACE("try curl_easy_init"); curl = curl_easy_init(); multi_handle = curl_multi_init(); headerlist = curl_slist_append(headerlist, buf); if (curl && multi_handle) { FM_LOG_TRACE("curl_multi_init OK"); curl_easy_setopt(curl, CURLOPT_URL, oj_config.api_url); curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); curl_multi_add_handle(multi_handle, curl); curl_multi_perform(multi_handle, &still_running); do { struct timeval timeout{}; int rc; /* select() return code */ CURLMcode mc; /* curl_multi_fdset() return code */ fd_set fdread; fd_set fdwrite; fd_set fdexcep; int maxfd = -1; long curl_timeo = -1; FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); /* set a suitable timeout to play around with */ timeout.tv_sec = 1; timeout.tv_usec = 0; curl_multi_timeout(multi_handle, &curl_timeo); if (curl_timeo >= 0) { timeout.tv_sec = curl_timeo / 1000; if (timeout.tv_sec > 1) timeout.tv_sec = 1; else timeout.tv_usec = (curl_timeo % 1000) * 1000; } /* get file descriptors from the transfers */ mc = curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); if (mc != CURLM_OK) { fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc); break; } if (maxfd == -1) { #ifdef _WIN32 Sleep(100); rc = 0; #else /* Portable sleep for platforms other than Windows. */ struct timeval wait = {0, 100 * 1000}; /* 100ms */ rc = select(0, NULL, NULL, NULL, &wait); #endif } else { /* Note that on some platforms 'timeout' may be modified by select(). If you need access to the original value save a copy beforehand. */ rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout); } switch (rc) { case -1: /* select error */ break; case 0: default: /* timeout or readable/writable sockets */ curl_multi_perform(multi_handle, &still_running); break; } } while (still_running); curl_multi_cleanup(multi_handle); curl_easy_cleanup(curl); curl_formfree(formpost); curl_slist_free_all(headerlist); FM_LOG_DEBUG("send_multi_result finished"); } else { FM_LOG_FATAL("cannot init curl: %s", strerror(errno)); update_system_error(EXIT_CURL_ERROR, oj_solution); } }
void run(oj_solution_t &oj_solution) { if (oj_solution.cid > 0) { snprintf(oj_solution.work_dir, PATH_SIZE, "%s/c%d", oj_config.temp_dir, oj_solution.cid); } else { strncpy(oj_solution.work_dir, oj_config.temp_dir, strlen(oj_config.temp_dir) + 1); } char stderr_file[PATH_SIZE]; snprintf(stderr_file, PATH_SIZE, "%s/%s/error.txt", oj_solution.work_dir, oj_solution.sid); FM_LOG_NOTICE("/usr/local/bin/powerjudge -s %s -p %s -l %s -t %s -m %s -w %s -D %s", oj_solution.sid, oj_solution.pid, oj_solution.language, oj_solution.time_limit, oj_solution.memory_limit, oj_solution.work_dir, oj_config.data_dir); pid_t pid = fork(); if (pid < 0) { FM_LOG_FATAL("fork judger failed: %s", strerror(errno)); SendQueue.push(std::make_pair(EXIT_FORK_ERROR, oj_solution)); } else if (pid == 0) { execl("/usr/local/bin/powerjudge", "/usr/local/bin/powerjudge", "-s", oj_solution.sid, "-p", oj_solution.pid, "-l", oj_solution.language, "-t", oj_solution.time_limit, "-m", oj_solution.memory_limit, "-w", oj_solution.work_dir, "-D", oj_config.data_dir, "-c", std::to_string(oj_solution.cid).c_str(), NULL); stderr = freopen(stderr_file, "a+", stderr); FM_LOG_FATAL("exec error: %s", strerror(errno)); SendQueue.push(std::make_pair(EXIT_EXEC_ERROR, oj_solution)); } else { int status = 0; FM_LOG_TRACE("process ID=%d", pid); if (waitpid(pid, &status, WUNTRACED) == -1) { FM_LOG_FATAL("waitpid for judger failed: %s", strerror(errno)); } if (WIFEXITED(status)) // normal termination { if (EXIT_SUCCESS == WEXITSTATUS(status)) { FM_LOG_DEBUG("judge succeeded"); SendQueue.push(std::make_pair(EXIT_OK, oj_solution)); } else if (EXIT_COMPILE_ERROR == WEXITSTATUS(status)) { FM_LOG_TRACE("compile error"); SendQueue.push(std::make_pair(EXIT_OK, oj_solution)); } else if (EXIT_JUDGE == WEXITSTATUS(status)) { FM_LOG_TRACE("judge error"); SendQueue.push(std::make_pair(OJ_SE, oj_solution)); } else { FM_LOG_TRACE("judge error"); SendQueue.push(std::make_pair(WEXITSTATUS(status), oj_solution)); } } else { if (WIFSIGNALED(status)) // killed by signal { int signo = WTERMSIG(status); FM_LOG_WARNING("judger killed by signal: %s", strsignal(signo)); SendQueue.push(std::make_pair(signo, oj_solution)); } else if (WIFSTOPPED(status)) // stopped by signal { int signo = WSTOPSIG(status); FM_LOG_FATAL("judger stopped by signal: %s\n", strsignal(signo)); SendQueue.push(std::make_pair(signo, oj_solution)); } else { FM_LOG_FATAL("judger stopped with unknown reason, status(%d)", status); SendQueue.push(std::make_pair(EXIT_UNKNOWN, oj_solution)); } } } }
void signal_handler(int signo) { if (signo == SIGTERM) { FM_LOG_NOTICE("SIGTERM received, Power Judge Exiting.."); isRunning = false; } }