1. 程式人生 > >OnlineJudge判題平臺——後臺流程

OnlineJudge判題平臺——後臺流程

判題分兩部分

1.judged為服務程序,ddaemon。負責輪詢資料庫,提取判題隊發現新任務時產生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.

設定SIGQUIT,SIGKILL,SIGTERM來觸發call_for_exit函式結束服務程序的執行

輪詢:

5.連線資料庫(host_name,user_name,password,db_name,port_number

6.輪詢資料庫中的solution表,將未測評的使用者提交扔進任務佇列

7.從任務佇列提取任務給“判題程序”(子程序),並標記該任務為“正在測評”

8.使用rlimit構體和setrlimit()設定“判題程序”的允許的最大CPU行時間,可以建立的最大檔案位元組數,可用記憶體最大位元組數,可擁有最大程序數(200

9.呼叫execl數執行/usr/bin/judge_client

,並傳遞引數為任務id,judge_client_id


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.建立子程序使用

execvp函式執行g++命令編譯Main.cc檔案,並將編譯資訊寫入ce.txt檔案中

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.如果userfilesize > outfilesize*2,則為結果超出限制,kill掉子程序,監控結束

25.exitcode=WEXITSTATUS(status)獲取子程序exit()返回的結束程式碼,如果為05則為正常,否則為異常結束,根據訊號的類別給出相應錯誤,比如SIGALRM為計時器時間到了訊號,SIGXCPU為執行時間到了訊號,SIGXFSZ為輸出檔案大小超出訊號等等

26.呼叫WIFSIGNALED(status)檢查是否為異常結束(子程序通過訊號結束)

27.呼叫sig=WTERMSIG(status)取得使子程序結束的訊號編號,根據sig的類別給出相應的錯誤

28.呼叫ptrace(PTRACE_GETREGS,pidApp,NULL,&reg)來取得程序的暫存器資訊(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開原始碼及作者!