HUST JudgeOnline 开发日记 1

来源:互联网 发布:如何搭建云计算平台 编辑:程序博客网 时间:2024/05/16 03:02
首先介绍一下这个项目:这是我的毕业设计,一个B/S系统,用于ACM/ICPC(国际大学生程序设计竞赛)的再线评测与竞赛。 

附加说明: 该项目将作为遵循GPL协议的开源项目发布。

评测过程是这样的,选手通过浏览器登陆系统,阅读编程问题描述(这里所有问题都有标准输入和输出),然后编写代码,通过标单提交,在服务器端对选手的代码进行检查,然后编译运行,服务器要对选手的程序运行状态进行控制,主要控制这几项:
编译错误(Compile Error)
运行时错误(Runtime Error)
使用内存超出限制(Memory Limit Exceeded)
消耗CPU时间超出限制(Time Limit Exceeded)
程序输出的信息量超出限制(Output Limit Exceeded)

出现以上任何一项问题都要立即中止评测,并给出错误报告,反馈给选手。

如果编译运行成功,则对程序输出的信息进行检查,此时有以下情况
程序输出与期望的相同(Accepted)
程序输出与期望的不同(Wrong Answer)
程序输出格式有误(Presentation Error)

对于以上三种情况要分别给出信息,反馈给选手。

在比赛中,会有10道以内的编程题供选手解答。
对于比赛成绩的判定实行罚时记分制,即比赛开始时所有选手分数为0,然后依选手提交代码并得到(Accept)的时间来进行扣分,即选手提交代码越晚,扣分越多,同时如果提交代码后得到Accept以外的任何结果,都进行相应的扣分。
比赛结束后,先按选手解题数目,然后按罚时排序,同样的解题数,罚时越小越靠前。

以上为整个系统的功能概况。我把这个系统分为三个部分来完成:
1。评测程序
2。数据库
3。用户界面

评测程序在整个系统中的地位是非常重要的,而且也是难度最高的,所以我将这一个模块的实现放到了首要位置。

以下是试验阶段的部分代码,使用父进程对待运行的客户程序进行监视,用wait4()函数来监控并取得子进程的终止状态,子进程调用客户程序,并使用setrlimit来限制它。
这样已经可以判断出各种运行时错误,准确计算运行时间,唯一的问题是内存不好测量

#include <stdio.h>
#include 
<sys/resource.h>
#include 
<sys/time.h>
#include 
<signal.h>
#include 
<unistd.h>
#include 
<stdlib.h>
#include 
<sys/wait.h>
#include 
<errno.h>

#define MEGA_BYTES 1048576

int main(int argc, char * argv[])
{
    pid_t pid 
= vfork();
    
if( pid > 0){
        
struct rusage contest_usage;
        
int ret;
        
int contest_status;
        
do {
            
// non-block wait, so as to monitor the child proccess' status
            ret = wait4(pid, &contest_status, WNOHANG, &contest_usage);
        }
while(ret == 0);

        
if(WIFEXITED(contest_status)){
            puts(
"hooray!");  // the child process terminated normally
        }

        
else if(WIFSIGNALED(contest_status)){
            printf(
"There might be some error! ");
            
int sig = WTERMSIG(contest_status);
            printf(
"error id: %d ", sig);
            
if(sig == SIGXCPU){
                puts(
"time limit exceeded");
            }

            
if(sig == SIGXFSZ){
                puts(
"output limit exceeded");
            }

            
if(sig == SIGSEGV){
                puts(
"runtime error");
            }

            
if(sig==SIGKILL){
                puts(
"memory limit exceeded");          
            }

        }


        
// calculate the time used by contestant's process
        double utime,stime,tmp;
        utime 
= contest_usage.ru_utime.tv_sec*1000.0 + contest_usage.ru_utime.tv_usec/1000.0;
        stime 
= contest_usage.ru_stime.tv_sec*1000.0 + contest_usage.ru_stime.tv_usec/1000.0;
        printf(
"user time: %f ",utime);
        printf(
"sys  time: %f ",stime);
        
// how to count the memory cost of the process?
        
//
    }

    
else {
        
struct rlimit limit;
        
// forbid the system to do core dump;
        
// getrlimit(PLIMIT_CORE, &limit);
        limit.rlim_cur = 0;
        setrlimit(RLIMIT_CORE, 
&limit);
        
// set the limit on the child process's CPU time
        getrlimit(RLIMIT_CPU, &limit);
        limit.rlim_cur 
= 3;
        setrlimit(RLIMIT_CPU, 
&limit);
        
// set the limit on the child process's memory
        getrlimit(RLIMIT_AS, &limit);
        limit.rlim_cur 
= 128*MEGA_BYTES;
        setrlimit(RLIMIT_AS, 
&limit);
        
// set the limit on the Maximum size of file created by child process
        getrlimit(RLIMIT_FSIZE, &limit);
        limit.rlim_cur 
= 1024;   // currently set to 100K;
        setrlimit(RLIMIT_FSIZE, &limit);

        
int exec_ret;
        freopen(
"infile","r",stdin);
        exec_ret 
= execv("./contestant.out", argv);
        
// if it goes here, there must be something wrong
        printf("an exception! error id: %d ", exec_ret);
    }

}