aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2012-11-14 09:44:26 +0800
committerLAN-TW <lantw44@gmail.com>2012-11-14 09:50:06 +0800
commita0a8496f1e04dc964e29cc4661193e92662eaffd (patch)
tree658e3c09a6d4ba9f3677e2a3e692ac3a4103ed72
parenta7aee0e7423dfe23bd562f1f0f0a981bfbb2ff17 (diff)
downloadsctjudge-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.c6
-rw-r--r--src/disptime.c6
-rw-r--r--src/main.c5
-rw-r--r--src/mkchild.c8
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,
diff --git a/src/main.c b/src/main.c
index bee7c30..d46c4c3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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 給你(避免進入無限迴圈)