OnlineJudge判題平臺——後臺流程
判題分兩部分
1.其中judged為服務程序,d即daemon。負責輪詢資料庫,提取判題隊列。當發現新任務時產生judge_client程序。
2.judge_client程序為實際判題程式,負責準備執行環境、資料,執行並監控目標程式的系統呼叫,採集執行指標,判斷執行結果。
Judged流程
初始化:
1.建立子程序pid_judged,並設定為會話的領頭程序(umask(0),close(0~2))
2.改變當前工作目錄為“/home/judge”
3.將pid_judged寫入檔案“/home/judge/etc/judge.pid”,並且加入寫鎖(用來檢查該服務程序是否已經在執行)
4.
輪詢:
5.連線資料庫(host_name,user_name,password,db_name,port_number)
6.輪詢資料庫中的solution表,將未測評的使用者提交扔進任務佇列
7.從任務佇列提取任務給“判題程序”(子程序),並標記該任務為“正在測評”
8.使用rlimit結構體和setrlimit()設定“判題程序”的允許的最大CPU運行時間,可以建立的最大檔案位元組數,可用記憶體最大位元組數,可擁有最大程序數(200)
9.呼叫execl函數執行/usr/bin/judge_client
Judge_client流程
初始化:
1.設定工作目錄為/home/judge
2.獲取任務id,judge_client_id
3.連線資料庫
4.設定工作目錄為workdir=“/home/judge/run?”
5.解掛檔案系統:workdir/proc,刪除workdir/下的所有檔案和目錄
編譯:
6.查詢資料庫獲取題目id,使用者id,語言型別
7.查詢資料庫獲取 題目規定的最大執行時間time_lmt,最大內存mem_lmt
8.查詢資料庫獲取使用者提交的程式碼並寫入Main.cc檔案
9.建立子程序使用
10.父程序呼叫waitpid函式來等待子程序編譯結束,通過檢視ce.txt檔案來判斷是否為編譯錯誤,若為編譯錯誤則退出
提取輸入輸出資料
11.在/home/judge/data/獲取題目輸入資料檔案並儲存路徑為infile
12.將題目輸入資料拷貝到workdir/data.in檔案
13.獲取題目輸出資料檔案並儲存路徑為outfile,建立user.out檔案並儲存路徑為userfile
執行目標程式:
14.建立子程序pidApp,重定向輸入輸出流,從data.in讀入資料,執行結果寫入user.out,執行錯誤資訊寫入error.out
15.使用ptrace(PTRACE_TRACEME, 0, NULL, NULL)函式來使父程序跟蹤自己
16.設定工作目錄workdir為根目錄(chroot()),提高系統安全性
17.使用rlimit結構體設定程序的CPU執行時間,可以建立最大檔案位元組數,可擁有最大程序數(1),擁有的堆疊數,可用記憶體數
18.alarm()設定定時器
19.呼叫execl使程序執行Main文件(目標程式)
監控目標程式:
20.父程序呼叫wait4(pidApp,&status,0,&ruse)來獲取子程序暫停或中止時的返回狀態和檢視程序的使用資源情況
21.檢視workdir/pro/pidApp/status裡的VmPeak:屬性的值,這個值是程序使用的最大記憶體數,如果超出限制,則ptrace(PTRACE_KILL,pidApp,NULL,NULL);退出監控
22.呼叫WIFEXITED(status)判斷子程序是否正常結束
23.檢視error.out檔案,如果有內容則為執行錯誤,KILL掉子程序,監控結束
24.如果userfile的size > outfile的size*2,則為結果超出限制,kill掉子程序,監控結束
25.exitcode=WEXITSTATUS(status)獲取子程序exit()返回的結束程式碼,如果為0或5則為正常,否則為異常結束,根據訊號的類別給出相應錯誤,比如SIGALRM為計時器時間到了訊號,SIGXCPU為執行時間到了訊號,SIGXFSZ為輸出檔案大小超出訊號等等
26.呼叫WIFSIGNALED(status)檢查是否為異常結束(子程序通過訊號結束)
27.呼叫sig=WTERMSIG(status)取得使子程序結束的訊號編號,根據sig的類別給出相應的錯誤
28.呼叫ptrace(PTRACE_GETREGS,pidApp,NULL,®)來取得程序的暫存器資訊(reg.REG_SYSCALL),檢查系統呼叫函式的使用情況,若為禁止的系統呼叫函式則KILL掉子程序並將執行錯誤寫入結果AC_status,結束監控
29.呼叫ptrace(PTRACE_SYSCALL,pidApp,NULL,NULL)使子程序繼續執行
30.在監控結束以後統計usedtime+=ruse.ru_utime(使用者使用時間)+ruse.ru_stime(系統使用時間)
31.根據AC_status的值更新資料庫
感謝hustoj開原始碼及作者!