diff options
author | LAN-TW <lantw44@gmail.com> | 2012-11-14 09:44:26 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2012-11-14 09:50:06 +0800 |
commit | a0a8496f1e04dc964e29cc4661193e92662eaffd (patch) | |
tree | 658e3c09a6d4ba9f3677e2a3e692ac3a4103ed72 | |
parent | a7aee0e7423dfe23bd562f1f0f0a981bfbb2ff17 (diff) | |
download | sctjudge-a0a8496f1e04dc964e29cc4661193e92662eaffd.tar.gz sctjudge-a0a8496f1e04dc964e29cc4661193e92662eaffd.tar.zst sctjudge-a0a8496f1e04dc964e29cc4661193e92662eaffd.zip |
去除所有 PTHREAD_CANCEL_ASYNCHRONOUS 以避免中斷位置不正確造成問題
解決此已知問題:在 FreeBSD 上如果受測程式太快結束,有機會導致本程式無法結束。
目前的做法事都先改成 PTHREAD_CANCEL_DEFERRED 並加入 cancel point,但我在想之
後應該要想辦法把所有 pthread_cancel() 都去掉。
-rw-r--r-- | src/checktle.c | 6 | ||||
-rw-r--r-- | src/disptime.c | 6 | ||||
-rw-r--r-- | src/main.c | 5 | ||||
-rw-r--r-- | src/mkchild.c | 8 |
4 files changed, 18 insertions, 7 deletions
diff --git a/src/checktle.c b/src/checktle.c index 0651ddf..9aec3f7 100644 --- a/src/checktle.c +++ b/src/checktle.c @@ -31,9 +31,10 @@ void* sctjudge_checktle(void* arg){ pthread_mutex_unlock(&tkill_mx); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); sem_wait(&addthr); + pthread_testcancel(); clock_gettime(CLOCK_REALTIME, &timeinit); #ifndef HAVE_CONF_CAP @@ -53,6 +54,8 @@ void* sctjudge_checktle(void* arg){ timelimit.tv_sec = timeinit.tv_sec + sleeptime / 1000000000; timelimit.tv_nsec = timeinit.tv_nsec + sleeptime % 1000000000; + pthread_testcancel(); + for(clock_gettime(CLOCK_REALTIME, &timecur); comparetimespec(&timecur, &timelimit) < 0 && !break_flag; clock_gettime(CLOCK_REALTIME, &timecur)){ @@ -62,6 +65,7 @@ void* sctjudge_checktle(void* arg){ }else{ nanosleep(&timetmp, NULL); } + pthread_testcancel(); } if(!break_flag){ diff --git a/src/disptime.c b/src/disptime.c index 2448e11..9711b7c 100644 --- a/src/disptime.c +++ b/src/disptime.c @@ -43,9 +43,10 @@ void* sctjudge_displaytime(void* arg){ pthread_mutex_unlock(&tdisplay_mx); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); + pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); sem_wait(&addthr); + pthread_testcancel(); #ifndef HAVE_CONF_CAP enable_setuid(); @@ -64,7 +65,10 @@ void* sctjudge_displaytime(void* arg){ sprintf(statusfile, PROC_PATH"/%d/status", pidcopy); #endif + pthread_testcancel(); + while(1){ + pthread_testcancel(); clock_gettime(CLOCK_REALTIME, &timecur); difftimespec(&timeinit, &timecur, &timepast); printf("\r%4ld.%03ld 秒", timepast.tv_sec, @@ -432,14 +432,15 @@ int main(int argc, char* argv[]){ pthread_attr_destroy(&joistate); sem_post(&mcthr); - /* 這個 semaphore 到這裡就沒用了, - * sctjudge_makechild 一旦開始動就會把它 destroy 掉 */ pthread_join(tmain, (void**)&mtreturn); /* XXX 底下這訊息很有可能讓使用者覺得很奇怪 */ pthread_mutex_destroy(&pidmutex); pthread_mutex_destroy(&tkill_mx); pthread_mutex_destroy(&tdisplay_mx); + sem_destroy(&mcthr); + sem_destroy(&addthr); + if(dryrun){ return SCTEXIT_SUCCESS; } diff --git a/src/mkchild.c b/src/mkchild.c index 3325632..ee370f5 100644 --- a/src/mkchild.c +++ b/src/mkchild.c @@ -95,6 +95,10 @@ static const char* childmsg_text[SCTCHILD_MSGMAX] = { }; static void sctjudge_makechild_cleanup_p1(void){ + /* 避免有 thread 卡在 sem 上砍不掉 */ + sem_post(&addthr); + sem_post(&addthr); + pthread_mutex_lock(&tkill_mx); if(tkill_yes){ tkill_yes = 0; @@ -273,7 +277,6 @@ static int read_size(int fd, void* buf, size_t count){ void* sctjudge_makechild(void* arg){ /* 首先等所有 thread 都啟動完成再開始動作 */ sem_wait(&mcthr); - sem_destroy(&mcthr); /* 宣告變數囉! */ int i; @@ -425,10 +428,9 @@ void* sctjudge_makechild(void* arg){ close(childpipe[0]); /* 現在我們確定受測程式已經在執行了,所以需要記錄一下時間 - * 通知其他 thread,然後就可以把 semaphore 丟掉了 */ + * 通知其他 thread */ sem_post(&addthr); sem_post(&addthr); - sem_destroy(&addthr); /* 開始要 wait 了,莫名其妙 stop 的程式我最多只會送 * 5 次 SIGCONT 給你(避免進入無限迴圈) |