From c41f897304100c89451e91acb0a47b3f07fc7b51 Mon Sep 17 00:00:00 2001
From: lantw44 <lantw44@gmail.com>
Date: Sat, 26 Jan 2013 20:29:09 +0800
Subject: 清除所有 pthread_cancel()
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

已使用 sem_timedwait 和 sem_post 取代所有以往需要 pthread_cancel 的地方
---
 COPYING        |  2 +-
 src/checktle.c | 29 ++++++++++-------------------
 src/disptime.c | 20 +++++++++-----------
 src/main.c     |  6 ++++--
 src/mkchild.c  | 13 +++++--------
 src/sctcore.h  |  2 +-
 6 files changed, 30 insertions(+), 42 deletions(-)

diff --git a/COPYING b/COPYING
index b529e31..175bc9a 100644
--- a/COPYING
+++ b/COPYING
@@ -1,4 +1,4 @@
-Copyright (c) 2012, 藍挺瑋
+Copyright (c) 2012-2013, 藍挺瑋
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without 
diff --git a/src/checktle.c b/src/checktle.c
index 9aec3f7..461147b 100644
--- a/src/checktle.c
+++ b/src/checktle.c
@@ -17,24 +17,21 @@ volatile sig_atomic_t break_flag;
 
 static void break_handler(int signo){
 	break_flag = 1;
+	sem_post(&tlethr);
 }
 
 void* sctjudge_checktle(void* arg){
 	pid_t pidcopy;
 	long long sleeptime = (long long)(*(int*)arg) * 1000000;
 	struct sigaction break_catch;
-	struct timespec timelimit, timeinit, timecur, timetmp;
+	struct timespec timelimit, timeinit, timecur, timeexpire;
 	const struct timespec nanslparg = {0, SCT_CHECKTLE_INTERVAL};
 
 	pthread_mutex_lock(&tkill_mx);
 	tkill_yes = 1;
 	pthread_mutex_unlock(&tkill_mx);
 
-	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
-	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
-
-	sem_wait(&addthr);
-	pthread_testcancel();
+	sem_wait(&tlethr);
 	clock_gettime(CLOCK_REALTIME, &timeinit);
 
 #ifndef HAVE_CONF_CAP
@@ -54,19 +51,13 @@ 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)){
-		difftimespec(&timecur, &timelimit, &timetmp);
-		if(comparetimespec(&timetmp, &nanslparg) > 0){
-			nanosleep(&nanslparg, NULL);
-		}else{
-			nanosleep(&timetmp, NULL);
-		}
-		pthread_testcancel();
-	}
+	do{
+		clock_gettime(CLOCK_REALTIME, &timecur);
+		timeexpire.tv_sec = timecur.tv_sec;
+		timeexpire.tv_nsec = timecur.tv_nsec + SCT_CHECKTLE_INTERVAL;
+		checktimespec(&timeexpire);
+	}while(comparetimespec(&timecur, &timelimit) < 0 && 
+		sem_timedwait(&tlethr, &timeexpire));
 
 	if(!break_flag){
 		pthread_mutex_lock(&judge_tle_mx);
diff --git a/src/disptime.c b/src/disptime.c
index 9711b7c..deeee68 100644
--- a/src/disptime.c
+++ b/src/disptime.c
@@ -15,6 +15,7 @@
 void* sctjudge_displaytime(void* arg){
 	struct timespec timeinit, timecur, timepast;
 	struct timespec timesleep;
+	struct timespec timeexpire;
 
 	timesleep.tv_sec = 0;
 	timesleep.tv_nsec = (*(long*)arg);
@@ -42,11 +43,7 @@ void* sctjudge_displaytime(void* arg){
 	tdisplay_yes = 1;
 	pthread_mutex_unlock(&tdisplay_mx);
 
-	pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
-	pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
-
-	sem_wait(&addthr);
-	pthread_testcancel();
+	sem_wait(&dispthr);
 
 #ifndef HAVE_CONF_CAP
 	enable_setuid();
@@ -65,10 +62,7 @@ void* sctjudge_displaytime(void* arg){
 	sprintf(statusfile, PROC_PATH"/%d/status", pidcopy);
 #endif
 
-	pthread_testcancel();
-
-	while(1){
-		pthread_testcancel();
+	do{
 		clock_gettime(CLOCK_REALTIME, &timecur);
 		difftimespec(&timeinit, &timecur, &timepast);
 		printf("\r%4ld.%03ld 秒", timepast.tv_sec,
@@ -139,8 +133,12 @@ void* sctjudge_displaytime(void* arg){
 		firstrun = 0;
 #endif
 		fflush(stdout);
-		nanosleep(&timesleep, NULL);
-	}
+
+		clock_gettime(CLOCK_REALTIME, &timecur);
+		timeexpire.tv_sec = timecur.tv_sec + timesleep.tv_sec;
+		timeexpire.tv_nsec = timecur.tv_nsec + timesleep.tv_nsec;
+		checktimespec(&timeexpire);
+	}while(sem_timedwait(&dispthr, &timeexpire));
 
 	pthread_mutex_lock(&tdisplay_mx);
 	tdisplay_yes = 0;
diff --git a/src/main.c b/src/main.c
index d46c4c3..eabf764 100644
--- a/src/main.c
+++ b/src/main.c
@@ -418,7 +418,8 @@ int main(int argc, char* argv[]){
 	pthread_mutex_init(&tdisplay_mx, NULL);
 	pthread_mutex_init(&judge_tle_mx, NULL);
 	sem_init(&mcthr, 0, 0);
-	sem_init(&addthr, 0, 0);
+	sem_init(&tlethr, 0, 0);
+	sem_init(&dispthr, 0, 0);
 	pthread_create(&tmain, &joistate, &sctjudge_makechild, (void*)&mcopt);
 	if(!dryrun){
 		pthread_create(&tkill, &detstate, &sctjudge_checktle, 
@@ -439,7 +440,8 @@ int main(int argc, char* argv[]){
 	pthread_mutex_destroy(&tdisplay_mx);
 
 	sem_destroy(&mcthr);
-	sem_destroy(&addthr);
+	sem_destroy(&tlethr);
+	sem_destroy(&dispthr);
 
 	if(dryrun){
 		return SCTEXIT_SUCCESS;
diff --git a/src/mkchild.c b/src/mkchild.c
index fe2ee8c..3f754a7 100644
--- a/src/mkchild.c
+++ b/src/mkchild.c
@@ -72,7 +72,7 @@ pid_t pidchild;
 pthread_mutex_t pidmutex, tkill_mx, tdisplay_mx, judge_tle_mx;
 pthread_t tkill, tdisplay;
 char tkill_yes = 0, tdisplay_yes = 0, judge_tle = 0;
-sem_t mcthr, addthr;
+sem_t mcthr, tlethr, dispthr;
 
 static const char* childmsg_text[SCTCHILD_MSGMAX] = {
 	"開啟輸入檔案",
@@ -99,7 +99,7 @@ static void sctjudge_makechild_cleanup_p1(void){
 	if(tkill_yes){
 		tkill_yes = 0;
 		pthread_mutex_unlock(&tkill_mx);
-		pthread_cancel(tkill);
+		sem_post(&tlethr);
 	}else{
 		pthread_mutex_unlock(&tkill_mx);
 	}
@@ -108,14 +108,11 @@ static void sctjudge_makechild_cleanup_p1(void){
 	if(tdisplay_yes){
 		tdisplay_yes = 0;
 		pthread_mutex_unlock(&tdisplay_mx);
-		pthread_cancel(tdisplay);
+		sem_post(&dispthr);
 	}else{
 		pthread_mutex_unlock(&tdisplay_mx);
 	}
 
-	/* 這基本上應該是可以去掉的,sem_wait() 也是 cancellation point */
-	sem_post(&addthr);
-	sem_post(&addthr);
 }
 	
 static void sctjudge_makechild_cleanup_p2(mcopt, oldperm, copiedexe)
@@ -429,8 +426,8 @@ void* sctjudge_makechild(void* arg){
 
 		/* 現在我們確定受測程式已經在執行了,所以需要記錄一下時間
 		 * 通知其他 thread */
-		sem_post(&addthr);
-		sem_post(&addthr);
+		sem_post(&tlethr);
+		sem_post(&dispthr);
 
 		/* 開始要 wait 了,莫名其妙 stop 的程式我最多只會送
 		 * 5 次 SIGCONT 給你(避免進入無限迴圈) 
diff --git a/src/sctcore.h b/src/sctcore.h
index 98bbda5..13c8783 100644
--- a/src/sctcore.h
+++ b/src/sctcore.h
@@ -21,7 +21,7 @@ extern char tkill_yes, tdisplay_yes;
 extern pthread_mutex_t tkill_mx, tdisplay_mx;
 
 /* 用來讓另外兩個 thread 卡住的 semaphore */
-extern sem_t mcthr, addthr;
+extern sem_t mcthr, tlethr, dispthr;
 
 /* 判斷有無 TLE,此變數由 sctjudge_checktle 設定 */
 extern char judge_tle;
-- 
cgit