diff options
author | LAN-TW <lantw44@gmail.com> | 2013-04-11 22:33:25 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2013-04-11 22:33:25 +0800 |
commit | 962be8a7de5035e7d86b9274962f7d6fe3315fdd (patch) | |
tree | a78bd11270904346d2e26123482c25f73664f728 /judge | |
parent | 4c094052d68e90bd672ae2d312419861e5f71722 (diff) | |
download | taiwan-online-judge-lantw44-962be8a7de5035e7d86b9274962f7d6fe3315fdd.tar.gz taiwan-online-judge-lantw44-962be8a7de5035e7d86b9274962f7d6fe3315fdd.tar.zst taiwan-online-judge-lantw44-962be8a7de5035e7d86b9274962f7d6fe3315fdd.zip |
Remove top-level directory `toj'
Diffstat (limited to 'judge')
-rw-r--r-- | judge/Makefile | 6 | ||||
-rw-r--r-- | judge/center.h | 47 | ||||
-rw-r--r-- | judge/center_com.h | 70 | ||||
-rw-r--r-- | judge/center_judge.cpp | 578 | ||||
-rw-r--r-- | judge/center_judge.h | 106 | ||||
-rw-r--r-- | judge/center_manage.cpp | 640 | ||||
-rw-r--r-- | judge/center_manage.h | 75 | ||||
-rw-r--r-- | judge/center_server.cpp | 198 | ||||
-rw-r--r-- | judge/center_server.h | 45 | ||||
-rw-r--r-- | judge/event_exec.cpp | 89 | ||||
-rw-r--r-- | judge/event_exec.h | 12 | ||||
-rw-r--r-- | judge/jmod_test.h | 17 | ||||
-rw-r--r-- | judge/jmod_test_check.cpp | 109 | ||||
-rw-r--r-- | judge/jmod_test_check.h | 4 | ||||
-rw-r--r-- | judge/jmod_test_line.cpp | 190 | ||||
-rw-r--r-- | judge/jmod_test_line.h | 11 | ||||
-rw-r--r-- | judge/jmod_test_manage.cpp | 96 | ||||
-rw-r--r-- | judge/jmod_test_manage.h | 35 | ||||
-rw-r--r-- | judge/judge.h | 44 | ||||
-rw-r--r-- | judge/judge_manage.cpp | 371 | ||||
-rw-r--r-- | judge/judge_manage.h | 60 | ||||
-rw-r--r-- | judge/judge_server.cpp | 515 | ||||
-rw-r--r-- | judge/judge_server.h | 87 | ||||
-rw-r--r-- | judge/judgm_lib.h | 418 | ||||
-rw-r--r-- | judge/judgm_line.h | 19 | ||||
-rw-r--r-- | judge/judgm_manage.h | 29 | ||||
-rw-r--r-- | judge/netio.h | 192 | ||||
-rw-r--r-- | judge/tool.cpp | 294 | ||||
-rw-r--r-- | judge/tool.h | 26 | ||||
-rw-r--r-- | judge/tpool.h | 175 |
30 files changed, 4558 insertions, 0 deletions
diff --git a/judge/Makefile b/judge/Makefile new file mode 100644 index 0000000..3fe0444 --- /dev/null +++ b/judge/Makefile @@ -0,0 +1,6 @@ +all: + g++ -I../include -g -rdynamic -fvisibility=hidden -O2 center_server.cpp center_manage.cpp center_judge.cpp tool.cpp event_exec.cpp -ldl -lpq -ltar -lbz2 -ljson -lcurl -pthread -o center_server + g++ -I../include -g -O2 judge_server.cpp judge_manage.cpp tool.cpp -ldl -lbz2 -ltar -pthread -o judge_server + g++ -shared -fPIC -fvisibility=hidden -O2 -I../include jmod_test_manage.cpp -ldl -ljson -pthread -o jmod_test_manage.so + g++ -shared -fPIC -fvisibility=hidden -O2 -I../include jmod_test_line.cpp -ljson -pthread -o jmod_test_line.so + g++ -shared -fPIC -fvisibility=hidden -O2 -I../include jmod_test_check.cpp -o jmod_test_check.so diff --git a/judge/center.h b/judge/center.h new file mode 100644 index 0000000..2625ab4 --- /dev/null +++ b/judge/center.h @@ -0,0 +1,47 @@ +#define CENTER_CACHESTATE_READY 0 +#define CENTER_CACHESTATE_UPDATE 1 + +class center_jmod_info{ +public: + char name[NAME_MAX + 1]; + int cacheid; + void *manage_dll; + void *manage_sub_fn; + void *manage_res_fn; + + int ref_count; + int state; + int update_cacheid; + + center_jmod_info(char *name,int cacheid){ + this->name[0] = '\0'; + strncat(this->name,name,sizeof(this->name)); + this->cacheid = cacheid; + this->manage_dll = NULL; + this->manage_sub_fn = NULL; + this->manage_res_fn = NULL; + } +}; + +class center_pro_info{ +public: + int proid; + int cacheid; + center_jmod_info *jmod_info; + int lang_flag; + + int ref_count; + int state; + int update_cacheid; + + center_pro_info(int proid,int cacheid,center_jmod_info *jmod_info,int lang_flag){ + this->proid = proid; + this->cacheid = cacheid; + this->jmod_info = jmod_info; + this->lang_flag = lang_flag; + + this->ref_count = 0; + this->state = CENTER_CACHESTATE_READY; + this->update_cacheid = 0; + } +}; diff --git a/judge/center_com.h b/judge/center_com.h new file mode 100644 index 0000000..6973eec --- /dev/null +++ b/judge/center_com.h @@ -0,0 +1,70 @@ +#define CENTER_COMCODE_SETID 1 +#define CENTER_COMCODE_SETINFO 2 +#define CENTER_COMCODE_SUBMIT 3 +#define CENTER_COMCODE_RESULT 4 + +#define CENTER_COMCODE_SETPRO 10 +#define CENTER_COMCODE_REQPRO 11 +#define CENTER_COMCODE_SENDPRO 12 +#define CENTER_COMCODE_SETJMOD 13 +#define CENTER_COMCODE_REQJMOD 14 +#define CENTER_COMCODE_SENDJMOD 15 + +#define CENTER_COMCODE_REQCODE 20 +#define CENTER_COMCODE_SENDCODE 21 + +struct center_com_header{ + int code; + int size; +}__attribute__((packed)); +struct center_com_setid{ + int id; //0:new judge +}__attribute__((packed)); +struct center_com_setinfo{ + int avail; +}__attribute__((packed)); +struct center_com_submit{ //judt submit header + int subid; + int proid; + int lang; +}__attribute__((packed)); +struct center_com_result{ //just result header + int subid; +}__attribute__((packed)); + +struct center_com_setpro{ + int proid; + int cacheid; + int type; //0:add problem 1:drop problem +}__attribute__((packed)); +struct center_com_reqpro{ + int proid; + int cacheid; +}__attribute__((packed)); +struct center_com_sendpro{ + int proid; + int cacheid; + size_t filesize; +}__attribute__((packed)); + +struct center_com_setjmod{ + char jmod_name[NAME_MAX + 1]; + int cacheid; + int type; //0:add jmod 1:drop jmod +}__attribute__((packed)); +struct center_com_reqjmod{ + char jmod_name[NAME_MAX + 1]; +}__attribute__((packed)); +struct center_com_sendjmod{ + char jmod_name[NAME_MAX + 1]; + int cacheid; + size_t filesize; +}__attribute__((packed)); + +struct center_com_reqcode{ + int subid; +}__attribute__((packed)); +struct center_com_sendcode{ + int subid; + size_t filesize; +}__attribute__((packed)); diff --git a/judge/center_judge.cpp b/judge/center_judge.cpp new file mode 100644 index 0000000..46600c2 --- /dev/null +++ b/judge/center_judge.cpp @@ -0,0 +1,578 @@ +#include<stdio.h> +#include<stdlib.h> +#include<string.h> +#include<unistd.h> +#include<fcntl.h> +#include<limits.h> +#include<errno.h> +#include<sys/stat.h> +#include<sys/types.h> +#include<sys/epoll.h> +#include<sys/sendfile.h> +#include<map> +#include<list> +#include<queue> +#include<string> + +#include"netio.h" +#include"judge_def.h" +#include"judgm_manage.h" +#include"center.h" +#include"center_com.h" +#include"center_judge.h" + +int judge_info::last_id = 0; +judge_info::judge_info(){ + last_id++; + this->id = last_id; + this->avail = 0; + + judge_idmap.insert(std::pair<int,judge_info*>(id,this)); + judge_runlist.push_back(this); + judge_it = judge_runlist.end(); + judge_it--; +} +judge_info::~judge_info(){ + judge_idmap.erase(id); + judge_runlist.erase(judge_it); +} +int judge_info::setavail(int avail){ + int old; + + old = this->avail; + this->avail = avail; + if(this->avail > 0 && old <= 0){ + judge_runlist.erase(judge_it); + judge_runlist.push_front(this); + judge_it = judge_runlist.begin(); + }else if(this->avail <= 0 && old > 0){ + judge_runlist.erase(judge_it); + judge_runlist.push_back(this); + judge_it = judge_runlist.end(); + judge_it--; + } + + return 0; +} +int judge_info::setinfo(int avail){ + setavail(avail); + return 0; +} +int judge_info::submit(judge_submit_info *sub_info){ + setavail(avail - 1); + conn_main->send_submit(sub_info); + return 0; +} +int judge_info::result(int subid,char *res_data){ + setavail(avail + 1); + + printf("submitid:%d\n",subid); + center_manage_result(subid,res_data); + + judge_run_waitqueue(); + return 0; +} +int judge_info::updatepro(std::vector<std::pair<int,int> > &pro_list){ + int i; + + for(i = 0;i < pro_list.size();i++){ + pro_map.erase(pro_list[i].first); + } + conn_main->send_setpro(pro_list,0); + + return 0; +} +int judge_info::updatejmod(std::vector<std::pair<char*,int> > &jmod_list){ + int i; + + for(i = 0;i < jmod_list.size();i++){ + jmod_map.erase(jmod_list[i].first); + } + conn_main->send_setjmod(jmod_list,0); + + return 0; +} + + +judge_conn::judge_conn(int fd):netio(fd){ + this->info = NULL; + this->recv_dispatch_fn = new netio_iofn<judge_conn>(this,&judge_conn::recv_dispatch); + this->recv_setid_fn = new netio_iofn<judge_conn>(this,&judge_conn::recv_setid); + this->recv_setinfo_fn = new netio_iofn<judge_conn>(this,&judge_conn::recv_setinfo); + this->recv_result_fn = new netio_iofn<judge_conn>(this,&judge_conn::recv_result); + this->recv_setpro_fn = new netio_iofn<judge_conn>(this,&judge_conn::recv_setpro); + this->recv_reqpro_fn = new netio_iofn<judge_conn>(this,&judge_conn::recv_reqpro); + this->done_sendpro_fn = new netio_iofn<judge_conn>(this,&judge_conn::done_sendpro); + this->recv_setjmod_fn = new netio_iofn<judge_conn>(this,&judge_conn::recv_setjmod); + this->recv_reqjmod_fn = new netio_iofn<judge_conn>(this,&judge_conn::recv_reqjmod); + this->recv_reqcode_fn = new netio_iofn<judge_conn>(this,&judge_conn::recv_reqcode); +} +judge_conn::~judge_conn(){ + info->conn_list.erase(conn_it); + if(info->conn_main == this){ + info->conn_main = NULL; + } + if(info->conn_list.empty()){ + delete info; + } + + delete recv_dispatch_fn; + delete recv_setid_fn; + delete recv_setinfo_fn; + delete recv_result_fn; + delete recv_setpro_fn; + delete recv_reqpro_fn; + delete done_sendpro_fn; + delete recv_setjmod_fn; + delete recv_reqjmod_fn; + delete recv_reqcode_fn; +} +char* judge_conn::create_combuf(int code,int size,int &len,void **data){ + char *buf; + center_com_header *header; + + buf = new char[sizeof(center_com_header) + size]; + header = (center_com_header*)buf; + header->code = code; + header->size = size; + len = sizeof(center_com_header) + size; + *data = (void*)(buf + sizeof(center_com_header)); + + return buf; +} +int judge_conn::send_setid(int judgeid){ + char *write_buf; + int write_len; + center_com_setid *setid; + + write_buf = create_combuf(CENTER_COMCODE_SETID,sizeof(center_com_setid),write_len,(void**)&setid); + setid->id = judgeid; + writebytes(write_buf,write_len,NULL,NULL); + + return 0; +} +int judge_conn::send_submit(judge_submit_info *sub_info){ + char *write_buf; + int write_len; + center_com_submit *sub; + + if(sub_info->set_len > JUDGE_SET_DATAMAX){ + delete sub_info; + return -1; + } + + write_buf = create_combuf(CENTER_COMCODE_SUBMIT,sizeof(center_com_submit) + sub_info->set_len,write_len,(void**)&sub); + sub->subid = sub_info->subid; + sub->proid = sub_info->proid; + sub->lang = sub_info->lang; + memcpy((void*)(write_buf + sizeof(center_com_header) + sizeof(center_com_submit)),sub_info->set_data,sub_info->set_len); + writebytes(write_buf,write_len,NULL,NULL); + + delete sub_info; + return 0; +} +int judge_conn::send_setpro(std::vector<std::pair<int,int> > &pro_list,int type){ + int i; + + int count; + char *write_buf; + int write_len; + center_com_setpro *setpro; + + count = pro_list.size(); + write_buf = create_combuf(CENTER_COMCODE_SETPRO,sizeof(center_com_setpro) * count,write_len,(void**)&setpro); + + for(i = 0;i < count;i++){ + setpro[i].proid = pro_list[i].first; + setpro[i].cacheid = pro_list[i].second; + setpro[i].type = type; + } + writebytes(write_buf,write_len,NULL,NULL); + + return 0; +} +int judge_conn::send_setjmod(std::vector<std::pair<char*,int> > &jmod_list,int type){ + int i; + + int count; + char *write_buf; + int write_len; + center_com_setjmod *setjmod; + + count = jmod_list.size(); + write_buf = create_combuf(CENTER_COMCODE_SETJMOD,sizeof(center_com_setjmod) * count,write_len,(void**)&setjmod); + + for(i = 0;i < count;i++){ + setjmod[i].jmod_name[0] = '\0'; + strncat(setjmod[i].jmod_name,jmod_list[i].first,sizeof(setjmod[i].jmod_name)); + setjmod[i].cacheid = jmod_list[i].second; + setjmod[i].type = type; + } + writebytes(write_buf,write_len,NULL,NULL); + + return 0; +} +int judge_conn::readidle(){ + readbytes(new center_com_header,sizeof(center_com_header),recv_dispatch_fn,NULL); + return 0; +} +void judge_conn::recv_dispatch(void *buf,size_t len,void *data){ + center_com_header *header; + char *readbuf; + + header = (center_com_header*)buf; + readbuf = new char[header->size]; + + printf("code:%d size:%d\n",header->code,header->size); + switch(header->code){ + case CENTER_COMCODE_SETID: + readbytes(readbuf,header->size,recv_setid_fn,NULL); + break; + case CENTER_COMCODE_SETINFO: + readbytes(readbuf,header->size,recv_setinfo_fn,NULL); + break; + case CENTER_COMCODE_RESULT: + readbytes(readbuf,header->size,recv_result_fn,NULL); + break; + case CENTER_COMCODE_SETPRO: + readbytes(readbuf,header->size,recv_setpro_fn,NULL); + break; + case CENTER_COMCODE_REQPRO: + readbytes(readbuf,header->size,recv_reqpro_fn,NULL); + break; + case CENTER_COMCODE_SETJMOD: + readbytes(readbuf,header->size,recv_setjmod_fn,NULL); + break; + case CENTER_COMCODE_REQJMOD: + readbytes(readbuf,header->size,recv_reqjmod_fn,NULL); + break; + case CENTER_COMCODE_REQCODE: + readbytes(readbuf,header->size,recv_reqcode_fn,NULL); + break; + } + + delete header; +} +void judge_conn::recv_setid(void *buf,size_t len,void *data){ + center_com_setid *setid; + std::map<int,judge_info*>::iterator it; + + setid = (center_com_setid*)buf; + if(setid->id == 0){ + info = new judge_info(); + + info->conn_list.push_front(this); + conn_it = info->conn_list.begin(); + info->conn_main = this; + + this->send_setid(info->id); + }else{ + if((it = judge_idmap.find(setid->id)) != judge_idmap.end()){ + info = it->second; + info->conn_list.push_front(this); + conn_it = info->conn_list.begin(); + } + } + + delete setid; +} +void judge_conn::recv_setinfo(void *buf,size_t len,void *data){ + int i; + int count; + + center_com_setinfo *setinfo; + std::map<std::string,center_jmod_info*>::iterator jmod_it; + std::vector<std::pair<char*,int> > jmod_list; + std::map<int,center_pro_info*>::iterator pro_it; + std::vector<std::pair<int,int> > pro_list; + + setinfo = (center_com_setinfo*)buf; + info->setinfo(setinfo->avail); + + count = center_manage_jmodmap.size(); + jmod_it = center_manage_jmodmap.begin(); + for(i = 0;i < count;i++,jmod_it++){ + jmod_list.push_back(std::make_pair(jmod_it->second->name,jmod_it->second->cacheid)); + } + send_setjmod(jmod_list,0); + + count = center_manage_promap.size(); + pro_it = center_manage_promap.begin(); + for(i = 0;i < count;i++,pro_it++){ + pro_list.push_back(std::make_pair(pro_it->second->proid,pro_it->second->cacheid)); + } + send_setpro(pro_list,0); + + delete setinfo; +} +void judge_conn::recv_result(void *buf,size_t len,void *data){ + int subid; + char *res_data; + + subid = ((center_com_result*)buf)->subid; + res_data = (char*)((char*)buf + sizeof(center_com_result)); + + info->result(subid,res_data); + + delete (char*)buf; +} +void judge_conn::recv_setpro(void *buf,size_t len,void *data){ + int i; + int count; + + center_com_setpro *setpro; + center_pro_info *pro_info; + std::map<int,center_pro_info*>::iterator pro_it; + + count = len / sizeof(center_com_setpro); + setpro = (center_com_setpro*)buf; + for(i = 0;i < count;i++){ + if(setpro[i].type == 0){ + if((pro_info = center_manage_getprobyid(setpro[i].proid)) == NULL){ + continue; + } + + if(pro_info->cacheid == setpro[i].cacheid){ + info->pro_map.insert(std::pair<int,int>(pro_info->proid,pro_info->cacheid)); + } + center_manage_putpro(pro_info); + + }else if(setpro[i].type == 1){ + info->pro_map.erase(setpro[i].proid); + } + } + + judge_run_waitqueue(); + delete setpro; +} +void judge_conn::recv_reqpro(void *buf,size_t len,void *data){ + center_com_reqpro *reqpro; + std::map<int,center_pro_info*>::iterator pro_it; + center_pro_info *pro_info; + + char tpath[PATH_MAX + 1]; + int fd; + struct stat st; + + char *write_buf; + int write_len; + center_com_sendpro *sendpro; + + reqpro = (center_com_reqpro*)buf; + try{ + if((pro_info = center_manage_getprobyid(reqpro->proid)) == NULL){ + throw -1; + } + if(pro_info->cacheid != reqpro->cacheid){ + throw -1; + } + + snprintf(tpath,sizeof(tpath),"tmp/propack/%d_%d.tar.bz2",pro_info->proid,pro_info->cacheid); + fd = open(tpath,O_RDONLY); + fstat(fd,&st); + write_buf = create_combuf(CENTER_COMCODE_SENDPRO,sizeof(center_com_sendpro),write_len,(void**)&sendpro); + sendpro->proid = pro_info->proid; + sendpro->cacheid = pro_info->cacheid; + sendpro->filesize = st.st_size; + printf("sendpro:%lu\n",sendpro->filesize); + + writebytes(write_buf,write_len,NULL,NULL); + writefile(fd,st.st_size,done_sendpro_fn,pro_info); + }catch(int err){ + if(pro_info != NULL){ + center_manage_putpro(pro_info); + } + } + + delete reqpro; +} +void judge_conn::done_sendpro(void *buf,size_t len,void *data){ + close((int)((long)buf)); + center_manage_putpro((center_pro_info*)data); +} +void judge_conn::recv_setjmod(void *buf,size_t len,void *data){ + int i; + int count; + + center_com_setjmod *setjmod; + std::map<std::string,center_jmod_info*>::iterator jmod_it; + + count = len / sizeof(center_com_setjmod); + setjmod = (center_com_setjmod*)buf; + for(i = 0;i < count;i++){ + if(setjmod[i].type == 0){ + if((jmod_it = center_manage_jmodmap.find(setjmod[i].jmod_name)) == center_manage_jmodmap.end()){ + continue; + } + if(jmod_it->second->cacheid != setjmod[i].cacheid){ + continue; + } + + info->jmod_map.insert(std::pair<std::string,center_jmod_info*>(jmod_it->second->name,jmod_it->second)); + }else if(setjmod[i].type == 1){ + info->jmod_map.erase(setjmod[i].jmod_name); + } + } + + judge_run_waitqueue(); + delete setjmod; +} +void judge_conn::recv_reqjmod(void *buf,size_t len,void *data){ + center_com_reqjmod *reqjmod; + std::map<std::string,center_jmod_info*>::iterator jmod_it; + center_jmod_info *jmod_info; + + char tpath[PATH_MAX + 1]; + int fd; + struct stat st; + + char *write_buf; + int write_len; + center_com_sendjmod *sendjmod; + + reqjmod = (center_com_reqjmod*)buf; + if((jmod_it = center_manage_jmodmap.find(reqjmod->jmod_name)) == center_manage_jmodmap.end()){ + //fix + }else{ + jmod_info = jmod_it->second; + + snprintf(tpath,sizeof(tpath),"tmp/jmodpack/%s.tar.bz2",jmod_info->name); + fd = open(tpath,O_RDONLY); + if(fstat(fd,&st)){ + //fix + }else{ + write_buf = create_combuf(CENTER_COMCODE_SENDJMOD,sizeof(center_com_sendjmod),write_len,(void**)&sendjmod); + sendjmod->jmod_name[0] = '\0'; + strncat(sendjmod->jmod_name,jmod_info->name,sizeof(sendjmod->jmod_name)); + sendjmod->cacheid = jmod_info->cacheid; + sendjmod->filesize = st.st_size; + printf("sendjmod:%lu\n",sendjmod->filesize); + + writebytes(write_buf,write_len,NULL,NULL); + writefile(fd,st.st_size,NULL,NULL); + } + } + + delete reqjmod; +} +void judge_conn::recv_reqcode(void *buf,size_t len,void *data){ + center_com_reqcode *reqcode; + char tpath[PATH_MAX + 1]; + int fd; + struct stat st; + + char *write_buf; + int write_len; + center_com_header *header; + center_com_sendcode *sendcode; + + reqcode = (center_com_reqcode*)buf; + snprintf(tpath,sizeof(tpath),"tmp/codepack/%d.tar.bz2",reqcode->subid); + fd = open(tpath,O_RDONLY); + if(fstat(fd,&st)){ + //fix + }else{ + write_buf = create_combuf(CENTER_COMCODE_SENDCODE,sizeof(center_com_sendcode),write_len,(void**)&sendcode); + sendcode->subid = reqcode->subid; + sendcode->filesize = st.st_size; + printf("sendcode:%lu\n",sendcode->filesize); + + writebytes(write_buf,write_len,NULL,NULL); + writefile(fd,st.st_size,NULL,NULL); + } + + delete reqcode; +} + + +static int judge_run_waitqueue(){ + int count; + judge_submit_info *sub_info; + bool wait_flag; + std::list<judge_info*>::iterator judge_it; + judge_info *info; + std::map<int,center_pro_info*>::iterator pro_it; + center_pro_info *pro_info; + + count = judge_submitqueue.size(); + printf(" remain count %d\n",count); + for(;count > 0;count--){ + sub_info = judge_submitqueue.front(); + judge_submitqueue.pop(); + + if((pro_it = center_manage_promap.find(sub_info->proid)) == center_manage_promap.end()){ + continue; + } + pro_info = pro_it->second; + + wait_flag = true; + for(judge_it = judge_runlist.begin();judge_it != judge_runlist.end();judge_it++){ + info = *judge_it; + if(info->avail <= 0){ + break; + } + if(info->pro_map.find(pro_info->proid) != info->pro_map.end() && info->jmod_map.find(pro_info->jmod_info->name) != info->jmod_map.end()){ + info->submit(sub_info); + wait_flag = false; + break; + } + } + if(wait_flag == true){ + judge_submitqueue.push(sub_info); + } + } + return 0; +} +int center_judge_init(){ + return 0; +} +void* center_judge_addconn(int fd){ + return new judge_conn(fd); +} +int center_judge_dispatch(int evflag,void *data){ + judge_conn *cinfo; + + cinfo = (judge_conn*)data; + if(evflag & EPOLLRDHUP){ + printf("close %d\n",cinfo->fd); + delete cinfo; + }else{ + if(evflag & EPOLLIN){ + cinfo->readio(); + } + if(evflag & EPOLLOUT){ + cinfo->writeio(); + } + } + + return 0; +} +int center_judge_submit(int subid,int proid,int lang,char *set_data,size_t set_len){ + judge_submitqueue.push(new judge_submit_info(subid,proid,lang,set_data,set_len)); + judge_run_waitqueue(); + return 0; +} +int center_judge_updatepro(std::vector<std::pair<int,int> > &pro_list){ + int i; + int j; + std::list<judge_info*>::iterator judge_it; + judge_info *info; + + for(judge_it = judge_runlist.begin();judge_it != judge_runlist.end();judge_it++){ + (*judge_it)->updatepro(pro_list); + } + + return 0; +} +int center_judge_updatejmod(std::vector<std::pair<char*,int> > &jmod_list){ + int i; + int j; + std::list<judge_info*>::iterator judge_it; + judge_info *info; + + for(judge_it = judge_runlist.begin();judge_it != judge_runlist.end();judge_it++){ + (*judge_it)->updatejmod(jmod_list); + } + + return 0; +} diff --git a/judge/center_judge.h b/judge/center_judge.h new file mode 100644 index 0000000..a955ce9 --- /dev/null +++ b/judge/center_judge.h @@ -0,0 +1,106 @@ +class judge_info; +class judge_conn; +class judge_submit_info; + +class judge_info{ +private: + static int last_id; + +public: + int id; + int avail; + judge_conn *conn_main; + std::list<judge_conn*> conn_list; + std::list<judge_info*>::iterator judge_it; + std::map<int,int> pro_map; + std::map<std::string,center_jmod_info*> jmod_map; + + judge_info(); + ~judge_info(); + int setavail(int value); + int setinfo(int avail); + int submit(judge_submit_info *submit_info); + int result(int subid,char *res_data); + int updatepro(std::vector<std::pair<int,int> > &pro_list); + int updatejmod(std::vector<std::pair<char*,int> > &jmod_list); +}; + +class judge_conn : public netio{ +private: + netio_iofn<judge_conn> *recv_dispatch_fn; + netio_iofn<judge_conn> *recv_setid_fn; + netio_iofn<judge_conn> *recv_setinfo_fn; + netio_iofn<judge_conn> *recv_result_fn; + netio_iofn<judge_conn> *recv_setpro_fn; + netio_iofn<judge_conn> *recv_reqpro_fn; + netio_iofn<judge_conn> *done_sendpro_fn; + netio_iofn<judge_conn> *recv_setjmod_fn; + netio_iofn<judge_conn> *recv_reqjmod_fn; + netio_iofn<judge_conn> *recv_reqcode_fn; + + char* create_combuf(int code,int size,int &len,void **data); + void recv_dispatch(void *buf,size_t len,void *data); + void recv_setid(void *buf,size_t len,void *data); + void recv_setinfo(void *buf,size_t len,void *data); + void recv_result(void *buf,size_t len,void *data); + void recv_setpro(void *buf,size_t len,void *data); + void recv_reqpro(void *buf,size_t len,void *data); + void done_sendpro(void *buf,size_t len,void *data); + void recv_setjmod(void *buf,size_t len,void *data); + void recv_reqjmod(void *buf,size_t len,void *data); + void recv_reqcode(void *buf,size_t len,void *data); + +public: + judge_info *info; + std::list<judge_conn*>::iterator conn_it; + + judge_conn(int fd); + ~judge_conn(); + int send_setid(int judgeid); + int send_submit(judge_submit_info* submit_info); + int send_setpro(std::vector<std::pair<int,int> > &pro_list,int type); + int send_setjmod(std::vector<std::pair<char*,int> > &jmod_list,int type); + virtual int readidle(); +}; + +class judge_submit_info{ +public: + int subid; + int proid; + int lang; + char *set_data; + size_t set_len; + + judge_submit_info(int subid,int proid,int lang,char *set_data,size_t set_len){ + this->subid = subid; + this->proid = proid; + this->lang = lang; + this->set_data = new char[set_len]; + memcpy(this->set_data,set_data,set_len); + this->set_len = set_len; + } + ~judge_submit_info(){ + delete this->set_data; + } +}; + +static int judge_run_waitqueue(); + +static std::map<int,judge_info*> judge_idmap; +static std::list<judge_info*> judge_runlist; +static std::queue<judge_submit_info*> judge_submitqueue; + +int center_judge_init(); +void* center_judge_addconn(int fd); +int center_judge_dispatch(int evflag,void *data); +int center_judge_submit(int subid,int proid,int lang,char *set_data,size_t set_len); +int center_judge_updatepro(std::vector<std::pair<int,int> > &pro_list); +int center_judge_updatejmod(std::vector<std::pair<char*,int> > &jmod_list); + +extern int center_manage_result(int subid,char *res_data); +extern center_pro_info* center_manage_getprobyid(int proid); +extern int center_manage_getpro(center_pro_info *pro_info); +extern int center_manage_putpro(center_pro_info *pro_info); + +extern std::map<std::string,center_jmod_info*> center_manage_jmodmap; +extern std::map<int,center_pro_info*> center_manage_promap; diff --git a/judge/center_manage.cpp b/judge/center_manage.cpp new file mode 100644 index 0000000..48cfd31 --- /dev/null +++ b/judge/center_manage.cpp @@ -0,0 +1,640 @@ +#include<stdio.h> +#include<stdlib.h> +#include<string.h> +#include<limits.h> +#include<dlfcn.h> +#include<unistd.h> +#include<pthread.h> +#include<semaphore.h> +#include<libpq-fe.h> +#include<sys/eventfd.h> +#include<sys/stat.h> +#include<json/json.h> +#include<vector> +#include<queue> +#include<map> +#include<string> + +#include"tpool.h" +#include"event_exec.h" +#include"judge_def.h" +#include"judgm_manage.h" +#include"center.h" +#include"center_manage.h" + +int center_manage_init(tpool **tpinfo){ + manage_tp = new tpool(4); + manage_tp->start(); + *tpinfo = manage_tp; + + manage_updatepro_thfn = new tpool_static_fn(manage_updatepro_th); + manage_updatepro_cbfn = new tpool_static_fn(manage_updatepro_cb); + manage_updatejmod_thfn = new tpool_static_fn(manage_updatejmod_th); + manage_updatejmod_cbfn = new tpool_static_fn(manage_updatejmod_cb); + manage_submit_thfn = new tpool_static_fn(manage_submit_th); + manage_submit_cbfn = new tpool_static_fn(manage_submit_cb); + + //run when startup + center_manage_updatedata(); + center_manage_submitwait(); + return 0; +} +PGconn* center_manage_conndb(){ + return PQconnectdb("host=localhost port=5432 dbname=xxxxx user=xxxxx password=xxxxx"); +} +int center_manage_closedb(PGconn *conn){ + PQfinish(conn); + return 0; +} +int center_manage_updatedata(){ + int i; + + PGconn *db_conn; + PGresult *db_res; + int db_count; + int cacheid; + center_jmod_info *jmod_info; + int proid; + int lang_flag; + std::map<std::string,center_jmod_info*>::iterator jmod_it; + center_pro_info *pro_info; + + std::vector<std::pair<int,int> > pro_list; + + if((db_conn = center_manage_conndb()) == NULL){ + return -1; + } + + db_res = PQexec(db_conn,"SELECT DISTINCT \"jmodname\" FROM \"mod\";"); + if(PQresultStatus(db_res) != PGRES_TUPLES_OK){ + center_manage_closedb(db_conn); + return -1; + } + + db_count = PQntuples(db_res); + for(i = 0;i < db_count;i++){ + jmod_info = new center_jmod_info(PQgetvalue(db_res,i,0),2); + center_manage_jmodmap.insert(std::pair<std::string,center_jmod_info*>(jmod_info->name,jmod_info)); + } + PQclear(db_res); + + db_res = PQexec(db_conn,"SELECT \"proid\",\"cacheid\",\"lang\",\"jmodname\" FROM \"problem\" INNER JOIN \"mod\" ON (\"problem\".\"modid\"=\"mod\".\"modid\");"); + if(PQresultStatus(db_res) != PGRES_TUPLES_OK){ + center_manage_closedb(db_conn); + return -1; + } + + db_count = PQntuples(db_res); + for(i = 0;i < db_count;i++){ + sscanf(PQgetvalue(db_res,i,0),"%d",&proid); + sscanf(PQgetvalue(db_res,i,1),"%d",&cacheid); + sscanf(PQgetvalue(db_res,i,2),"%d",&lang_flag); + if((jmod_it = center_manage_jmodmap.find(PQgetvalue(db_res,i,3))) == center_manage_jmodmap.end()){ + continue; + } + + if(manage_updatepro(proid,cacheid,jmod_it->second,lang_flag) == 1){ + pro_list.push_back(std::make_pair(proid,cacheid)); + + printf("pro update %d %d\n",proid,cacheid); + } + } + PQclear(db_res); + + if(!pro_list.empty()){ + center_judge_updatepro(pro_list); + } + + center_manage_closedb(db_conn); + return 0; +} +int center_manage_submitwait(){ + int i; + + PGconn *db_conn; + PGresult *db_res; + int db_count; + int subid; + + if((db_conn = center_manage_conndb()) == NULL){ + return -1; + } + + db_res = PQexec(db_conn,"SELECT \"subid\" FROM \"submit\" WHERE \"result\"=100;"); + if(PQresultStatus(db_res) != PGRES_TUPLES_OK){ + center_manage_closedb(db_conn); + return -1; + } + + db_count = PQntuples(db_res); + for(i = 0;i < db_count;i++){ + sscanf(PQgetvalue(db_res,i,0),"%d",&subid); + center_manage_submit(subid,"{}"); + } + + PQclear(db_res); + center_manage_closedb(db_conn); + return 0; +} + + +int center_manage_submit(int subid,char *param){ + PGconn *db_conn; + PGresult *db_res; + char *db_param[1]; + char db_subid[64]; + + int uid; + int proid; + int lang; + int result; + bool rejudge_flag; + std::map<int,center_pro_info*>::iterator pro_it; + center_pro_info *pro_info; + center_jmod_info *jmod_info; + manage_submit_info *sub_info; + + if((db_conn = center_manage_conndb()) == NULL){ + return -1; + } + + snprintf(db_subid,sizeof(db_subid),"%d",subid); + db_param[0] = db_subid; + db_res = PQexecParams(db_conn, + "SELECT \"uid\",\"proid\",\"lang\",\"result\" FROM \"submit\" WHERE \"subid\"=$1;", + 1, + NULL, + db_param, + NULL, + NULL, + 0); + if(PQresultStatus(db_res) != PGRES_TUPLES_OK){ + center_manage_closedb(db_conn); + return -1; + } + + sscanf(PQgetvalue(db_res,0,0),"%d",&uid); + sscanf(PQgetvalue(db_res,0,1),"%d",&proid); + sscanf(PQgetvalue(db_res,0,2),"%d",&lang); + sscanf(PQgetvalue(db_res,0,3),"%d",&result); + PQclear(db_res); + center_manage_closedb(db_conn); + + if((pro_it = center_manage_promap.find(proid)) == center_manage_promap.end()){ + return -1; + } + pro_info = pro_it->second; + + if((lang & pro_info->lang_flag) == 0){ + return -1; + } + jmod_info = pro_info->jmod_info; + + if(result == JUDGE_WAIT){ + rejudge_flag = false; + }else{ + rejudge_flag = true; + } + + center_manage_getpro(pro_info); + + sub_info = new manage_submit_info(subid,uid,jmod_info,pro_info,lang,rejudge_flag,param); + manage_submap.insert(std::pair<int,manage_submit_info*>(sub_info->subid,sub_info)); + manage_tp->add(manage_submit_thfn,sub_info,manage_submit_cbfn,sub_info); + + return 0; +} +static void manage_submit_th(void *data){ + manage_submit_info *sub_info; + char dir_path[PATH_MAX + 1]; + char pack_path[PATH_MAX + 1]; + + sub_info = (manage_submit_info*)data; + + snprintf(dir_path,sizeof(dir_path),"submit/%d/%d/data",(sub_info->subid / 1000) * 1000,sub_info->subid); + snprintf(pack_path,sizeof(pack_path),"tmp/codepack/%d.tar.bz2",sub_info->subid); + tool_pack(pack_path,dir_path); +} +static void manage_submit_cb(void *data){ + manage_submit_info *sub_info; + center_jmod_info *jmod_info; + center_pro_info *pro_info; + + char cwd_path[PATH_MAX + 1]; + char tpath[PATH_MAX + 1]; + judgm_manage_info *mg_info; + judgm_manage_submit_fn mg_sub_fn; + FILE *set_file; + char lchr; + char tchr; + + try{ + sub_info = (manage_submit_info*)data; + jmod_info = sub_info->jmod_info; + pro_info = sub_info->pro_info; + + if(jmod_info->manage_dll == NULL){ + getcwd(cwd_path,sizeof(cwd_path)); + snprintf(tpath,sizeof(tpath),"%s/jmod/%s/%s_manage.so",cwd_path,jmod_info->name,jmod_info->name); + + jmod_info->manage_dll = dlopen(tpath,RTLD_NOW); + jmod_info->manage_sub_fn = dlsym(jmod_info->manage_dll,"submit"); + jmod_info->manage_res_fn = dlsym(jmod_info->manage_dll,"result"); + } + mg_sub_fn = (judgm_manage_submit_fn)jmod_info->manage_sub_fn; + + mg_info = sub_info->manage_info; + snprintf(mg_info->pro_path,sizeof(mg_info->pro_path),"tmp/pro/%d_%d",pro_info->proid,pro_info->cacheid); + snprintf(mg_info->res_path,sizeof(mg_info->res_path),"submit/%d/%d/result",(sub_info->subid / 1000) * 1000,sub_info->subid); + + snprintf(tpath,sizeof(tpath),"tmp/pro/%d_%d/setting",pro_info->proid,pro_info->cacheid); + if((set_file = fopen(tpath,"r")) == NULL){ + throw 0; + } + lchr = '\n'; + while((tchr = fgetc(set_file)) != EOF){ + if(lchr == '\n' && tchr == '='){ + while(fgetc(set_file) != '\n'); + break; + } + lchr = tchr; + } + + mg_sub_fn(mg_info,set_file); + + fclose(set_file); + }catch(...){ + manage_finish_result(sub_info->subid, + sub_info->uid, + sub_info->pro_info->proid, + JUDGE_ERR, + 0, + 0, + 0, + sub_info->rejudge_flag); + } +} +DLL_PUBLIC int center_manage_queuesubmit(int subid,int proid,int lang,char *set_data,size_t set_len){ + center_judge_submit(subid,proid,lang,set_data,set_len); + return 0; +} + +int center_manage_result(int subid,char *res_data){ + std::map<int,manage_submit_info*>::iterator sub_it; + manage_submit_info *sub_info; + center_jmod_info *jmod_info; + + char res_path[PATH_MAX + 1]; + judgm_manage_info *mg_info; + judgm_manage_result_fn mg_res_fn; + + if((sub_it = manage_submap.find(subid)) == manage_submap.end()){ + return -1; + } + sub_info = sub_it->second; + jmod_info = sub_info->jmod_info; + mg_info = sub_info->manage_info; + + mg_res_fn = (judgm_manage_result_fn)jmod_info->manage_res_fn; + if(mg_res_fn(mg_info,res_data)){ + manage_submap.erase(sub_it); + + manage_finish_result(subid, + sub_info->uid, + sub_info->pro_info->proid, + mg_info->result, + mg_info->score, + mg_info->runtime, + mg_info->memory, + sub_info->rejudge_flag); + + center_manage_putpro(sub_info->pro_info); + delete sub_info; + }else{ + return -1; + } + + return 0; +} +static int manage_finish_result(int subid,int uid,int proid,int result,double score,int runtime,int memory,bool rejudge_flag){ + PGconn *db_conn; + PGresult *db_res; + char db_result[32]; + char db_score[32]; + char db_runtime[32]; + char db_memory[32]; + char db_subid[32]; + char *db_param[5]; + + if((db_conn = center_manage_conndb()) == NULL){ + return -1; + } + + snprintf(db_result,sizeof(db_result),"%d",result); + snprintf(db_score,sizeof(db_score),"%lf",score); + snprintf(db_runtime,sizeof(db_runtime),"%lu",runtime); + snprintf(db_memory,sizeof(db_memory),"%lu",memory / 1024UL); + snprintf(db_subid,sizeof(db_subid),"%d",subid); + db_param[0] = db_result; + db_param[1] = db_score; + db_param[2] = db_runtime; + db_param[3] = db_memory; + db_param[4] = db_subid; + db_res = PQexecParams(db_conn, + "UPDATE \"submit\" SET \"result\"=$1,\"score\"=$2,\"runtime\"=$3,\"memory\"=$4 WHERE \"subid\"=$5;", + 5, + NULL, + db_param, + NULL, + NULL, + 0); + PQclear(db_res); + center_manage_closedb(db_conn); + + manage_notice(subid, + uid, + proid, + result, + score, + runtime, + memory, + rejudge_flag); + + return 0; +} +static int manage_notice(int subid,int uid,int proid,int result,double score,int runtime,int memory,bool rejudge_flag){ + char msg[4096]; + json_object *jso_msg; + json_object *jso_arg; + + jso_msg = json_object_new_object(); + json_object_object_add(jso_msg,"type",json_object_new_string("result")); + json_object_object_add(jso_msg,"subid",json_object_new_int(subid)); + json_object_object_add(jso_msg,"proid",json_object_new_int(proid)); + json_object_object_add(jso_msg,"result",json_object_new_int(result)); + json_object_object_add(jso_msg,"score",json_object_new_double(score)); + json_object_object_add(jso_msg,"runtime",json_object_new_int(runtime)); + json_object_object_add(jso_msg,"memory",json_object_new_int(memory / 1024UL)); + json_object_object_add(jso_msg,"rejudge_flag",json_object_new_boolean(rejudge_flag)); + + jso_arg = json_object_new_array(); + json_object_array_add(jso_arg,json_object_new_int(uid)); + json_object_array_add(jso_arg,jso_msg); + + event_exec("pzreadtest.php","center_result_event",json_object_get_string(jso_arg)); + json_object_put(jso_arg); + + return 0; +} + + +center_pro_info* center_manage_getprobyid(int proid){ + std::map<int,center_pro_info*>::iterator pro_it; + center_pro_info *pro_info; + + if((pro_it = center_manage_promap.find(proid)) == center_manage_promap.end()){ + return NULL; + } + pro_info = pro_it->second; + + if(center_manage_getpro(pro_info)){ + return NULL; + } + + return pro_info; +} +int center_manage_getpro(center_pro_info *pro_info){ + pro_info->ref_count++; + return 0; +} +int center_manage_putpro(center_pro_info *pro_info){ + char tpath[PATH_MAX + 1]; + + pro_info->ref_count--; + if(pro_info->ref_count == 0){ + snprintf(tpath,sizeof(tpath),"tmp/pro/%d_%d",pro_info->proid,pro_info->cacheid); + tool_cleardir(tpath); + rmdir(tpath); + + snprintf(tpath,sizeof(tpath),"tmp/propack/%d_%d.tar.bz2",pro_info->proid,pro_info->cacheid); + unlink(tpath); + + delete pro_info; + } + return 0; +} +static int manage_updatepro(int proid,int cacheid,center_jmod_info *jmod_info,int lang_flag){ + std::map<int,center_pro_info*>::iterator pro_it; + center_pro_info *old_pro_info; + center_pro_info *update_pro_info; + + char tpath[PATH_MAX + 1]; + struct stat st; + std::pair<std::map<int,center_pro_info*>::iterator,bool> ins_ret; + + if((pro_it = center_manage_promap.find(proid)) == center_manage_promap.end()){ + old_pro_info = NULL; + }else{ + old_pro_info = pro_it->second; + + if(old_pro_info->state == CENTER_CACHESTATE_READY && cacheid == old_pro_info->cacheid){ + return 1; + } + if(old_pro_info->state == CENTER_CACHESTATE_UPDATE && (cacheid <= old_pro_info->cacheid || cacheid <= old_pro_info->update_cacheid)){ + return -1; + } + + old_pro_info->state = CENTER_CACHESTATE_UPDATE; + old_pro_info->update_cacheid = cacheid; + } + + update_pro_info = new center_pro_info(proid,cacheid,jmod_info,lang_flag); //set cacheid 0 to new pro + center_manage_getpro(update_pro_info); + + snprintf(tpath,sizeof(tpath),"tmp/pro/%d_%d",update_pro_info->proid,update_pro_info->cacheid); + if(!stat(tpath,&st)){ + snprintf(tpath,sizeof(tpath),"tmp/propack/%d_%d.tar.bz2",update_pro_info->proid,update_pro_info->cacheid); + if(!stat(tpath,&st)){ + + if(old_pro_info != NULL){ + center_manage_putpro(old_pro_info); + } + + ins_ret = center_manage_promap.insert(std::make_pair(update_pro_info->proid,update_pro_info)); + if(ins_ret.second == false){ + ins_ret.first->second = update_pro_info; + } + + return 1; + } + } + + manage_tp->add(manage_updatepro_thfn,update_pro_info,manage_updatepro_cbfn,update_pro_info); + + return 0; +} +static void manage_updatepro_th(void *data){ + center_pro_info *pro_info; + char src_path[PATH_MAX + 1]; + char dir_path[PATH_MAX + 1]; + char pack_path[PATH_MAX + 1]; + + pro_info = (center_pro_info*)data; + + snprintf(src_path,sizeof(src_path),"pro/%d",pro_info->proid); + snprintf(dir_path,sizeof(dir_path),"tmp/pro/%d_%d",pro_info->proid,pro_info->cacheid); + tool_copydir(src_path,dir_path); + + snprintf(pack_path,sizeof(pack_path),"tmp/propack/%d_%d.tar.bz2",pro_info->proid,pro_info->cacheid); + tool_pack(pack_path,dir_path); +} +static void manage_updatepro_cb(void *data){ + center_pro_info *old_pro_info; + center_pro_info *update_pro_info; + std::pair<std::map<int,center_pro_info*>::iterator,bool> ins_ret; + std::vector<std::pair<int,int> > pro_pair; + + update_pro_info = (center_pro_info*)data; + + ins_ret = center_manage_promap.insert(std::make_pair(update_pro_info->proid,update_pro_info)); + if(ins_ret.second == false){ + old_pro_info = ins_ret.first->second; + + if(update_pro_info->cacheid <= old_pro_info->cacheid){ + center_manage_putpro(update_pro_info); + return; + } + + center_manage_putpro(ins_ret.first->second); + ins_ret.first->second = update_pro_info; + } + + pro_pair.push_back(std::make_pair(update_pro_info->proid,update_pro_info->cacheid)); + center_judge_updatepro(pro_pair); +} + +center_jmod_info* center_manage_getjmodbyname(char *name){ + std::map<std::string,center_jmod_info*>::iterator jmod_it; + center_jmod_info *jmod_info; + + if((jmod_it = center_manage_jmodmap.find(name)) == center_manage_jmodmap.end()){ + return NULL; + } + jmod_info = jmod_it->second; + + if(center_manage_getjmod(jmod_info)){ + return NULL; + } + + return jmod_info; +} +int center_manage_getjmod(center_jmod_info *jmod_info){ + jmod_info->ref_count++; + return 0; +} +int center_manage_putjmod(center_jmod_info *jmod_info){ + char tpath[PATH_MAX + 1]; + + jmod_info->ref_count--; + if(jmod_info->ref_count == 0){ + snprintf(tpath,sizeof(tpath),"tmp/jmod/%s_%d",jmod_info->name,jmod_info->cacheid); + tool_cleardir(tpath); + rmdir(tpath); + + snprintf(tpath,sizeof(tpath),"tmp/jmodpack/%s_%d.tar.bz2",jmod_info->name,jmod_info->cacheid); + unlink(tpath); + + delete jmod_info; + } + return 0; +} +static int manage_updatejmod(char *name,int cacheid){ + std::map<std::string,center_jmod_info*>::iterator jmod_it; + center_jmod_info *old_jmod_info; + center_jmod_info *update_jmod_info; + + char tpath[PATH_MAX + 1]; + struct stat st; + std::pair<std::map<std::string,center_jmod_info*>::iterator,bool> ins_ret; + + if((jmod_it = center_manage_jmodmap.find(name)) == center_manage_jmodmap.end()){ + old_jmod_info = NULL; + }else{ + old_jmod_info = jmod_it->second; + + if(old_jmod_info->state == CENTER_CACHESTATE_READY && cacheid == old_jmod_info->cacheid){ + return -1; + } + if(old_jmod_info->state == CENTER_CACHESTATE_UPDATE && (cacheid <= old_jmod_info->cacheid || cacheid <= old_jmod_info->update_cacheid)){ + return -1; + } + + old_jmod_info->state = CENTER_CACHESTATE_UPDATE; + old_jmod_info->update_cacheid = cacheid; + } + + update_jmod_info = new center_jmod_info(name,cacheid); + center_manage_getjmod(update_jmod_info); + + snprintf(tpath,sizeof(tpath),"tmp/jmod/%s_%d",update_jmod_info->name,update_jmod_info->cacheid); + if(!stat(tpath,&st)){ + snprintf(tpath,sizeof(tpath),"tmp/jmodpack/%s_%d.tar.bz2",update_jmod_info->name,update_jmod_info->cacheid); + if(!stat(tpath,&st)){ + + if(old_jmod_info != NULL){ + center_manage_putjmod(old_jmod_info); + + ins_ret = center_manage_jmodmap.insert(std::make_pair(update_jmod_info->name,update_jmod_info)); + if(ins_ret.second == false){ + ins_ret.first->second = update_jmod_info; + } + + return 1; + } + } + } + + manage_tp->add(manage_updatejmod_thfn,update_jmod_info,manage_updatejmod_cbfn,update_jmod_info); + + return 0; +} +static void manage_updatejmod_th(void *data){ + center_jmod_info *jmod_info; + char src_path[PATH_MAX + 1]; + char dir_path[PATH_MAX + 1]; + char pack_path[PATH_MAX + 1]; + + jmod_info = (center_jmod_info*)data; + + snprintf(src_path,sizeof(src_path),"jmod/%s",jmod_info->name); + snprintf(dir_path,sizeof(dir_path),"tmp/jmod/%s_%d.tar.bz2",jmod_info->name,jmod_info->cacheid); + tool_copydir(src_path,dir_path); + + snprintf(pack_path,sizeof(pack_path),"tmp/jmodpack/%s_%d.tar.bz2",jmod_info->name,jmod_info->cacheid); + tool_pack(pack_path,dir_path); +} +static void manage_updatejmod_cb(void *data){ + center_jmod_info *old_jmod_info; + center_jmod_info *update_jmod_info; + std::pair<std::map<std::string,center_jmod_info*>::iterator,bool> ins_ret; + std::vector<std::pair<std::string,int> > jmod_pair; + + update_jmod_info = (center_jmod_info*)data; + + ins_ret = center_manage_jmodmap.insert(std::make_pair(update_jmod_info->name,update_jmod_info)); + if(ins_ret.second == false){ + old_jmod_info = ins_ret.first->second; + + if(update_jmod_info->cacheid <= old_jmod_info->cacheid){ + center_manage_putjmod(update_jmod_info); + } + + center_manage_putjmod(old_jmod_info); + ins_ret.first->second = update_jmod_info; + } + + jmod_pair.push_back(std::make_pair(update_jmod_info->name,update_jmod_info->cacheid)); + //wait + + // +} diff --git a/judge/center_manage.h b/judge/center_manage.h new file mode 100644 index 0000000..b2ee36e --- /dev/null +++ b/judge/center_manage.h @@ -0,0 +1,75 @@ +class manage_submit_info{ +public: + int subid; + int uid; + center_jmod_info *jmod_info; + center_pro_info *pro_info; + int lang; + bool rejudge_flag; + char param[JUDGE_SUB_PARAMMAX]; + judgm_manage_info *manage_info; + + manage_submit_info(int subid,int uid,center_jmod_info *jmod_info,center_pro_info *pro_info,int lang,bool rejudge_flag,char *param){ + this->subid = subid; + this->uid = uid; + this->jmod_info = jmod_info; + this->pro_info = pro_info; + this->lang = lang; + this->rejudge_flag = rejudge_flag; + this->param[0] = '\0'; + strncat(this->param,param,sizeof(this->param)); + + this->manage_info = new judgm_manage_info(this->subid,this->uid,pro_info->proid,this->lang,this->param); + } + ~manage_submit_info(){ + delete this->manage_info; + } +}; + +static void manage_submit_th(void *data); +static void manage_submit_cb(void *data); +static int manage_finish_result(int subid,int uid,int proid,int result,double score,int runtime,int memory,bool rejudge_flag); +static int manage_notice(int subid,int uid,int proid,int result,double score,int runtime,int memory,bool rejudge_flag); + +static int manage_updatepro(int proid,int cacheid,center_jmod_info *jmod_info,int lang_flag); +static void manage_updatepro_th(void *data); +static void manage_updatepro_cb(void *data); +static int manage_updatejmod(char *name,int cacheid); +static void manage_updatejmod_th(void *data); +static void manage_updatejmod_cb(void *data); + +static tpool *manage_tp; +static tpool_static_fn *manage_updatepro_thfn; +static tpool_static_fn *manage_updatepro_cbfn; +static tpool_static_fn *manage_updatejmod_thfn; +static tpool_static_fn *manage_updatejmod_cbfn; +static tpool_static_fn *manage_submit_thfn; +static tpool_static_fn *manage_submit_cbfn; +static std::map<int,manage_submit_info*> manage_submap; + +int center_manage_init(tpool **tpinfo); +PGconn* center_manage_conndb(); +int center_manage_closedb(PGconn *conn); +int center_manage_updatedata(); +int center_manage_submitwait(); +int center_manage_submit(int subid,char *param); +int center_manage_result(int subid,char *res_data); +DLL_PUBLIC int center_manage_queuesubmit(int subid,int proid,int lang,char *set_data,size_t set_len); + +center_pro_info* center_manage_getprobyid(int proid); +int center_manage_getpro(center_pro_info*); +int center_manage_putpro(center_pro_info *pro_info); +center_jmod_info* center_manage_getjmodbyname(char *name); +int center_manage_getjmod(center_jmod_info *jmod_info); +int center_manage_putjmod(center_jmod_info *jmod_info); + +std::map<int,center_pro_info*> center_manage_promap; +std::map<std::string,center_jmod_info*> center_manage_jmodmap; + +extern int tool_pack(char *pack_path,char *dir_path); +extern int tool_unpack(char *pack_path,char *dir_path); +extern int tool_cleardir(char *path); +extern int tool_copydir(char *old_path,char *new_path); + +extern int center_judge_submit(int subid,int proid,int lang,char *set_data,size_t set_len); +extern int center_judge_updatepro(std::vector<std::pair<int,int> > &pro_list); diff --git a/judge/center_server.cpp b/judge/center_server.cpp new file mode 100644 index 0000000..030e273 --- /dev/null +++ b/judge/center_server.cpp @@ -0,0 +1,198 @@ +#include<stdio.h> +#include<stdlib.h> +#include<string.h> +#include<unistd.h> +#include<signal.h> +#include<limits.h> +#include<errno.h> +#include<fcntl.h> +#include<pthread.h> +#include<semaphore.h> +#include<libpq-fe.h> +#include<sys/socket.h> +#include<sys/epoll.h> +#include<sys/eventfd.h> +#include<netinet/in.h> +#include<arpa/inet.h> +#include<libpq-fe.h> +#include<vector> +#include<queue> + +#include"tpool.h" +#include"center_server.h" + +server_epevdata::server_epevdata(int fd,int type,void *data){ + this->fd = fd; + this->type = type; + this->data = data; +} + + +server_web_conn::server_web_conn(int fd){ + this->fd = fd; + this->off = 0; + this->count = 0; +} +server_web_conn::~server_web_conn(){ + epoll_ctl(server_epfd,EPOLL_CTL_DEL,fd,NULL); + close(fd); +} +int server_web_conn::readio(){ + int ret; + char c; + int len; + int subid; + char *param; + + while((ret = read(fd,&c,1)) > 0){ + buf[off] = c; + off++; + if(c == '\0'){ + count++; + if(count == 2){ + break; + } + } + } + + if(count == 2){ + off = 0; + count = 0; + + sscanf(buf,"%d",&subid); + param = buf + strlen(buf) + 1; + printf("%d %s\n",subid,param); + + //test + if(subid == -1){ + center_manage_updatedata(); + }else{ + center_manage_submit(subid,param); + } + + //test + + write(fd,"S",2); + } + + return 0; +} + + +static int server_addepev(int fd,unsigned int flag,int type,void *data){ + server_epevdata *epevdata; + epoll_event epev; + + epevdata = new server_epevdata(fd,type,data); + epev.events = flag; + epev.data.ptr = epevdata; + epoll_ctl(server_epfd,EPOLL_CTL_ADD,fd,&epev); + + return 0; +} +static int server_delepev(server_epevdata *epevdata){ + epoll_ctl(server_epfd,EPOLL_CTL_DEL,epevdata->fd,NULL); + delete epevdata; + return 0; +} +int main(){ + int ret; + int i; + + int judge_sfd; + int web_sfd; + int cfd; + sockaddr_in saddr; + sockaddr_in caddr; + epoll_event epev; + epoll_event epevs[SERVER_EPOLL_MAXEVENT]; + int nevs; + + unsigned int ev_flag; + server_epevdata *epevdata; + server_web_conn *winfo; + tpool *tpinfo; + + signal(SIGPIPE,SIG_IGN); + server_epfd = epoll_create1(0); + center_manage_init(&tpinfo); + server_addepev(tpinfo->fd,EPOLLIN | EPOLLET,SERVER_EPEV_TPOOL,tpinfo); + center_judge_init(); + + judge_sfd = socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,6); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(SERVER_JUDGE_PORT); + //saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + //saddr.sin_addr.s_addr = htonl(INADDR_ANY); + saddr.sin_addr.s_addr = inet_addr("10.8.0.2"); + setsockopt(judge_sfd,SOL_SOCKET,SO_REUSEADDR,&saddr,sizeof(saddr)); + bind(judge_sfd,(sockaddr*)&saddr,sizeof(saddr)); + + server_addepev(judge_sfd,EPOLLIN | EPOLLET,SERVER_EPEV_JUDGESERVER,NULL); + listen(judge_sfd,4096); + + web_sfd = socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,6); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(SERVER_WEB_PORT); + saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + //saddr.sin_addr.s_addr = htonl(INADDR_ANY); + setsockopt(web_sfd,SOL_SOCKET,SO_REUSEADDR,&saddr,sizeof(saddr)); + bind(web_sfd,(sockaddr*)&saddr,sizeof(saddr)); + + server_addepev(web_sfd,EPOLLIN | EPOLLET,SERVER_EPEV_WEBSERVER,NULL); + listen(web_sfd,4096); + + while(true){ + nevs = epoll_wait(server_epfd,epevs,SERVER_EPOLL_MAXEVENT,-1); + for(i = 0;i < nevs;i++){ + ev_flag = epevs[i].events; + epevdata = (server_epevdata*)epevs[i].data.ptr; + + if(epevdata->type == SERVER_EPEV_JUDGESERVER){ + while(true){ + ret = 0; + if((cfd = accept4(epevdata->fd,(sockaddr*)&caddr,(socklen_t*)&ret,SOCK_NONBLOCK)) == -1){ + break; + } + + server_addepev(cfd,EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET,SERVER_EPEV_JUDGECLIENT,center_judge_addconn(cfd)); + } + }else if(epevdata->type == SERVER_EPEV_JUDGECLIENT){ + center_judge_dispatch(ev_flag,epevdata->data); + if(ev_flag & EPOLLRDHUP){ + server_delepev(epevdata); + } + }else if(epevdata->type == SERVER_EPEV_WEBSERVER){ + printf("test\n"); + while(true){ + ret = 0; + if((cfd = accept4(epevdata->fd,(sockaddr*)&caddr,(socklen_t*)&ret,SOCK_NONBLOCK)) == -1){ + break; + } + + server_addepev(cfd,EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET,SERVER_EPEV_WEBCLIENT,new server_web_conn(cfd)); + } + }else if(epevdata->type == SERVER_EPEV_WEBCLIENT){ + winfo = (server_web_conn*)epevdata->data; + if(ev_flag & EPOLLIN){ + winfo->readio(); + } + if(ev_flag & EPOLLRDHUP){ + delete winfo; + delete (server_epevdata*)epev.data.ptr; + } + }else if(epevdata->type == SERVER_EPEV_TPOOL){ + tpinfo = (tpool*)epevdata->data; + if(ev_flag & EPOLLIN){ + tpinfo->done(); + } + } + } + } + + close(judge_sfd); + close(server_epfd); + close(web_sfd); + + return 0; +} diff --git a/judge/center_server.h b/judge/center_server.h new file mode 100644 index 0000000..039e84b --- /dev/null +++ b/judge/center_server.h @@ -0,0 +1,45 @@ +#define SERVER_JUDGE_PORT 2573 +#define SERVER_WEB_PORT 2501 +#define SERVER_EPOLL_MAXEVENT 4096 + +#define SERVER_EPEV_JUDGESERVER 0 +#define SERVER_EPEV_JUDGECLIENT 1 +#define SERVER_EPEV_WEBSERVER 2 +#define SERVER_EPEV_WEBCLIENT 3 +#define SERVER_EPEV_TPOOL 4 +class server_epevdata{ +public: + int fd; + int type; + void *data; + + server_epevdata(int fd,int type,void *data); +}; + +class server_web_conn{ +private: + int fd; + char buf[65536]; + int off; + int count; + +public: + server_web_conn(int fd); + ~server_web_conn(); + int readio(); +}; + +static int server_addepev(int fd,unsigned int flag,int type,void *data); +static int server_delepev(server_epevdata *epevdata); +static int server_epfd; + +extern int center_manage_init(tpool **tpinfo); +extern int center_manage_updatedata(); +extern int center_manage_submit(int subid,char *param); + +extern int center_judge_init(); +extern void* center_judge_addconn(int fd); +extern int center_judge_dispatch(int ev_flag,void *data); + +extern int pack_pack(char *pack_path,char *dir_path); +extern int pack_unpack(char *pack_path,char *target_path); diff --git a/judge/event_exec.cpp b/judge/event_exec.cpp new file mode 100644 index 0000000..af258c0 --- /dev/null +++ b/judge/event_exec.cpp @@ -0,0 +1,89 @@ +#include "event_exec.h" + +#define EVENT_BUFLEN 1005 +#define EVENT_URL "http://localhost/toj/php/event.php" + +struct event_handle +{ + int init, plen, blen; + char *post, *buf; + pthread_mutex_t mutex; + CURL *handle; +}; + +static struct event_handle conn; + +size_t event_write_cb(void *in, size_t siz, size_t nb, void *buf) +{ + int len; + len = siz*nb+1; + if(len > conn.blen) + { + len = conn.blen-1; + } + memcpy(buf, in, len); + ((char*)buf)[len] = 0; + return siz*nb; +} + +int event_init() +{ + if(conn.init) + { + return 0; + } + conn.plen = conn.blen = EVENT_BUFLEN; + conn.post = (char*)malloc(EVENT_BUFLEN); + conn.buf = (char*)malloc(EVENT_BUFLEN); + curl_global_init(CURL_GLOBAL_ALL); + conn.handle = curl_easy_init(); + curl_easy_setopt(conn.handle, CURLOPT_URL, EVENT_URL); + curl_easy_setopt(conn.handle, CURLOPT_WRITEFUNCTION, event_write_cb); + curl_easy_setopt(conn.handle, CURLOPT_WRITEDATA, conn.buf); + pthread_mutex_init(&conn.mutex, NULL); + conn.init = 1; + return 1; +} + +int event_exec(const char *fname, const char *name, const char *arg) +{ + int res, len; + char *t; + event_init(); + if(pthread_mutex_lock(&conn.mutex) == 0) + { + len = 0; + len += strlen(fname)+6; + len += strlen(name)+6; + len += strlen(arg)+6; + if(len > conn.plen) + { + t = (char*)malloc(len); + if(!t) + { + pthread_mutex_unlock(&conn.mutex); + return 0; + } + free(conn.post); + conn.post = t; + conn.plen = len; + } + sprintf(conn.post, "fname=%s&name=%s&arg=%s", fname, name, arg); + curl_easy_setopt(conn.handle, CURLOPT_POSTFIELDS, conn.post); + res = curl_easy_perform(conn.handle); + if(res) + { + pthread_mutex_unlock(&conn.mutex); + return 0; + } + fprintf(stderr, "%s\n", conn.buf); + if(!strcmp(conn.buf, "true")) + { + pthread_mutex_unlock(&conn.mutex); + return 1; + } + + pthread_mutex_unlock(&conn.mutex); + } + return 0; +} diff --git a/judge/event_exec.h b/judge/event_exec.h new file mode 100644 index 0000000..aec1acb --- /dev/null +++ b/judge/event_exec.h @@ -0,0 +1,12 @@ +#ifndef EVENT_EXEC +#define EVENT_EXEC + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <curl/curl.h> +#include <pthread.h> + +int event_exec(const char *fname, const char *name, const char *arg); + +#endif diff --git a/judge/jmod_test.h b/judge/jmod_test.h new file mode 100644 index 0000000..844f5c8 --- /dev/null +++ b/judge/jmod_test.h @@ -0,0 +1,17 @@ +#define LINE_ERRMSG_MAXSIZE 4096 + +typedef int (*check_init_fn)(int judgk_modfd,char *data_path,char *run_path); +typedef int (*check_run_fn)(int &status,char *err_msg); +typedef int (*check_stop_fn)(); + +struct line_set_data{ + int id; +}; +struct line_result_data{ + int id; + int status; + double score; + unsigned long runtime; + unsigned long memory; + char err_msg[LINE_ERRMSG_MAXSIZE]; +}; diff --git a/judge/jmod_test_check.cpp b/judge/jmod_test_check.cpp new file mode 100644 index 0000000..984473b --- /dev/null +++ b/judge/jmod_test_check.cpp @@ -0,0 +1,109 @@ +#include<stdio.h> +#include<stdlib.h> +#include<string.h> +#include<limits.h> +#include<unistd.h> +#include<fcntl.h> +#include<errno.h> + +#include<judge_def.h> +#include"judgm_lib.h" +#include"jmod_test.h" +#include"jmod_test_check.h" + +static int ansfd; +static judgm_hyperio *hyperio; +static int tty_idx; + +int p[2]; + +DLL_PUBLIC int init(int judgk_modfd,char *datapath,char *runpath){ + char tpath[PATH_MAX + 1]; + char dstpath[PATH_MAX + 1]; + + pipe(p); + + snprintf(tpath,sizeof(tpath),"%s/in",datapath); + snprintf(dstpath,sizeof(dstpath),"%s/in",runpath); + if(link(tpath,dstpath)){ + return -1; + } + snprintf(tpath,sizeof(tpath),"%s/ans",datapath); + if((ansfd = open(tpath,O_RDONLY)) == -1){ + return -1; + } + + //hyperio = new judgm_hyperio(judgk_modfd); + //tty_idx = hyperio->tty_idx; + + return 0; +} +DLL_PUBLIC int run(int &status,char *err_msg){ + int ret; + + char *inbuf; + char *ansbuf; + + status = JUDGE_AC; + inbuf = new char[65536]; + ansbuf = new char[65536]; + + /*while((ret = read(ansfd,ansbuf,65536)) > 0){ + if(hyperio->compare(ansbuf,ret)){ + status = JUDGE_WA; + break; + } + } + if(status == JUDGE_AC && hyperio->wait() > 0){ + status = JUDGE_WA; + } + + delete inbuf; + delete ansbuf; + close(ansfd); + delete hyperio;*/ + + close(p[1]); + int c_read=-1,pre_status=status; + while((ret = read(p[0],inbuf,65536)) > 0){ + if((c_read=read(ansfd,ansbuf,ret)) != ret){ + status = JUDGE_WA; + break; + } + if(memcmp(ansbuf,inbuf,ret)){ + status = JUDGE_WA; + break; + } + } +// if(c_read - ret == 1 && ansbuf[c_read-1]=='\n'){ +// status = pre_status; +// } + + if(status == JUDGE_AC && ((c_read = read(ansfd,ansbuf,1)) > 1 || c_read == 1 && ansbuf[0]!='\n')){ + status = JUDGE_WA; + } + + return 0; +} +DLL_PUBLIC int proc(){ + int infd; + int outfd; + + if((infd = open("in",O_RDONLY)) == -1){ + return -1; + } + /*if((outfd = judgm_hyperio::get_ttyfd(tty_idx)) == -1){ + return -1; + }*/ + + close(p[0]); + outfd = p[1]; + dup2(infd,0); + dup2(outfd,1); + dup2(outfd,2); + + return 0; +} +DLL_PUBLIC int stop(){ + return 0; +} diff --git a/judge/jmod_test_check.h b/judge/jmod_test_check.h new file mode 100644 index 0000000..20a6286 --- /dev/null +++ b/judge/jmod_test_check.h @@ -0,0 +1,4 @@ +DLL_PUBLIC int init(int judgk_modfd,char *datapath,char *runpath); +DLL_PUBLIC int run(int &status,char *err_msg); +DLL_PUBLIC int proc(); +DLL_PUBLIC int stop(); diff --git a/judge/jmod_test_line.cpp b/judge/jmod_test_line.cpp new file mode 100644 index 0000000..33a32b9 --- /dev/null +++ b/judge/jmod_test_line.cpp @@ -0,0 +1,190 @@ +#include<stdio.h> +#include<stdlib.h> +#include<limits.h> +#include<dlfcn.h> +#include<pthread.h> +#include<json/json.h> + +#include<judge_def.h> +#include"judgm_lib.h" +#include"judgm_line.h" +#include"jmod_test.h" +#include"jmod_test_line.h" + +static int line_load_setfile(FILE *set_file,int id,int &timelimit,int &memlimit,double &score){ + int ret; + + json_object *jso; + char buf[JUDGE_SET_FILEMAX]; + + fread(buf,1,sizeof(buf),set_file); + jso = json_tokener_parse(buf); + + timelimit = json_object_get_int(json_object_object_get(jso,"timelimit")); + memlimit = json_object_get_int(json_object_object_get(jso,"memlimit")); + score = json_object_get_double(json_object_array_get_idx(json_object_object_get(jso,"score"),id - 1)); + + json_object_put(jso); + return 0; +} +static void line_sigaction(int sig_num,siginfo_t *sig_info,void *context){ + if(sig_info->si_pid == line_proc->pid && line_proc->status == JUDGE_RUN){ + if(!line_proc->proc_wait(false)){ + line_chk_stop_fn(); + } + } +} +static int line_sig_set(){ + struct sigaction sig; + + sig.sa_sigaction = line_sigaction; + sigemptyset(&sig.sa_mask); + sig.sa_flags = SA_SIGINFO | SA_RESTART; + if(sigaction(SIGCHLD,&sig,NULL)){ + return -1; + } + + return 0; +} +static int line_sig_restore(){ + struct sigaction sig; + + sig.sa_handler = SIG_DFL; + sigemptyset(&sig.sa_mask); + sig.sa_flags = 0; + if(sigaction(SIGCHLD,&sig,NULL)){ + return -1; + } + + return 0; +} +static int line_sig_block(){ + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask,SIGCHLD); + if(pthread_sigmask(SIG_BLOCK,&mask,NULL)){ + return -1; + } + + return 0; +} +static int line_sig_unblock(){ + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask,SIGCHLD); + if(pthread_sigmask(SIG_UNBLOCK,&mask,NULL)){ + return -1; + } + + return 0; +} +static int line_sig_wait(){ + sigset_t mask; + int num; + + sigfillset(&mask); + sigdelset(&mask,SIGKILL); + sigdelset(&mask,SIGTERM); + sigdelset(&mask,SIGINT); + sigdelset(&mask,SIGCHLD); + sigsuspend(&mask); + + return 0; +} +DLL_PUBLIC int run(judgm_line_info *info){ + int i; + + line_result_data *res_data; + + int set_timelimit; + int set_memlimit; + double set_score; + line_set_data *set_data; + + char main_path[PATH_MAX + 1]; + char exe_path[PATH_MAX + 1]; + + check_init_fn chk_init_fn; + check_run_fn chk_run_fn; + judgm_proc_check_fn chk_proc_fn; + + char data_path[PATH_MAX + 1]; + int chk_status; + + set_data = (line_set_data*)info->set_data; + + res_data = (line_result_data*)info->res_data; + info->res_len = sizeof(line_result_data); + + res_data->id = set_data->id; + res_data->status = JUDGE_ERR; + res_data->score = 0; + res_data->runtime = 0; + res_data->memory = 0; + res_data->err_msg[0] = '\0'; + + if(line_load_setfile(info->set_file,set_data->id,set_timelimit,set_memlimit,set_score)){ + return -1; + } + + snprintf(main_path,sizeof(main_path),"%s/main.cpp",info->code_path); + snprintf(exe_path,sizeof(exe_path),"%s/test",info->run_path); + if(judgm_compile(info->subid,main_path,exe_path,info->lang,false,res_data->err_msg,LINE_ERRMSG_MAXSIZE)){ + res_data->status = JUDGE_CE; + return -1; + } + + chk_init_fn = (check_init_fn)dlsym(info->check_dll,"init"); + chk_run_fn = (check_run_fn)dlsym(info->check_dll,"run"); + chk_proc_fn = (judgm_proc_check_fn)dlsym(info->check_dll,"proc"); + line_chk_stop_fn = (check_stop_fn)dlsym(info->check_dll,"stop"); + line_proc = new judgm_proc(info->judgk_modfd,info->run_path,exe_path,set_timelimit,(set_timelimit * 10 + 5000),set_memlimit,chk_proc_fn); + + snprintf(data_path,sizeof(data_path),"%s/private/%d",info->pro_path,set_data->id); + if(chk_init_fn(info->judgk_modfd,data_path,info->run_path)){ + delete line_proc; + return -1; + } + if(line_sig_set()){ + delete line_proc; + return -1; + } + + if(line_proc->proc_run()){ + delete line_proc; + return -1; + } + chk_run_fn(chk_status,res_data->err_msg); + + line_sig_block(); + if(line_proc->status == JUDGE_RUN){ + line_proc->proc_kill(); + line_sig_wait(); + } + line_sig_unblock(); + + printf("check status %d proc status %d\n",chk_status,line_proc->status); + + if(line_sig_restore()){ + delete line_proc; + return -1; + } + + if(line_proc->status != JUDGE_AC){ + res_data->status = line_proc->status; + }else{ + res_data->status = chk_status; + } + if(res_data->status == JUDGE_AC){ + res_data->score = set_score; + }else{ + res_data->score = 0; + } + res_data->runtime = line_proc->runtime; + res_data->memory = line_proc->memory; + + delete line_proc; + return 0; +} diff --git a/judge/jmod_test_line.h b/judge/jmod_test_line.h new file mode 100644 index 0000000..c09a503 --- /dev/null +++ b/judge/jmod_test_line.h @@ -0,0 +1,11 @@ +static int line_load_setfile(FILE *set_file,int test_id,int &timelimit,int &memlimit,double &score); +static int line_sig_set(); +static int line_sig_restore(); +static int line_sig_block(); +static int line_sig_unblock(); +static int line_sig_wait(); + +static judgm_proc *line_proc; +static check_stop_fn line_chk_stop_fn; + +DLL_PUBLIC int run(judgm_line_info *info); diff --git a/judge/jmod_test_manage.cpp b/judge/jmod_test_manage.cpp new file mode 100644 index 0000000..b020574 --- /dev/null +++ b/judge/jmod_test_manage.cpp @@ -0,0 +1,96 @@ +#include<stdio.h> +#include<stdlib.h> +#include<string.h> +#include<limits.h> +#include<dlfcn.h> +#include<json/json.h> + +#include<judge_def.h> +#include"judgm_lib.h" +#include"judgm_manage.h" +#include"jmod_test.h" +#include"jmod_test_manage.h" + +static void __attribute__ ((constructor)) manage_init(){ + manage_queuesubmit_fn = (judgm_manage_queuesubmit_fn)dlsym(dlopen(NULL,RTLD_NOW),"center_manage_queuesubmit"); +} +static int manage_load_setfile(FILE *set_file,int &count){ + int ret; + + json_object *jso; + char buf[JUDGE_SET_FILEMAX]; + + fread(buf,1,sizeof(buf),set_file); + jso = json_tokener_parse(buf); + + count = json_object_get_int(json_object_object_get(jso,"count")); + + json_object_put(jso); + return 0; +} + +DLL_PUBLIC int submit(judgm_manage_info *info,FILE *set_file){ + int i; + + int count; + manage_result_info *res_info; + line_set_data set_data; + + manage_load_setfile(set_file,count); + + res_info = new manage_result_info(count); + info->private_data = res_info; + + for(i = 0;i < count;i++){ + set_data.id = i + 1; + manage_queuesubmit_fn(info->subid,info->proid,info->lang,(char*)&set_data,sizeof(line_set_data)); + } + + return 0; +} +DLL_PUBLIC int result(judgm_manage_info *info,line_result_data *res_data){ + manage_result_info *res_info; + json_object *jso_item; + char tpath[PATH_MAX + 1]; + + res_info = (manage_result_info*)info->private_data; + res_info->count++; + + if(res_data->status > res_info->result){ + res_info->result = res_data->status; + } + res_info->totalscore += res_data->score; + res_info->totalruntime += res_data->runtime; + if(res_data->memory > res_info->maxmemory){ + res_info->maxmemory = res_data->memory; + } + + jso_item = json_object_new_object(); + json_object_object_add(jso_item,"status",json_object_new_int(res_data->status)); + json_object_object_add(jso_item,"score",json_object_new_double(res_data->score)); + json_object_object_add(jso_item,"runtime",json_object_new_int64(res_data->runtime)); + json_object_object_add(jso_item,"memory",json_object_new_int64(res_data->memory / 1024UL)); + if(strlen(res_data->err_msg) > 0){ + printf(" strlen %d\n",strlen(res_data->err_msg)); + json_object_object_add(jso_item,"errmsg",json_object_new_string(res_data->err_msg)); + } + json_object_array_put_idx(res_info->jso_resarray,res_data->id - 1,jso_item); + + printf("jmod count %d %d\n",res_info->count,res_info->allcount); + + if(res_info->count == res_info->allcount){ + snprintf(tpath,sizeof(tpath),"%s/result",info->res_path); + json_object_to_file_ext(tpath,res_info->jso_res,JSON_C_TO_STRING_PLAIN); + + info->result = res_info->result; + info->score = res_info->totalscore; + info->runtime = res_info->totalruntime; + info->memory = res_info->maxmemory; + + delete res_info; + return 1; + } + return 0; +} + + diff --git a/judge/jmod_test_manage.h b/judge/jmod_test_manage.h new file mode 100644 index 0000000..b0244e3 --- /dev/null +++ b/judge/jmod_test_manage.h @@ -0,0 +1,35 @@ +class manage_result_info{ +public: + int allcount; + int count; + int result; + double totalscore; + unsigned long totalruntime; + unsigned long maxmemory; + json_object *jso_res; + json_object *jso_resarray; + + manage_result_info(int allcount){ + this->allcount = allcount; + this->count = 0; + this->result = JUDGE_AC; + this->totalscore = 0; + this->totalruntime = 0; + this->maxmemory = 0; + + this->jso_res = json_object_new_object(); + this->jso_resarray = json_object_new_array(); + json_object_object_add(this->jso_res,"result",this->jso_resarray); + } + ~manage_result_info(){ + json_object_put(jso_res); + } +}; + +DLL_PUBLIC int submit(judgm_manage_info *info,FILE *set_file); +DLL_PUBLIC int result(judgm_manage_info *info,line_result_data *res_data); + +static void __attribute__ ((constructor)) manage_init(); +static int manage_load_setfile(FILE *setfile,int &count); + +static judgm_manage_queuesubmit_fn manage_queuesubmit_fn; diff --git a/judge/judge.h b/judge/judge.h new file mode 100644 index 0000000..5183942 --- /dev/null +++ b/judge/judge.h @@ -0,0 +1,44 @@ +#ifndef JUDGE_H +#define JUDGE_H + +#define JUDGE_THREAD_MAX 16 +#define JUDGE_THREAD_JUDGEMAX 2 + +#define JUDGE_CACHESTATE_READY 0 +#define JUDGE_CACHESTATE_UPDATE 1 + +class judge_pro_info{ +public: + int proid; + int cacheid; + int ref_count; + + int state; + int update_cacheid; + + judge_pro_info(int proid,int cacheid){ + this->proid = proid; + this->cacheid = cacheid; + this->ref_count = 0; + + this->state = JUDGE_CACHESTATE_READY; + this->update_cacheid = 0; + } +}; + +class judge_submit_info{ +public: + int subid; + judge_pro_info *pro_info; + int lang; + char *set_data; + + judge_submit_info(int subid,judge_pro_info *pro_info,int lang,char *set_data){ + this->subid = subid; + this->pro_info = pro_info; + this->lang = lang; + this->set_data = set_data; + } +}; + +#endif diff --git a/judge/judge_manage.cpp b/judge/judge_manage.cpp new file mode 100644 index 0000000..32181bc --- /dev/null +++ b/judge/judge_manage.cpp @@ -0,0 +1,371 @@ +#include<stdio.h> +#include<stdlib.h> +#include<string.h> +#include<unistd.h> +#include<limits.h> +#include<dirent.h> +#include<dlfcn.h> +#include<sys/types.h> +#include<sys/stat.h> +#include<sys/mman.h> +#include<map> + +#include"tpool.h" +#include"judge_def.h" +#include"judge.h" +#include"judgm_line.h" +#include"judgm_lib.h" +#include"judge_manage.h" + +int judge_manage_init(){ + int i; + + manage_tp = new tpool(JUDGE_THREAD_MAX); + judge_server_addtpool(manage_tp); + manage_tp->start(); + + manage_judgk_modfd = open("/dev/judgk",O_RDWR); + for(i = 0;i < JUDGE_THREAD_JUDGEMAX;i++){ + manage_judgepool[i] = new manage_judgeth_info(i); + } + manage_updatepro_thfn = new tpool_static_fn(manage_updatepro_th); + manage_updatepro_cbfn = new tpool_static_fn(manage_updatepro_cb); + manage_unpackcode_thfn = new tpool_static_fn(manage_unpackcode_th); + manage_unpackcode_cbfn = new tpool_static_fn(manage_unpackcode_cb); + manage_judge_thfn = new tpool_static_fn(manage_judge_th); + manage_judge_cbfn = new tpool_static_fn(manage_judge_cb); + + judge_manage_updatedata(); + return 0; +} +int judge_manage_updatedata(){ + DIR *dirp; + char *buf; + dirent *entry; + int proid; + int cacheid; + judge_pro_info *pro_info; + + if((dirp = opendir("tmp/pro")) == NULL){ + return -1; + } + buf = new char[sizeof(dirent) + NAME_MAX + 1]; + + while(true){ + readdir_r(dirp,(dirent*)buf,&entry); + if(entry == NULL){ + break; + } + if(strcmp(entry->d_name,".") == 0 || strcmp(entry->d_name,"..") == 0){ + continue; + } + + if(entry->d_type == DT_DIR){ + sscanf(entry->d_name,"%d_%d",&proid,&cacheid); + pro_info = new judge_pro_info(proid,cacheid); + judge_manage_getpro(pro_info); + judge_manage_promap.insert(std::make_pair(proid,pro_info)); + } + } + + delete(buf); + closedir(dirp); + + return 0; +} + +judge_pro_info* judge_manage_getprobyid(int proid){ + std::map<int,judge_pro_info*>::iterator pro_it; + judge_pro_info *pro_info; + + if((pro_it = judge_manage_promap.find(proid)) == judge_manage_promap.end()){ + return NULL; + } + pro_info = pro_it->second; + + if(judge_manage_getpro(pro_info)){ + return NULL; + } + + return pro_info; +} +int judge_manage_getpro(judge_pro_info *pro_info){ + pro_info->ref_count++; + return 0; +} +int judge_manage_putpro(judge_pro_info *pro_info){ + std::map<int,judge_pro_info*> pro_it; + char tpath[PATH_MAX + 1]; + char src_path[PATH_MAX + 1]; + + pro_info->ref_count--; + if(pro_info->ref_count == 0){ + snprintf(tpath,sizeof(tpath),"tmp/pro/%d_%d",pro_info->proid,pro_info->cacheid); + tool_cleardir(tpath); + rmdir(tpath); + + delete pro_info; + } + return 0; +} +int judge_manage_updatepro(int proid,int cacheid,bool check_flag,judge_pro_info **update_pro_info){ //If check_flag = true, just check + int ret; + + std::map<int,judge_pro_info*>::iterator pro_it; + judge_pro_info *old_pro_info; + + if((pro_it = judge_manage_promap.find(proid)) == judge_manage_promap.end()){ + if(check_flag == true){ + return 0; + } + }else{ + old_pro_info = pro_it->second; + + if(old_pro_info->state == JUDGE_CACHESTATE_READY && cacheid == old_pro_info->cacheid){ + return 1; + } + if(old_pro_info->state == JUDGE_CACHESTATE_UPDATE && (cacheid <= old_pro_info->cacheid || cacheid <= old_pro_info->update_cacheid)){ + return -1; + } + + if(check_flag == true){ + return 0; + } + + old_pro_info->update_cacheid = cacheid; + old_pro_info->state = JUDGE_CACHESTATE_UPDATE; + } + + *update_pro_info = new judge_pro_info(proid,cacheid); + judge_manage_getpro(*update_pro_info); + + return 0; +} +int judge_manage_done_updatepro(judge_pro_info *pro_info){ + manage_tp->add(manage_updatepro_thfn,pro_info,manage_updatepro_cbfn,pro_info); + return 0; +} +static void manage_updatepro_th(void *data){ + judge_pro_info *pro_info; + int proid; + int cacheid; + char pack_path[PATH_MAX + 1]; + char dir_path[PATH_MAX + 1]; + char tpath[PATH_MAX + 1]; + FILE *f; + + pro_info = (judge_pro_info*)data; + + snprintf(pack_path,sizeof(pack_path),"tmp/propack/%d_%d.tar.bz2",pro_info->proid,pro_info->cacheid); + snprintf(dir_path,sizeof(dir_path),"tmp/pro/%d_%d",pro_info->proid,pro_info->cacheid); + mkdir(dir_path,0755); + tool_cleardir(dir_path); + tool_unpack(pack_path,dir_path); + //unlink(pack_path); + + snprintf(tpath,sizeof(tpath),"tmp/pro/%d_%d/cacheinfo",pro_info->proid,pro_info->cacheid); + f = fopen(tpath,"w"); + fprintf(f,"%d",pro_info->cacheid); + fclose(f); +} +static void manage_updatepro_cb(void *data){ + judge_pro_info *old_pro_info; + judge_pro_info *update_pro_info; + std::pair<std::map<int,judge_pro_info*>::iterator,bool> ins_ret; + std::vector<std::pair<int,int> > pro_list; + + update_pro_info = (judge_pro_info*)data; + + ins_ret = judge_manage_promap.insert(std::make_pair(update_pro_info->proid,update_pro_info)); + if(ins_ret.second == false){ + old_pro_info = ins_ret.first->second; + + if(update_pro_info->cacheid < old_pro_info->cacheid){ + judge_manage_putpro(update_pro_info); + return; + } + + judge_manage_putpro(ins_ret.first->second); + ins_ret.first->second = update_pro_info; + } + + pro_list.push_back(std::make_pair(update_pro_info->proid,update_pro_info->cacheid)); + judge_server_setpro(pro_list); +} + + +int judge_manage_submit(int subid,int proid,int lang,char *set_data,int set_len){ + judge_pro_info *pro_info; + judge_submit_info *sub_info; + + char tpath[PATH_MAX + 1]; + struct stat st; + + pro_info = judge_manage_getprobyid(proid); + sub_info = new judge_submit_info(subid,pro_info,lang,set_data,set_len); + + if(manage_submap.find(subid) == manage_submap.end()){ + snprintf(tpath,sizeof(tpath),"tmp/code/%d",subid); + if(!stat(tpath,&st)){ + manage_queuejudge(sub_info); + }else{ + judge_server_reqcode(subid); + manage_submap.insert(std::make_pair(subid,sub_info)); + } + }else{ + manage_submap.insert(std::make_pair(subid,sub_info)); + } + + return 0; +} +int judge_manage_done_code(int subid){ + manage_tp->add(manage_unpackcode_thfn,(void*)((long)subid),manage_unpackcode_cbfn,(void*)((long)subid)); + return 0; +} +static void manage_unpackcode_th(void *data){ + int subid; + char pack_path[PATH_MAX + 1]; + char dir_path[PATH_MAX + 1]; + char tpath[PATH_MAX + 1]; + FILE *f; + + subid = (int)((long)data); + + snprintf(pack_path,sizeof(pack_path),"tmp/codepack/%d.tar.bz2",subid); + snprintf(dir_path,sizeof(dir_path),"tmp/code/%d",subid); + mkdir(dir_path,0755); + tool_cleardir(dir_path); + tool_unpack(pack_path,dir_path); +} +static void manage_unpackcode_cb(void *data){ + int subid; + std::multimap<int,judge_submit_info*>::iterator sub_it; + judge_submit_info *sub_info; + + subid = (int)((long)data); + + while((sub_it = manage_submap.find(subid)) != manage_submap.end()){ + sub_info = sub_it->second; + manage_queuejudge(sub_info); + manage_submap.erase(sub_it); + } +} +static int manage_queuejudge(judge_submit_info *sub_info){ + int i; + + printf("queue judge %d %d\n",sub_info->subid,sub_info->pro_info->proid); + for(i = 0;i < 16;i++){ + if(manage_judgepool[i]->use_flag == false){ + manage_judgepool[i]->use_flag = true; + manage_judgepool[i]->sub_info = sub_info; + manage_tp->add(manage_judge_thfn,manage_judgepool[i],manage_judge_cbfn,manage_judgepool[i]); + break; + } + } + + return 0; +} +static void manage_judge_th(void *data){ + manage_judgeth_info *th_info; + judge_submit_info *sub_info; + judge_pro_info *pro_info; + char pro_path[PATH_MAX + 1]; + char code_path[PATH_MAX + 1]; + char *set_data; + + th_info = (manage_judgeth_info*)data; + sub_info = th_info->sub_info; + pro_info = sub_info->pro_info; + + snprintf(pro_path,sizeof(pro_path),"tmp/pro/%d_%d",pro_info->proid,pro_info->cacheid); + snprintf(code_path,sizeof(code_path),"tmp/code/%d",sub_info->subid); + manage_judge(sub_info->subid,pro_path,code_path,th_info->run_path,sub_info->lang,sub_info->set_data,th_info->res_data,th_info->res_len); +} +static void manage_judge_cb(void *data){ + manage_judgeth_info *th_info; + judge_submit_info *sub_info; + std::vector<std::pair<int,int> > pro_list; + + th_info = (manage_judgeth_info*)data; + sub_info = th_info->sub_info; + + judge_server_result(sub_info->subid,th_info->res_data,th_info->res_len); + judge_manage_putpro(sub_info->pro_info); + + th_info->use_flag = false; + th_info->sub_info = NULL; + delete sub_info; +} +static int manage_judge(int subid,char *pro_path,char *code_path,char *run_path,int lang,char *set_data,char *res_data,size_t &res_len){ + judgm_line_info *line_info; + int pid; + + char tpath[PATH_MAX + 1]; + FILE *set_file; + char cwd_path[PATH_MAX + 1]; + char jmod_name[NAME_MAX + 1]; + char line_path[PATH_MAX + 1]; + char check_name[NAME_MAX + 1]; + char check_path[PATH_MAX + 1]; + char lchr; + char tchr; + + void *line_dll; + void *check_dll; + judgm_line_run_fn run_fn; + + snprintf(tpath,sizeof(tpath),"%s/setting",pro_path); + set_file = fopen(tpath,"r"); + + getcwd(cwd_path,sizeof(cwd_path)); + fscanf(set_file,"%s",jmod_name); + snprintf(line_path,sizeof(line_path),"%s/tmp/jmod/%s/%s_line.so",cwd_path,jmod_name,jmod_name); + fscanf(set_file,"%s",check_name); + if(check_name[0] == '/'){ + snprintf(check_path,sizeof(check_path),"%s/%s/private%s.so",cwd_path,pro_path,check_name); + }else{ + snprintf(check_path,sizeof(check_path),"%s/tmp/jmod/%s/%s.so",cwd_path,jmod_name,check_name); + } + + lchr = '\n'; + while((tchr = fgetc(set_file)) != EOF){ + if(lchr == '\n' && tchr == '='){ + while(fgetc(set_file) != '\n'); + break; + } + lchr = tchr; + } + + line_dll = dlopen(line_path,RTLD_NOW); + check_dll = dlopen(check_path,RTLD_NOW); + + line_info = (judgm_line_info*)mmap(NULL,sizeof(struct judgm_line_info),PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANONYMOUS,-1,0); + line_info->subid = subid; + line_info->pro_path = pro_path; + line_info->code_path = code_path; + line_info->run_path = run_path; + + line_info->judgk_modfd = manage_judgk_modfd; + line_info->line_dll = line_dll; + line_info->check_dll = check_dll; + + line_info->lang = lang; + line_info->set_file = set_file; + line_info->set_data = set_data; + + tool_cleardir(line_info->run_path); + + run_fn = (judgm_line_run_fn)dlsym(line_dll,"run"); + if((pid = fork()) == 0){ + run_fn(line_info); + exit(0); + } + waitpid(pid,NULL,0); + + memcpy(res_data,line_info->res_data,line_info->res_len); + res_len = line_info->res_len; + + munmap(line_info,sizeof(judgm_line_info)); + fclose(set_file); + return 0; +} diff --git a/judge/judge_manage.h b/judge/judge_manage.h new file mode 100644 index 0000000..594ea71 --- /dev/null +++ b/judge/judge_manage.h @@ -0,0 +1,60 @@ +class manage_judgeth_info{ +public: + bool use_flag; + int thid; + char run_path[PATH_MAX + 1]; + judge_submit_info *sub_info; + char res_data[JUDGE_RES_DATAMAX]; + size_t res_len; + + manage_judgeth_info(int thid){ + this->use_flag = false; + this->thid = thid; + snprintf(this->run_path,sizeof(this->run_path),"tmp/run/%d",thid); + mkdir(this->run_path,0775); + this->sub_info = NULL; + this->res_len = 0; + } +}; + +static void manage_updatepro_th(void *data); +static void manage_updatepro_cb(void *data); +static void manage_unpackcode_th(void *data); +static void manage_unpackcode_cb(void *data); +static void manage_judge_th(void *data); +static void manage_judge_cb(void *data); +static int manage_queuejudge(judge_submit_info *sub_info); +static int manage_judge(int subid,char *pro_path,char *code_path,char *run_path,int lang,char *set_data,char *res_data,size_t &res_len); + +static tpool *manage_tp; +static int manage_judgk_modfd; +static manage_judgeth_info *manage_judgepool[16]; +static tpool_static_fn *manage_updatepro_thfn; +static tpool_static_fn *manage_updatepro_cbfn; +static tpool_static_fn *manage_unpackcode_thfn; +static tpool_static_fn *manage_unpackcode_cbfn; +static tpool_static_fn *manage_judge_thfn; +static tpool_static_fn *manage_judge_cbfn; +static std::multimap<int,judge_submit_info*> manage_submap; + +int judge_manage_init(); +int judge_manage_updatedata(); +judge_pro_info* judge_manage_getprobyid(int proid); +int judge_manage_getpro(judge_pro_info *pro_info); +int judge_manage_putpro(judge_pro_info *pro_info); +int judge_manage_updatepro(int proid,int cacheid,bool check_flag,judge_pro_info **update_pro_info); +int judge_manage_done_updatepro(judge_pro_info *pro_info); +int judge_manage_submit(int subid,int proid,int lang,char *set_data,int set_len); +int judge_manage_done_code(int subid); + +std::map<int,judge_pro_info*> judge_manage_promap; + +extern int tool_pack(char *pack_path,char *dir_path); +extern int tool_unpack(char *pack_path,char *dir_path); +extern int tool_cleardir(char *path); + +extern int judge_server_addtpool(tpool *tpinfo); +extern int judge_server_setpro(std::vector<std::pair<int,int> > &pro_list); +extern int judge_server_reqpro(int subid); +extern int judge_server_reqcode(int subid); +extern int judge_server_result(int subid,char *res_data,int res_len); diff --git a/judge/judge_server.cpp b/judge/judge_server.cpp new file mode 100644 index 0000000..66b4d01 --- /dev/null +++ b/judge/judge_server.cpp @@ -0,0 +1,515 @@ +#include<stdio.h> +#include<stdlib.h> +#include<string.h> +#include<unistd.h> +#include<fcntl.h> +#include<dlfcn.h> +#include<signal.h> +#include<limits.h> +#include<pthread.h> +#include<semaphore.h> +#include<errno.h> +#include<sys/types.h> +#include<sys/socket.h> +#include<sys/epoll.h> +#include<sys/eventfd.h> +#include<sys/sendfile.h> +#include<sys/mman.h> +#include<netinet/in.h> +#include<arpa/inet.h> +#include<map> +#include<queue> + +#include"netio.h" +#include"tpool.h" +#include"judge_def.h" +#include"judge.h" +#include"center_com.h" +#include"judgm_line.h" +#include"judgm_lib.h" +#include"judge_server.h" + +server_epevdata::server_epevdata(int fd,int type,void *data){ + this->fd = fd; + this->type = type; + this->data = data; +} + + +server_conn::server_conn(int fd):netio(fd){ + this->recv_dispatch_fn = new netio_iofn<server_conn>(this,&server_conn::recv_dispatch); + this->recv_setid_fn = new netio_iofn<server_conn>(this,&server_conn::recv_setid); + this->recv_submit_fn = new netio_iofn<server_conn>(this,&server_conn::recv_submit); + this->recv_setpro_fn = new netio_iofn<server_conn>(this,&server_conn::recv_setpro); + this->recv_sendpro_fn = new netio_iofn<server_conn>(this,&server_conn::recv_sendpro); + this->done_sendpro_fn = new netio_iofn<server_conn>(this,&server_conn::done_sendpro); + this->recv_setjmod_fn = new netio_iofn<server_conn>(this,&server_conn::recv_setjmod); + this->recv_sendjmod_fn = new netio_iofn<server_conn>(this,&server_conn::recv_sendjmod); + this->done_sendjmod_fn = new netio_iofn<server_conn>(this,&server_conn::done_sendjmod); + this->recv_sendcode_fn = new netio_iofn<server_conn>(this,&server_conn::recv_sendcode); + this->done_sendcode_fn = new netio_iofn<server_conn>(this,&server_conn::done_sendcode); + this->tp_unpackjmod_thfn = new tpool_fn<server_conn>(this,&server_conn::tp_unpackjmod_th); + this->tp_unpackjmod_cbfn = new tpool_fn<server_conn>(this,&server_conn::tp_unpackjmod_cb); + + send_setid(); +} +char* server_conn::create_combuf(int code,int size,int &len,void **data){ + char *buf; + center_com_header *header; + + buf = new char[sizeof(center_com_header) + size]; + header = (center_com_header*)buf; + header->code = code; + header->size = size; + len = sizeof(center_com_header) + size; + *data = (void*)(buf + sizeof(center_com_header)); + + return buf; +} +int server_conn::send_setid(){ + char *write_buf; + int write_len; + center_com_setid *setid; + + write_buf = create_combuf(CENTER_COMCODE_SETID,sizeof(center_com_setid),write_len,(void**)&setid); + setid->id = server_id; + writebytes(write_buf,write_len,NULL,NULL); + + return 0; +} +int server_conn::send_setinfo(){ + char *write_buf; + int write_len; + center_com_setinfo *setinfo; + + write_buf = create_combuf(CENTER_COMCODE_SETINFO,sizeof(center_com_setinfo),write_len,(void**)&setinfo); + setinfo->avail = server_avail; + writebytes(write_buf,write_len,NULL,NULL); + + return 0; +} +int server_conn::send_result(int subid,char *res_data,size_t res_len){ + char *write_buf; + int write_len; + center_com_result *result; + + if(res_len > JUDGE_RES_DATAMAX){ + return -1; + } + + write_buf = create_combuf(CENTER_COMCODE_RESULT,sizeof(center_com_result) + res_len,write_len,(void**)&result); + result->subid = subid; + memcpy((void*)(write_buf + sizeof(center_com_header) + sizeof(center_com_result)),res_data,res_len); + writebytes(write_buf,write_len,NULL,NULL); + + return 0; +} +int server_conn::send_reqpro(int proid,int cacheid){ + char *write_buf; + int write_len; + center_com_reqpro *reqpro; + + write_buf = create_combuf(CENTER_COMCODE_REQPRO,sizeof(center_com_reqpro),write_len,(void**)&reqpro); + reqpro->proid = proid; + reqpro->cacheid = cacheid; + writebytes(write_buf,write_len,NULL,NULL); +} +int server_conn::send_setpro(std::vector<std::pair<int,int> > &pro_list,int type){ + int i; + int count; + char *write_buf; + int write_len; + center_com_setpro *setpro; + judge_pro_info *pro_info; + + count = pro_list.size(); + write_buf = create_combuf(CENTER_COMCODE_SETPRO,sizeof(center_com_setpro) * count,write_len,(void**)&setpro); + + for(i = 0;i < count;i++){ + setpro[i].proid = pro_list[i].first; + setpro[i].cacheid = pro_list[i].second; + setpro[i].type = type; + } + writebytes(write_buf,write_len,NULL,NULL); + + return 0; +} +int server_conn::send_setjmod(char **jmod_name,int *cacheid,int type,int count){ + int i; + + char *write_buf; + int write_len; + center_com_setjmod *setjmod; + + write_buf = create_combuf(CENTER_COMCODE_SETJMOD,sizeof(center_com_setjmod) * count,write_len,(void**)&setjmod); + for(i = 0;i < count;i++){ + setjmod[i].jmod_name[0] = '\0'; + strncat(setjmod[i].jmod_name,jmod_name[i],sizeof(setjmod[i].jmod_name)); + setjmod[i].cacheid = cacheid[i]; + setjmod[i].type = type; + } + writebytes(write_buf,write_len,NULL,NULL); + + return 0; +} +int server_conn::send_reqcode(int subid){ + char *write_buf; + int write_len; + center_com_reqcode *reqcode; + + write_buf = create_combuf(CENTER_COMCODE_REQCODE,sizeof(center_com_reqcode),write_len,(void**)&reqcode); + reqcode->subid = subid; + writebytes(write_buf,write_len,NULL,NULL); + + return 0; +} +int server_conn::readidle(){ + readbytes(new center_com_header,sizeof(center_com_header),recv_dispatch_fn,NULL); + return 0; +} +void server_conn::recv_dispatch(void *buf,size_t len,void *data){ + center_com_header *header; + char *readbuf; + + header = (center_com_header*)buf; + readbuf = new char[header->size]; + printf("code:%d size:%d\n",header->code,header->size); + switch(header->code){ + case CENTER_COMCODE_SETID: + readbytes(readbuf,header->size,recv_setid_fn,NULL); + break; + case CENTER_COMCODE_SUBMIT: + readbytes(readbuf,header->size,recv_submit_fn,NULL); + break; + case CENTER_COMCODE_SETPRO: + readbytes(readbuf,header->size,recv_setpro_fn,NULL); + break; + case CENTER_COMCODE_SENDPRO: + readbytes(readbuf,header->size,recv_sendpro_fn,NULL); + break; + case CENTER_COMCODE_SETJMOD: + readbytes(readbuf,header->size,recv_setjmod_fn,NULL); + break; + case CENTER_COMCODE_SENDJMOD: + readbytes(readbuf,header->size,recv_sendjmod_fn,NULL); + break; + case CENTER_COMCODE_SENDCODE: + readbytes(readbuf,header->size,recv_sendcode_fn,NULL); + break; + } + + delete header; +} +void server_conn::recv_setid(void *buf,size_t len,void *data){ + center_com_setid *setid; + + setid = (center_com_setid*)buf; + server_id = setid->id; + printf("server_id:%d\n",server_id); + + //judge server init + send_setinfo(); + + delete setid; +} +void server_conn::recv_submit(void *buf,size_t len,void *data){ + center_com_submit *sub; + + sub = (center_com_submit*)buf; + judge_manage_submit(sub->subid,sub->proid,sub->lang,(char*)((char*)buf + sizeof(center_com_submit)),len - sizeof(center_com_submit)); + + delete sub; +} +void server_conn::recv_setpro(void *buf,size_t len,void *data){ + int ret; + int i; + int count; + center_com_setpro *setpro; + + char tpath[PATH_MAX + 1]; + FILE *f; + int cacheid; + std::vector<std::pair<int,int> > pro_list; + + count = len / sizeof(center_com_setpro); + setpro = (center_com_setpro*)buf; + for(i = 0;i < count;i++){ + if(setpro[i].type == 0){ + ret = judge_manage_updatepro(setpro[i].proid,setpro[i].cacheid,true,NULL); + if(ret == 0){ + if(server_fileconn == NULL){ + server_fileconn = server_connect(); + } + server_fileconn->send_reqpro(setpro[i].proid,setpro[i].cacheid); + }else if(ret == 1){ + pro_list.push_back(std::make_pair(setpro[i].proid,setpro[i].cacheid)); + } + }else if(setpro[i].type == 1){ + + } + } + + if(!pro_list.empty()){ + this->send_setpro(pro_list,0); + } + + delete setpro; +} +void server_conn::recv_sendpro(void *buf,size_t len,void *data){ + center_com_sendpro *sendpro; + judge_pro_info *pro_info; + char tpath[PATH_MAX + 1]; + int fd; + + sendpro = (center_com_sendpro*)buf; + + if(judge_manage_updatepro(sendpro->proid,sendpro->cacheid,false,&pro_info) == 0){ + snprintf(tpath,sizeof(tpath),"tmp/propack/%d_%d.tar.bz2",sendpro->proid,sendpro->cacheid); + fd = open(tpath,O_WRONLY | O_CREAT,0644); + readfile(fd,sendpro->filesize,done_sendpro_fn,pro_info); + } + + delete sendpro; +} +void server_conn::done_sendpro(void *buf,size_t len,void *data){ + judge_pro_info *pro_info; + + close(*(int*)buf); + + pro_info = (judge_pro_info*)data; + judge_manage_done_updatepro(pro_info); +} +void server_conn::recv_setjmod(void *buf,size_t len,void *data){ + int i; + int count; + center_com_setjmod *setjmod; + + char tpath[PATH_MAX + 1]; + FILE *f; + int cacheid; + std::vector<char*> sl_jmod_name; + std::vector<int> sl_cacheid; + + char *write_buf; + int write_len; + center_com_reqjmod *reqjmod; + + count = len / sizeof(center_com_setjmod); + setjmod = (center_com_setjmod*)buf; + for(i = 0;i < count;i++){ + if(setjmod[i].type == 0){ + snprintf(tpath,sizeof(tpath),"tmp/jmod/%s/cacheinfo",setjmod[i].jmod_name); + f = fopen(tpath,"r"); + if(f != NULL){ + fscanf(f,"%d",&cacheid); + fclose(f); + + if(cacheid == setjmod[i].cacheid){ + sl_jmod_name.push_back(setjmod[i].jmod_name); + sl_cacheid.push_back(setjmod[i].cacheid); + continue; + } + } + + if(server_fileconn == NULL){ + server_fileconn = server_connect(); + } + + write_buf = create_combuf(CENTER_COMCODE_REQJMOD,sizeof(center_com_reqjmod),write_len,(void**)&reqjmod); + reqjmod->jmod_name[0] = '\0'; + strncat(reqjmod->jmod_name,setjmod[i].jmod_name,sizeof(reqjmod->jmod_name)); + server_fileconn->writebytes(write_buf,write_len,NULL,NULL); + }else if(setjmod[i].type == 1){ + + } + } + + if(!sl_jmod_name.empty()){ + this->send_setjmod(&sl_jmod_name[0],&sl_cacheid[0],0,sl_jmod_name.size()); + } + + delete setjmod; +} +void server_conn::recv_sendjmod(void *buf,size_t len,void *data){ + center_com_sendjmod *sendjmod; + char tpath[PATH_MAX + 1]; + int fd; + + sendjmod = (center_com_sendjmod*)buf; + snprintf(tpath,sizeof(tpath),"tmp/jmodpack/%s.tar.bz2",sendjmod->jmod_name); + fd = open(tpath,O_WRONLY | O_CREAT,0644); + readfile(fd,sendjmod->filesize,done_sendjmod_fn,sendjmod); +} +void server_conn::done_sendjmod(void *buf,size_t len,void *data){ + center_com_sendjmod *sendjmod; + + close(*(int*)buf); + + sendjmod = (center_com_sendjmod*)data; + server_packtp->add(tp_unpackjmod_thfn,sendjmod,tp_unpackjmod_cbfn,sendjmod); +} +void server_conn::recv_sendcode(void *buf,size_t len,void *data){ + center_com_sendcode *sendcode; + char tpath[PATH_MAX + 1]; + int fd; + + sendcode = (center_com_sendcode*)buf; + snprintf(tpath,sizeof(tpath),"tmp/codepack/%d.tar.bz2",sendcode->subid); + fd = open(tpath,O_WRONLY | O_CREAT,0644); + readfile(fd,sendcode->filesize,done_sendcode_fn,sendcode); +} +void server_conn::done_sendcode(void *buf,size_t len,void *data){ + center_com_sendcode *sendcode; + + close(*(int*)buf); + + sendcode = (center_com_sendcode*)data; + judge_manage_done_code(sendcode->subid); + + delete sendcode; +} +void server_conn::tp_unpackjmod_th(void *data){ + center_com_sendjmod *sendjmod; + char pack_path[PATH_MAX + 1]; + char dir_path[PATH_MAX + 1]; + char tpath[PATH_MAX + 1]; + FILE *f; + + sendjmod = (center_com_sendjmod*)data; + + snprintf(pack_path,sizeof(pack_path),"tmp/jmodpack/%s.tar.bz2",sendjmod->jmod_name); + snprintf(dir_path,sizeof(dir_path),"tmp/jmod/%s",sendjmod->jmod_name); + mkdir(dir_path,0755); + tool_cleardir(dir_path); + tool_unpack(pack_path,dir_path); + + snprintf(tpath,sizeof(tpath),"tmp/jmod/%s/cacheinfo",sendjmod->jmod_name); + f = fopen(tpath,"w"); + fprintf(f,"%d",sendjmod->cacheid); + fclose(f); +} +void server_conn::tp_unpackjmod_cb(void *data){ + center_com_sendjmod *sendjmod; + char *jmod_name; + + sendjmod = (center_com_sendjmod*)data; + jmod_name = sendjmod->jmod_name; + send_setjmod(&jmod_name,&sendjmod->cacheid,0,1); + + delete sendjmod; +} + + + +int judge_server_addtpool(tpool *tpinfo){ + server_addepev(tpinfo->fd,EPOLLIN | EPOLLET,SERVER_EPEV_TPOOL,tpinfo); + return 0; +} +int judge_server_setpro(std::vector<std::pair<int,int> > &pro_list){ + server_mainconn->send_setpro(pro_list,0); + return 0; +} +int judge_server_reqcode(int subid){ + if(server_codeconn == NULL){ + server_codeconn = server_connect(); + } + server_codeconn->send_reqcode(subid); + + return 0; +} +int judge_server_result(int subid,char *res_data,int res_len){ + server_mainconn->send_result(subid,res_data,res_len); + return 0; +} + +static int server_addepev(int fd,unsigned int flag,int type,void *data){ + server_epevdata *epevdata; + epoll_event epev; + + epevdata = new server_epevdata(fd,type,data); + epev.events = flag; + epev.data.ptr = epevdata; + epoll_ctl(server_epfd,EPOLL_CTL_ADD,fd,&epev); + + return 0; +} +static int server_delepev(server_epevdata *epevdata){ + epoll_ctl(server_epfd,EPOLL_CTL_DEL,epevdata->fd,NULL); + delete epevdata; + return 0; +} +static server_conn* server_connect(){ + int cfd; + sockaddr_in caddr; + epoll_event epev; + server_conn *cinfo; + + cfd = socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,6); + caddr.sin_family = AF_INET; + caddr.sin_port = htons(SERVER_JUDGE_PORT); + //caddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + caddr.sin_addr.s_addr = inet_addr("10.8.0.2"); + + cinfo = new server_conn(cfd); + server_addepev(cfd,EPOLLIN | EPOLLOUT | EPOLLRDHUP | EPOLLET,SERVER_EPEV_JUDGECLIENT,cinfo); + connect(cfd,(sockaddr*)&caddr,sizeof(caddr)); + + return cinfo; +} +int main(){ + int i; + + epoll_event epev; + epoll_event epevs[SERVER_EPOLL_MAXEVENT]; + int nevs; + + int ev_flag; + server_epevdata *epevdata; + server_conn *cinfo; + tpool *tpinfo; + + signal(SIGPIPE,SIG_IGN); + server_epfd = epoll_create1(0); + + server_id = 0; + server_avail = JUDGE_THREAD_JUDGEMAX; + server_mainconn = server_connect(); + server_fileconn = NULL; + server_codeconn = NULL; + + judge_manage_init(); + + server_packtp = new tpool(4); + judge_server_addtpool(server_packtp); + server_packtp->start(); + + + while(true){ + nevs = epoll_wait(server_epfd,epevs,SERVER_EPOLL_MAXEVENT,-1); + for(i = 0;i < nevs;i++){ + ev_flag = epevs[i].events; + epevdata = (server_epevdata*)epevs[i].data.ptr; + + if(epevdata->type == SERVER_EPEV_JUDGECLIENT){ + cinfo = (server_conn*)epevdata->data; + if(ev_flag & EPOLLIN){ + cinfo->readio(); + } + if(ev_flag & EPOLLOUT){ + cinfo->writeio(); + } + + server_packtp->done(); + }else if(epevdata->type = SERVER_EPEV_TPOOL){ + tpinfo = (tpool*)epevdata->data; + if(ev_flag & EPOLLIN){ + tpinfo->done(); + } + } + } + } + + close(server_epfd); + + return 0; +} diff --git a/judge/judge_server.h b/judge/judge_server.h new file mode 100644 index 0000000..90a4e7c --- /dev/null +++ b/judge/judge_server.h @@ -0,0 +1,87 @@ +#define SERVER_JUDGE_PORT 2573 +#define SERVER_EPOLL_MAXEVENT 4096 + +#define SERVER_EPEV_JUDGECLIENT 0 +#define SERVER_EPEV_TPOOL 1 +class server_epevdata{ +public: + int fd; + int type; + void *data; + + server_epevdata(int fd,int type,void *data); +}; + +class server_conn : public netio{ +private: + netio_iofn<server_conn> *recv_dispatch_fn; + netio_iofn<server_conn> *recv_setid_fn; + netio_iofn<server_conn> *recv_submit_fn; + netio_iofn<server_conn> *recv_setpro_fn; + netio_iofn<server_conn> *recv_sendpro_fn; + netio_iofn<server_conn> *done_sendpro_fn; + netio_iofn<server_conn> *recv_setjmod_fn; + netio_iofn<server_conn> *recv_sendjmod_fn; + netio_iofn<server_conn> *done_sendjmod_fn; + netio_iofn<server_conn> *recv_sendcode_fn; + netio_iofn<server_conn> *done_sendcode_fn; + tpool_fn<server_conn> *tp_unpackjmod_thfn; + tpool_fn<server_conn> *tp_unpackjmod_cbfn; + + char* create_combuf(int code,int size,int &len,void **data); + void recv_dispatch(void *buf,size_t len,void *data); + void recv_setid(void *buf,size_t len,void *data); + void recv_submit(void *buf,size_t len,void *data); + void recv_setpro(void *buf,size_t len,void *data); + void recv_sendpro(void *buf,size_t len,void *data); + void done_sendpro(void *buf,size_t len,void *data); + void recv_setjmod(void *buf,size_t len,void *data); + void recv_sendjmod(void *buf,size_t len,void *data); + void done_sendjmod(void *buf,size_t len,void *data); + void recv_sendcode(void *buf,size_t len,void *data); + void done_sendcode(void *buf,size_t len,void *data); + void tp_unpackjmod_th(void *data); + void tp_unpackjmod_cb(void *data); + +public: + server_conn(int fd); + int send_setid(); + int send_setinfo(); + int send_result(int subid,char *res_data,size_t res_len); + int send_reqpro(int proid,int cacheid); + int send_setpro(std::vector<std::pair<int,int> > &pro_list,int type); + int send_setjmod(char **jmod_name,int *cacheid,int type,int count); + int send_reqcode(int subid); + virtual int readidle(); +}; + +static int server_addepev(int fd,unsigned int flag,int type,void *data); +static int server_delepev(server_epevdata *epevdata); +static server_conn* server_connect(); + +static int server_id; +static int server_avail; +static int server_epfd; +static server_conn *server_mainconn; +static server_conn *server_fileconn; +static server_conn *server_codeconn; +static tpool *server_packtp; + +int judge_server_addtpool(tpool *tpinfo); +int judge_server_setpro(std::vector<std::pair<int,int> > &pro_list); +int judge_server_reqcode(int subid); +int judge_server_result(int subid,char *res_data,int res_len); + +extern int tool_pack(char *pack_path,char *dir_path); +extern int tool_unpack(char *pack_path,char *dir_path); +extern int tool_cleardir(char *path); + +extern int judge_manage_init(); +extern judge_pro_info* judge_manage_getprobyid(int proid); +extern int judge_manage_getpro(judge_pro_info *pro_info); +extern int judge_manage_putpro(judge_pro_info *pro_info); +extern int judge_manage_updatepro(int proid,int cacheid,bool check_flag,judge_pro_info **update_pro_info); +extern int judge_manage_done_updatepro(judge_pro_info *pro_info); +extern int judge_manage_submit(int subid,int proid,int lang,char *set_data,int set_len); +extern int judge_manage_done_code(int subid); + diff --git a/judge/judgm_lib.h b/judge/judgm_lib.h new file mode 100644 index 0000000..041901d --- /dev/null +++ b/judge/judgm_lib.h @@ -0,0 +1,418 @@ +#include<string.h> +#include<limits.h> +#include<unistd.h> +#include<signal.h> +#include<limits.h> +#include<errno.h> +#include<pthread.h> +#include<semaphore.h> +#include<fcntl.h> +#include<sys/ioctl.h> +#include<sys/resource.h> +#include<sys/stat.h> +#include<sys/types.h> +#include<sys/wait.h> +#include<sys/mman.h> +#include<map> +#include<utility> + +#include"judge.h" + +typedef int (*judgm_proc_check_fn)(); + +class judgm_proc{ +private: + int init(){ + int i; + int j; + struct stat st; + + if(stat(exe_path,&st)){ + return -1; + } + if(!S_ISREG(st.st_mode)){ + return -1; + } + + exe_name[NAME_MAX] = '\0'; + for(i = 0,j = 0;exe_path[i] != '\0' && j < NAME_MAX;i++){ + if(exe_path[i] == '/'){ + j = 0; + }else{ + exe_name[j] = exe_path[i]; + j++; + } + } + exe_name[j] = '\0'; + + pid = 0; + kern_task = 0; + status = JUDGE_WAIT; + runtime = 0; + memory = 0; + + return 0; + } + int protect(){ + rlimit limit; + judgk_com_proc_add com_proc_add; + + limit.rlim_cur = 1; + limit.rlim_max = limit.rlim_cur; + prlimit(pid,RLIMIT_NPROC,&limit,NULL); + + limit.rlim_cur = 8L; + limit.rlim_max = limit.rlim_cur; + prlimit(pid,RLIMIT_NOFILE,&limit,NULL); + + limit.rlim_cur = 70368744177664L; + limit.rlim_max = limit.rlim_cur; + prlimit(pid,RLIMIT_STACK,&limit,NULL); + + com_proc_add.run_path[0] = '\0'; + strncat(com_proc_add.run_path,run_path,sizeof(com_proc_add.run_path)); + com_proc_add.pid = pid; + com_proc_add.timelimit = timelimit * 1000L; + com_proc_add.hardtimelimit = hardtimelimit * 1000L; + com_proc_add.memlimit = memlimit * 1024L + 4096L * 128L; + if(ioctl(judgk_modfd,IOCTL_PROC_ADD,&com_proc_add)){ + return -1; + } + kern_task = com_proc_add.kern_task; + + return 0; + } + +public: + int judgk_modfd; + char run_path[PATH_MAX + 1]; + char exe_path[PATH_MAX + 1]; + char exe_name[NAME_MAX + 1]; + unsigned long timelimit; + unsigned long hardtimelimit; + unsigned long memlimit; + judgm_proc_check_fn check_fn; + + pid_t pid; + unsigned long kern_task; + int status; + unsigned long runtime; + unsigned long memory; + + judgm_proc(int judgk_modfd,char *runpath,char *exe_path,unsigned long timelimit,unsigned long hardtimelimit,unsigned long memlimit,judgm_proc_check_fn check_fn){ + this->judgk_modfd = judgk_modfd; + this->run_path[0] = '\0'; + strncat(this->run_path,runpath,sizeof(this->run_path)); + this->exe_path[0] = '\0'; + strncat(this->exe_path,exe_path,sizeof(this->exe_path)); + + this->timelimit = timelimit; + this->hardtimelimit = hardtimelimit; + this->memlimit = memlimit; + this->check_fn = check_fn; + } + + int proc_run(){ + char abspath[PATH_MAX + 1]; + + if(init()){ + return -1; + } + + realpath(exe_path,abspath); + if((pid = fork()) == 0){ + char *argv[] = {NULL,NULL}; + char *envp[] = {NULL}; + + chdir(run_path); + check_fn(); + + setgid(99); + setuid(99); + kill(getpid(),SIGSTOP); + + argv[0] = exe_name; + execve(abspath,argv,envp); + exit(0); + } + + if(pid == -1){ + return -1; + } + waitpid(pid,NULL,WUNTRACED); + + if(protect()){ + kill(pid,SIGKILL); + return -1; + } + status = JUDGE_RUN; + kill(pid,SIGCONT); + + return 0; + } + int proc_wait(bool blockflag){ + int wstatus; + struct judgk_com_proc_get com_proc_get; + + if(blockflag == true){ + if(waitpid(pid,&wstatus,WUNTRACED) == -1){ + return -1; + } + }else{ + if(waitpid(pid,&wstatus,WUNTRACED | WNOHANG) <= 0){ + return -1; + } + } + + com_proc_get.kern_task = kern_task; + if(ioctl(judgk_modfd,IOCTL_PROC_GET,&com_proc_get)){ + return -1; + } + + runtime = com_proc_get.runtime / 1000L; + memory = com_proc_get.memory; + + printf("runtime:%lu memory:%lu\n",runtime,memory); + + if(com_proc_get.status != JUDGE_AC){ + status = com_proc_get.status; + }else if(memory > (memlimit * 1024L)){ + status = JUDGE_MLE; + }else if(runtime > timelimit){ + status = JUDGE_TLE; + }else if(WIFEXITED(wstatus) || (WIFSIGNALED(wstatus) && WTERMSIG(wstatus) == SIGKILL)){ + status = JUDGE_AC; + }else{ + status = JUDGE_RE; + } + + return 0; + } + int proc_kill(){ + if(kill(pid,SIGKILL)){ + return -1; + } + return 0; + } +}; + +class judgm_hyperio{ +private: + int judgk_modfd; + char *read_buf; + off_t read_off; + +public: + int tty_idx; + + judgm_hyperio(int judgk_modfd){ + this->judgk_modfd = judgk_modfd; + this->tty_idx = ioctl(this->judgk_modfd,IOCTL_HYPERIO_ADD,0); + this->read_buf = (char*)mmap(NULL,JUDGK_COM_HYPERIO_BUFSIZE,PROT_READ,MAP_SHARED,judgk_modfd,0); + this->read_off = 0; + } + ~judgm_hyperio(){ + munmap(read_buf,JUDGK_COM_HYPERIO_BUFSIZE); + ioctl(judgk_modfd,IOCTL_HYPERIO_DEL,0); + } + + static int get_ttyfd(int idx){ + char tpath[PATH_MAX + 1]; + + snprintf(tpath,sizeof(tpath),"/dev/jtty%d",idx); + return open(tpath,O_RDWR); + } + size_t wait(){ + return ioctl(judgk_modfd,IOCTL_HYPERIO_READ,0); + } + int compare(char *buf,size_t len){ + int flag; + size_t remain; + off_t off; + size_t data_len; + size_t cmp_len; + + flag = 0; + remain = len; + off = 0; + data_len = 0; + cmp_len = 0; + while(remain > 0 && flag == 0){ + if(data_len == 0){ + if((data_len = ioctl(judgk_modfd,IOCTL_HYPERIO_READ,cmp_len)) <= 0){ + return -1; + } + } + if(remain < data_len){ + cmp_len = remain; + }else{ + cmp_len = data_len; + } + + if((cmp_len + read_off) < JUDGK_COM_HYPERIO_BUFSIZE){ + flag |= memcmp(read_buf + read_off,buf + off,cmp_len); + read_off += cmp_len; + }else{ + flag |= memcmp(read_buf + read_off,buf + off,JUDGK_COM_HYPERIO_BUFSIZE - read_off); + flag |= memcmp(read_buf,buf + off + (JUDGK_COM_HYPERIO_BUFSIZE - read_off),(cmp_len + read_off) - JUDGK_COM_HYPERIO_BUFSIZE); + read_off = (cmp_len + read_off) - JUDGK_COM_HYPERIO_BUFSIZE; + } + remain -= cmp_len; + off += cmp_len; + data_len -= cmp_len; + } + if(cmp_len > 0){ + ioctl(judgk_modfd,IOCTL_HYPERIO_READ,-(long)cmp_len); + } + + if(flag == 0){ + return 0; + }else{ + return -1; + } + } +}; + +static int judgm_compile(int subid,char *code_path,char *exe_path,int lang,bool force_flag,char *err_msg,size_t err_len){ + int ret; + int i; + + char log_path[PATH_MAX + 1]; + char main_path[PATH_MAX + 1]; + char sem_path[PATH_MAX + 1]; + struct stat st; + sem_t *wait_sem; + bool ce_flag; + char dir_path[PATH_MAX + 1]; + char *out_path; + int io[2]; + int pid; + int wstatus; + char buf[64]; + off_t err_off; + FILE *f_log; + + if(force_flag == true){ + force_flag = true; + out_path = exe_path; + }else{ + snprintf(log_path,sizeof(log_path),"tmp/exe/%d/log",subid); + snprintf(main_path,sizeof(main_path),"tmp/exe/%d/main",subid); + snprintf(sem_path,sizeof(sem_path),"/judgm_compile_wait_%d",subid); + if((wait_sem = sem_open(sem_path,0)) == SEM_FAILED){ + if(stat(main_path,&st)){ + if((wait_sem = sem_open(sem_path,O_CREAT | O_EXCL,0644,0)) != SEM_FAILED){ + out_path = main_path; + goto compile; + }else if((wait_sem = sem_open(sem_path,0)) != SEM_FAILED){ + + sem_wait(wait_sem); + + sem_close(wait_sem); + } + } + }else{ + + sem_wait(wait_sem); + + sem_close(wait_sem); + } + + if((f_log = fopen(log_path,"r")) != NULL){ + err_off = fread(err_msg,1,err_len - 1,f_log); + fclose(f_log); + err_msg[err_off] = '\0'; + + if(!link(main_path,exe_path)){ + return 0; + }else{ + return -1; + } + } + } + +compile: + + if(force_flag == false){ + snprintf(dir_path,sizeof(dir_path),"tmp/exe/%d",subid); + mkdir(dir_path,0755); + } + ce_flag = false; + err_off = 0; + + if(lang == JUDGE_CPP){ + pipe(io); + + if((pid = fork()) == 0){ + char arg_compiler[16]; + char arg_static[16]; + char arg_o[16]; + char arg_std[16]; + char arg_output[16]; + char *argv[8]; + + arg_compiler[0] = '\0'; + strncat(arg_compiler,"g++",sizeof(arg_compiler)); + arg_static[0] = '\0'; + strncat(arg_static,"-static",sizeof(arg_static)); + arg_o[0] = '\0'; + strncat(arg_o,"-O2",sizeof(arg_o)); + arg_std[0] = '\0'; + strncat(arg_std,"-std=c++0x",sizeof(arg_std)); + arg_output[0] = '\0'; + strncat(arg_output,"-o",sizeof(arg_output)); + + argv[0] = arg_compiler; + argv[1] = arg_static; + argv[2] = arg_o; + argv[3] = code_path; + argv[4] = arg_std; + argv[5] = arg_output; + argv[6] = out_path; + argv[7] = NULL; + + dup2(io[1],1); + dup2(io[1],2); + execvp("g++",argv); + } + + close(io[1]); + while((ret = read(io[0],err_msg + err_off,err_len - err_off - 1)) > 0){ + err_off += ret; + } + err_msg[err_off] = '\0'; + + while(read(io[0],buf,64) > 0); + close(io[0]); + + if(err_off > (err_len - 4)){ + err_msg[err_len - 4] = '\0'; + strncat(err_msg + err_len - 4,"...",4); + err_off = err_len - 1; + } + + waitpid(pid,&wstatus,0); + if(wstatus != 0){ + ce_flag = true; + } + } + + if(force_flag == false){ + f_log = fopen(log_path,"w"); + fwrite(err_msg,err_off,1,f_log); + fclose(f_log); + + for(i = 0;i < JUDGE_THREAD_MAX;i++){ + sem_post(wait_sem); + } + sem_close(wait_sem); + sem_unlink(sem_path); + } + if(ce_flag == true){ + return -1; + } + + link(main_path,exe_path); + + return 0; +} diff --git a/judge/judgm_line.h b/judge/judgm_line.h new file mode 100644 index 0000000..1b36c74 --- /dev/null +++ b/judge/judgm_line.h @@ -0,0 +1,19 @@ +struct judgm_line_info{ + int subid; + + char *pro_path; + char *code_path; + char *run_path; + + int judgk_modfd; + void *line_dll; + void *check_dll; + + int lang; + FILE *set_file; + char *set_data; + + char res_data[JUDGE_RES_DATAMAX]; + size_t res_len; +}; +typedef int (*judgm_line_run_fn)(judgm_line_info *info); diff --git a/judge/judgm_manage.h b/judge/judgm_manage.h new file mode 100644 index 0000000..2795ec7 --- /dev/null +++ b/judge/judgm_manage.h @@ -0,0 +1,29 @@ +typedef int (*judgm_manage_queuesubmit_fn)(int subid,int proid,int lang,char *set_data,size_t set_len); + +class judgm_manage_info{ +public: + int subid; + int uid; + int proid; + int lang; + char *param; + char pro_path[PATH_MAX + 1]; + char res_path[PATH_MAX + 1]; + + int result; + double score; + unsigned long runtime; + unsigned long memory; + + void *private_data; + + judgm_manage_info(int subid,int uid,int proid,int lang,char *param){ + this->subid = subid; + this->uid = uid; + this->proid = proid; + this->lang = lang; + this->param = param; + } +}; +typedef int (*judgm_manage_submit_fn)(judgm_manage_info *info,FILE *set_file); +typedef int (*judgm_manage_result_fn)(judgm_manage_info *info,char *res_data); diff --git a/judge/netio.h b/judge/netio.h new file mode 100644 index 0000000..db54b23 --- /dev/null +++ b/judge/netio.h @@ -0,0 +1,192 @@ +class netio_protoiofn{ +public: + virtual void operator()(void *buf,size_t len,void *data) = 0; +}; + +template<typename C> +class netio_iofn : public netio_protoiofn{ +private: + typedef void (C::*netio_iofn_type)(void *buf,size_t len,void *data); + C *obj; + netio_iofn_type fn; + +public: + netio_iofn(C *obj,netio_iofn_type fn){ + this->obj = obj; + this->fn = fn; + } + void operator()(void *buf,size_t len,void *data){ + (obj->*fn)(buf,len,data); + } +}; + +#define NETIO_IOTYPE_PLAIN 0 +#define NETIO_IOTYPE_FILE 1 +class netio_iocb{ +public: + int type; + + void *buf; + int fd; + off_t off; + size_t len; + netio_protoiofn *cb_fn; + void *cb_data; + + netio_iocb(void *buf,size_t len,netio_protoiofn *cb_fn,void *cb_data){ + this->type = NETIO_IOTYPE_PLAIN; + this->buf = buf; + this->off = 0; + this->len = len; + this->cb_fn = cb_fn; + this->cb_data = cb_data; + } + netio_iocb(int fd,size_t len,netio_protoiofn *cb_fn,void *cb_data){ + this->type = NETIO_IOTYPE_FILE; + this->buf = &this->fd; + this->fd = fd; + this->off = 0; + this->len = len; + this->cb_fn = cb_fn; + this->cb_data = cb_data; + } +}; + +#define NETIO_IOSIZE 65536 +class netio{ +private: + netio_iocb *read_iocb; + std::queue<netio_iocb*> write_queue; + bool readio_reen; + char readio_buf[NETIO_IOSIZE]; + +public: + int fd; + virtual int readidle() = 0; + + netio(int fd){ + this->fd = fd; + this->read_iocb = NULL; + this->readio_reen = false; + } + ~netio(){ + close(this->fd); + } + int readio(){ + int ret; + size_t len; + netio_iocb *iocb; + + if(readio_reen == true){ + return -1; + } + readio_reen = true; + + while(true){ + if(read_iocb == NULL){ + readidle(); + } + + iocb = read_iocb; + if(iocb->type == NETIO_IOTYPE_PLAIN){ + while((ret = read(fd,(char*)iocb->buf + iocb->off,iocb->len - iocb->off)) > 0){ + iocb->off += ret; + } + }else if(iocb->type == NETIO_IOTYPE_FILE){ + while(true){ + len = iocb->len - iocb->off; + if(len >= NETIO_IOSIZE){ + len = NETIO_IOSIZE; + } + if((ret = read(fd,readio_buf,len)) <= 0){ + break; + } + + write(iocb->fd,readio_buf,ret); + iocb->off += ret; + } + } + if(iocb->off == iocb->len){ + read_iocb = NULL; + + if(iocb->cb_fn != NULL){ + (*iocb->cb_fn)(iocb->buf,iocb->len,iocb->cb_data); + }else{ + if(iocb->type == NETIO_IOTYPE_PLAIN){ + delete (char*)iocb->buf; + }else if(iocb->type == NETIO_IOTYPE_FILE){ + close(iocb->fd); + } + } + + delete iocb; + }else{ + break; + } + } + + readio_reen = false; + return 0; + } + int readbytes(void *buf,size_t len,netio_protoiofn *cb_fn,void *cb_data){ + read_iocb = new netio_iocb(buf,len,cb_fn,cb_data); + readio(); + return 0; + } + int readfile(int fd,size_t len,netio_protoiofn *cb_fn,void *cb_data){ + read_iocb = new netio_iocb(fd,len,cb_fn,cb_data); + readio(); + return 0; + } + int writeio(){ + int ret; + size_t len; + netio_iocb *iocb; + + while(!write_queue.empty()){ + iocb = write_queue.front(); + if(iocb->type == NETIO_IOTYPE_PLAIN){ + while((ret = write(fd,(char*)iocb->buf + iocb->off,iocb->len - iocb->off)) > 0){ + iocb->off += ret; + } + }else if(iocb->type == NETIO_IOTYPE_FILE){ + len = iocb->len - iocb->off; + if(len >= NETIO_IOSIZE){ + len = NETIO_IOSIZE; + } + while((ret = sendfile(fd,iocb->fd,NULL,len)) > 0){ + iocb->off += ret; + } + } + if(iocb->off == iocb->len){ + write_queue.pop(); + + if(iocb->cb_fn != NULL){ + (*iocb->cb_fn)(iocb->buf,iocb->len,iocb->cb_data); + }else{ + if(iocb->type == NETIO_IOTYPE_PLAIN){ + delete (char*)iocb->buf; + }else if(iocb->type == NETIO_IOTYPE_FILE){ + close(iocb->fd); + } + } + + delete iocb; + }else{ + break; + } + } + + return 0; + } + int writebytes(void *buf,size_t len,netio_protoiofn *cb_fn,void *cb_data){ + write_queue.push(new netio_iocb(buf,len,cb_fn,cb_data)); + writeio(); + return 0; + } + int writefile(int fd,size_t len,netio_protoiofn *cb_fn,void *cb_data){ + write_queue.push(new netio_iocb(fd,len,cb_fn,cb_data)); + writeio(); + return 0; + } +}; diff --git a/judge/tool.cpp b/judge/tool.cpp new file mode 100644 index 0000000..b4a302d --- /dev/null +++ b/judge/tool.cpp @@ -0,0 +1,294 @@ +#include<string.h> +#include<dirent.h> +#include<unistd.h> +#include<fcntl.h> +#include<limits.h> +#include<ftw.h> +#include<libtar.h> +#include<bzlib.h> +#include<sys/stat.h> +#include<sys/sendfile.h> +#include<map> +#include<vector> +#include<string> + +#include"tool.h" + +static int pack_copenfn(const char *pathname,int flags,...){ + int fd; + pack_bzinfo *bzinfo; + + if((fd = open(pathname,flags,0644)) == -1){ + return -1; + } + + bzinfo = new pack_bzinfo; + bzinfo->len = 0; + bzinfo->off = 0; + bzinfo->endflag = false; + bzinfo->bzs.bzalloc = NULL; + bzinfo->bzs.bzfree = NULL; + bzinfo->bzs.opaque = NULL; + BZ2_bzCompressInit(&bzinfo->bzs,9,0,0); + + pack_fdmap.insert(std::pair<int,pack_bzinfo*>(fd,bzinfo)); + + return fd; +} +static int pack_cclosefn(long fd){ + int ret; + pack_bzinfo *bzinfo; + + bzinfo = pack_fdmap.find(fd)->second; + pack_fdmap.erase(fd); + + bzinfo->bzs.next_in = NULL; + bzinfo->bzs.avail_in = 0; + while(true){ + bzinfo->bzs.next_out = bzinfo->buf; + bzinfo->bzs.avail_out = PACK_BUFSIZE; + ret = BZ2_bzCompress(&bzinfo->bzs,BZ_FINISH); + + if(bzinfo->bzs.avail_out != PACK_BUFSIZE){ + write(fd,bzinfo->buf,PACK_BUFSIZE - bzinfo->bzs.avail_out); + } + if(ret == BZ_STREAM_END){ + break; + } + } + + BZ2_bzCompressEnd(&bzinfo->bzs); + delete bzinfo; + return close(fd); +} +static ssize_t pack_cwritefn(long fd,const void *buf,size_t count){ + pack_bzinfo *bzinfo; + + bzinfo = pack_fdmap.find(fd)->second; + + bzinfo->bzs.next_in = (char*)buf; + bzinfo->bzs.avail_in = count; + while(bzinfo->bzs.avail_in > 0){ + bzinfo->bzs.next_out = bzinfo->buf; + bzinfo->bzs.avail_out = PACK_BUFSIZE; + BZ2_bzCompress(&bzinfo->bzs,BZ_RUN); + if(bzinfo->bzs.avail_out != PACK_BUFSIZE){ + write(fd,bzinfo->buf,PACK_BUFSIZE - bzinfo->bzs.avail_out); + } + } + + return count; +} +static int pack_xopenfn(const char *pathname,int flags,...){ + int fd; + pack_bzinfo *bzinfo; + + if((fd = open(pathname,flags)) == -1){ + return -1; + } + + bzinfo = new pack_bzinfo; + bzinfo->len = 0; + bzinfo->off = 0; + bzinfo->endflag = false; + bzinfo->bzs.bzalloc = NULL; + bzinfo->bzs.bzfree = NULL; + bzinfo->bzs.opaque = NULL; + BZ2_bzDecompressInit(&bzinfo->bzs,0,0); + + pack_fdmap.insert(std::pair<int,pack_bzinfo*>(fd,bzinfo)); + + return fd; +} +static int pack_xclosefn(long fd){ + int ret; + pack_bzinfo *bzinfo; + + bzinfo = pack_fdmap.find(fd)->second; + pack_fdmap.erase(fd); + BZ2_bzDecompressEnd(&bzinfo->bzs); + delete bzinfo; + + return close(fd); +} +static ssize_t pack_xreadfn(long fd,void *buf,size_t count){ + int ret; + pack_bzinfo *bzinfo; + + bzinfo = pack_fdmap.find(fd)->second; + + bzinfo->bzs.next_out = (char*)buf; + bzinfo->bzs.avail_out = count; + while(bzinfo->endflag == false){ + if(bzinfo->len == 0){ + ret = read(fd,bzinfo->buf,PACK_BUFSIZE); + bzinfo->len = ret; + bzinfo->off = 0; + } + if(bzinfo->len == 0){ + break; + } + + bzinfo->bzs.next_in = bzinfo->buf + bzinfo->off; + bzinfo->bzs.avail_in = bzinfo->len; + while(bzinfo->bzs.avail_in > 0 && bzinfo->bzs.avail_out > 0){ + if(BZ2_bzDecompress(&bzinfo->bzs) != BZ_OK){ + bzinfo->endflag = true; + break; + } + } + bzinfo->off += bzinfo->len - bzinfo->bzs.avail_in; + bzinfo->len = bzinfo->bzs.avail_in; + + if(bzinfo->bzs.avail_out == 0){ + break; + } + } + + return count - bzinfo->bzs.avail_out; +} + +int tool_pack(char *pack_path,char *dir_path){ + tartype_t tar_type; + TAR *tarp; + char tpath[2] = {'.','\0'}; + + tar_type.openfunc = pack_copenfn; + tar_type.closefunc = pack_cclosefn; + tar_type.readfunc = (readfunc_t)read; + tar_type.writefunc = pack_cwritefn; + tar_open(&tarp,pack_path,&tar_type,O_WRONLY | O_CREAT,0644,TAR_GNU); + + tar_append_tree(tarp,dir_path,tpath); + tar_close(tarp); + + return 0; +} +int tool_unpack(char *pack_path,char *dir_path){ + tartype_t tar_type; + TAR *tarp; + + tool_cleardir(dir_path); + mkdir(dir_path,0775); + + tar_type.openfunc = pack_xopenfn; + tar_type.closefunc = pack_xclosefn; + tar_type.readfunc = pack_xreadfn; + tar_type.writefunc = (writefunc_t)write; + tar_open(&tarp,pack_path,&tar_type,O_RDONLY,0644,TAR_GNU); + + tar_extract_all(tarp,dir_path); + tar_close(tarp); + + return 0; +} + +static int cleardir_callback(const char *path,const struct stat *st,int flag,struct FTW *ftw_buf){ + if(ftw_buf->level == 0){ + return 0; + } + + if(S_ISDIR(st->st_mode)){ + rmdir(path); + }else{ + unlink(path); + } + return 0; +} +int tool_cleardir(char *path){ + nftw(path,cleardir_callback,64,FTW_DEPTH | FTW_PHYS); + return 0; +} +static int copydir_travel(char *old_path,int old_len,char *new_path,int new_len){ + int i; + int j; + int len; + + DIR *dirp; + char *buf; + dirent *entry; + std::vector<std::string> wait_list; + const char *tname; + + int infd; + int outfd; + struct stat st; + + if((dirp = opendir(old_path)) == NULL){ + return -1; + } + buf = new char[sizeof(dirent) + NAME_MAX + 1]; + + while(true){ + readdir_r(dirp,(dirent*)buf,&entry); + if(entry == NULL){ + break; + } + if(strcmp(entry->d_name,".") == 0 || strcmp(entry->d_name,"..") == 0){ + continue; + } + + if(entry->d_type == DT_DIR){ + wait_list.push_back(entry->d_name); + }else{ + old_path[old_len] = '/'; + new_path[new_len] = '/'; + len = strlen(entry->d_name); + for(i = 0;i <= len;i++){ + old_path[old_len + i + 1] = entry->d_name[i]; + new_path[new_len + i + 1] = entry->d_name[i]; + } + + infd = open(old_path,O_RDONLY); + outfd = open(new_path,O_WRONLY | O_CREAT); + fstat(infd,&st); + sendfile(outfd,infd,NULL,st.st_size); + close(infd); + close(outfd); + + old_path[old_len] = '\0'; + new_path[new_len] = '\0'; + } + } + + delete buf; + closedir(dirp); + + while(!wait_list.empty()){ + tname = wait_list.back().c_str(); + wait_list.pop_back(); + + old_path[old_len] = '/'; + new_path[new_len] = '/'; + len = strlen(tname); + for(i = 0;i <= len;i++){ + old_path[old_len + i + 1] = tname[i]; + new_path[new_len + i + 1] = tname[i]; + } + + mkdir(new_path,0775); + + copydir_travel(old_path,old_len + len + 1,new_path,new_len + len + 1); + + old_path[old_len] = '\0'; + new_path[new_len] = '\0'; + } + + return 0; +} +int tool_copydir(char *old_path,char *new_path){ + char old_buf[PATH_MAX + 1]; + char new_buf[PATH_MAX + 1]; + + tool_cleardir(new_path); + mkdir(new_path,0775); + + old_buf[0] = '\0'; + strncat(old_buf,old_path,sizeof(old_buf)); + new_buf[0] = '\0'; + strncat(new_buf,new_path,sizeof(new_buf)); + + copydir_travel(old_buf,strlen(old_buf),new_buf,strlen(new_buf)); + + return 0; +} diff --git a/judge/tool.h b/judge/tool.h new file mode 100644 index 0000000..f876c29 --- /dev/null +++ b/judge/tool.h @@ -0,0 +1,26 @@ +#define PACK_BUFSIZE 65536 +struct pack_bzinfo{ + bz_stream bzs; + char buf[PACK_BUFSIZE]; + int len; + int off; + bool endflag; +}; + +static int pack_copenfn(const char *pathname,int flags,...); +static int pack_cclosefn(long fd); +static ssize_t cpack_writefn(long fd,const void *buf,size_t count); +static int pack_xopenfn(const char *pathname,int flags,...); +static int pack_xclosefn(long fd); +static ssize_t pack_xreadfn(long fd,void *buf,size_t count); + +static std::map<int,pack_bzinfo*> pack_fdmap; + +int tool_pack(char *pack_path,char *dir_path); +int tool_unpack(char *pack_path,char *dir_path); + +static int cleardir_callback(const char *path,const struct stat *st,int flag,struct FTW *ftw_buf); +static int copydir_travel(char *old_path,int old_len,char *new_path,int new_len); + +int tool_cleardir(char *path); +int tool_copydir(char *old_path,char *new_path); diff --git a/judge/tpool.h b/judge/tpool.h new file mode 100644 index 0000000..c06efc1 --- /dev/null +++ b/judge/tpool.h @@ -0,0 +1,175 @@ +#include<pthread.h> +#include<semaphore.h> +#include<sys/eventfd.h> +#include<queue> +#include<vector> + +class tpool_protofn{ +public: + virtual void operator()(void *data) = 0; +}; + +template<typename C> +class tpool_fn : public tpool_protofn{ +private: + typedef void (C::*tpool_fn_type)(void *data); + C *obj; + tpool_fn_type fn; + +public: + tpool_fn(C *obj,tpool_fn_type fn){ + this->obj = obj; + this->fn = fn; + } + void operator()(void *data){ + (obj->*fn)(data); + } +}; +class tpool_static_fn : public tpool_protofn{ +private: + typedef void (*tpool_static_fn_type)(void *data); + tpool_static_fn_type fn; + +public: + tpool_static_fn(tpool_static_fn_type fn){ + this->fn = fn; + } + void operator()(void *data){ + fn(data); + } +}; + +class tpool_thcb{ +public: + tpool_protofn *th_fn; + void *th_data; + tpool_protofn *cb_fn; + void *cb_data; + + tpool_thcb(tpool_protofn *th_fn,void *th_data,tpool_protofn *cb_fn,void *cb_data){ + this->th_fn = th_fn; + this->th_data = th_data; + this->cb_fn = cb_fn; + this->cb_data = cb_data; + } + int run(){ + (*th_fn)(th_data); + return 0; + } + int done(){ + if(cb_fn != NULL){ + (*cb_fn)(cb_data); + } + return 0; + } +}; + +#define TPOOL_THREAD_MAXNUM 64 +class tpool{ +private: + std::queue<tpool_thcb*> wait_queue; + std::vector<tpool_thcb*> done_list; + pthread_t pt[TPOOL_THREAD_MAXNUM]; + int pt_num; + sem_t pt_sem; + pthread_mutex_t pt_mutex; + + static void* pt_runfn(void *arg){ + tpool *that; + tpool_thcb *thcb; + long long int sig; + + that = (tpool*)arg; + + while(true){ + + sem_wait(&that->pt_sem); + + pthread_mutex_lock(&that->pt_mutex); + + if(!that->wait_queue.empty()){ + thcb = that->wait_queue.front(); + that->wait_queue.pop(); + }else{ + thcb = NULL; + } + + pthread_mutex_unlock(&that->pt_mutex); + + if(thcb == NULL){ + continue; + } + + thcb->run(); + + pthread_mutex_lock(&that->pt_mutex); + + that->done_list.push_back(thcb); + + pthread_mutex_unlock(&that->pt_mutex); + + sig = 1; + write(that->fd,&sig,sizeof(sig)),that->done_list.size(); + } + return NULL; + } + +public: + int fd; + + tpool(int pt_num){ + if((this->pt_num = pt_num) > TPOOL_THREAD_MAXNUM){ + this->pt_num = TPOOL_THREAD_MAXNUM; + } + fd = eventfd(0,EFD_NONBLOCK); + sem_init(&pt_sem,0,0); + pthread_mutex_init(&pt_mutex,NULL); + } + ~tpool(){ + close(fd); + sem_destroy(&pt_sem); + pthread_mutex_destroy(&pt_mutex); + } + int start(){ + int i; + + for(i = 0;i < pt_num;i++){ + pthread_create(&pt[pt_num],NULL,pt_runfn,this); + } + + return 0; + } + int done(){ + int i; + std::vector<tpool_thcb*> l; + long long int sig; + + pthread_mutex_lock(&pt_mutex); + + l.swap(done_list); + + pthread_mutex_unlock(&pt_mutex); + + for(i = l.size() - 1;i >= 0;i--){ + l[i]->done(); + delete l[i]; + } + + read(fd,&sig,sizeof(sig)); + } + int add(tpool_protofn *th_fn,void *th_data,tpool_protofn *cb_fn,void *cb_data){ + tpool_thcb *thcb; + + thcb = new tpool_thcb(th_fn,th_data,cb_fn,cb_data); + + pthread_mutex_lock(&pt_mutex); + + wait_queue.push(thcb); + + pthread_mutex_unlock(&pt_mutex); + + sem_post(&pt_sem); + + return 0; + } +}; |