Browse Source

for SIGEV_THREAD timer threads, replace signal handler with sigwaitinfo

this eliminates some ugly hacks that were repurposing the start
function and start argument fields in the pthread structure for timer
use, and the need to longjmp out of a signal handler.
Rich Felker 6 năm trước cách đây
mục cha
commit
5b74eed3b3
2 tập tin đã thay đổi với 16 bổ sung21 xóa
  1. 15 20
      src/time/timer_create.c
  2. 1 1
      src/time/timer_delete.c

+ 15 - 20
src/time/timer_create.c

@@ -34,16 +34,6 @@ static void cleanup_fromsig(void *p)
 
 
 static void timer_handler(int sig, siginfo_t *si, void *ctx)
 static void timer_handler(int sig, siginfo_t *si, void *ctx)
 {
 {
-	pthread_t self = __pthread_self();
-	jmp_buf jb;
-	void (*notify)(union sigval) = (void (*)(union sigval))self->start;
-	union sigval val = { .sival_ptr = self->start_arg };
-
-	if (!setjmp(jb) && si->si_code == SI_TIMER) {
-		pthread_cleanup_push(cleanup_fromsig, jb);
-		notify(val);
-		pthread_cleanup_pop(1);
-	}
 }
 }
 
 
 static void install_handler()
 static void install_handler()
@@ -59,20 +49,24 @@ static void *start(void *arg)
 {
 {
 	pthread_t self = __pthread_self();
 	pthread_t self = __pthread_self();
 	struct start_args *args = arg;
 	struct start_args *args = arg;
-	int id;
+	int id = self->timer_id;
+	jmp_buf jb;
 
 
-	/* Reuse no-longer-needed thread structure fields to avoid
-	 * needing the timer address in the signal handler. */
-	self->start = (void *(*)(void *))args->sev->sigev_notify_function;
-	self->start_arg = args->sev->sigev_value.sival_ptr;
+	void (*notify)(union sigval) = args->sev->sigev_notify_function;
+	union sigval val = args->sev->sigev_value;
 
 
 	pthread_barrier_wait(&args->b);
 	pthread_barrier_wait(&args->b);
-	if ((id = self->timer_id) >= 0) {
-		__syscall(SYS_rt_sigprocmask, SIG_UNBLOCK,
-			SIGTIMER_SET, 0, _NSIG/8);
-		__wait(&self->timer_id, 0, id, 1);
-		__syscall(SYS_timer_delete, id);
+	for (;;) {
+		siginfo_t si;
+		while (sigwaitinfo(SIGTIMER_SET, &si) < 0);
+		if (si.si_code == SI_TIMER && !setjmp(jb)) {
+			pthread_cleanup_push(cleanup_fromsig, jb);
+			notify(val);
+			pthread_cleanup_pop(1);
+		}
+		if (self->timer_id < 0) break;
 	}
 	}
+	__syscall(SYS_timer_delete, id);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -112,6 +106,7 @@ int timer_create(clockid_t clk, struct sigevent *restrict evp, timer_t *restrict
 		args.sev = evp;
 		args.sev = evp;
 
 
 		__block_app_sigs(&set);
 		__block_app_sigs(&set);
+		__syscall(SYS_rt_sigprocmask, SIG_BLOCK, SIGTIMER_SET, 0, _NSIG/8);
 		r = pthread_create(&td, &attr, start, &args);
 		r = pthread_create(&td, &attr, start, &args);
 		__restore_sigs(&set);
 		__restore_sigs(&set);
 		if (r) {
 		if (r) {

+ 1 - 1
src/time/timer_delete.c

@@ -7,7 +7,7 @@ int timer_delete(timer_t t)
 	if ((intptr_t)t < 0) {
 	if ((intptr_t)t < 0) {
 		pthread_t td = (void *)((uintptr_t)t << 1);
 		pthread_t td = (void *)((uintptr_t)t << 1);
 		a_store(&td->timer_id, td->timer_id | INT_MIN);
 		a_store(&td->timer_id, td->timer_id | INT_MIN);
-		__wake(&td->timer_id, 1, 1);
+		__syscall(SYS_tkill, td->tid, SIGTIMER);
 		return 0;
 		return 0;
 	}
 	}
 	return __syscall(SYS_timer_delete, t);
 	return __syscall(SYS_timer_delete, t);