From 22a81fc246efb2668eddcb6ccd27129feaa5910c Mon Sep 17 00:00:00 2001 From: davidxu Date: Mon, 4 Dec 2006 14:15:12 +0000 Subject: if a thread blocked on userland condition variable is pthread_cancel()ed, it is expected that the thread will not consume a pthread_cond_signal(), therefor, we use thr_wake() to mark a flag, the flag tells a thread calling do_cv_wait() in umtx code to not block on a condition variable. Thread library is expected that once a thread detected itself is in pthread_cond_wait, it will call the thr_wake() for itself in its SIGCANCEL handler. --- sys/kern/kern_thr.c | 11 +++++++++++ sys/kern/kern_umtx.c | 15 ++++++++++----- sys/sys/proc.h | 1 + sys/sys/umtx.h | 3 +++ 4 files changed, 25 insertions(+), 5 deletions(-) (limited to 'sys') diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index 29c7614..37e3df2 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -402,6 +402,12 @@ kern_thr_suspend(struct thread *td, struct timespec *tsp) TIMESPEC_TO_TIMEVAL(&tv, tsp); hz = tvtohz(&tv); } + + if (td->td_pflags & TDP_WAKEUP) { + td->td_pflags &= ~TDP_WAKEUP; + return (0); + } + PROC_LOCK(td->td_proc); if ((td->td_flags & TDF_THRWAKEUP) == 0) error = msleep((void *)td, &td->td_proc->p_mtx, PCATCH, "lthr", @@ -430,6 +436,11 @@ thr_wake(struct thread *td, struct thr_wake_args *uap) struct proc *p; struct thread *ttd; + if (uap->id == td->td_tid) { + td->td_pflags |= TDP_WAKEUP; + return (0); + } + p = td->td_proc; PROC_LOCK(p); ttd = thread_find(p, uap->id); diff --git a/sys/kern/kern_umtx.c b/sys/kern/kern_umtx.c index 89faec8..328fb57 100644 --- a/sys/kern/kern_umtx.c +++ b/sys/kern/kern_umtx.c @@ -2170,7 +2170,7 @@ do_unlock_umutex(struct thread *td, struct umutex *m) static int do_cv_wait(struct thread *td, struct ucond *cv, struct umutex *m, - struct timespec *timeout) + struct timespec *timeout, u_long wflags) { struct umtx_q *uq; struct timeval tv; @@ -2202,7 +2202,11 @@ do_cv_wait(struct thread *td, struct ucond *cv, struct umutex *m, umtxq_lock(&uq->uq_key); if (error == 0) { - if (timeout == NULL) { + if ((wflags & UMTX_CHECK_UNPARKING) && + (td->td_pflags & TDP_WAKEUP)) { + td->td_pflags &= ~TDP_WAKEUP; + error = EINTR; + } else if (timeout == NULL) { error = umtxq_sleep(uq, "ucond", 0); } else { getnanouptime(&ets); @@ -2236,7 +2240,8 @@ do_cv_wait(struct thread *td, struct ucond *cv, struct umutex *m, * occur, and indeed a kernel based implementation * can not avoid it. */ - umtxq_signal(&uq->uq_key, 1); + if (!umtxq_signal(&uq->uq_key, 1)) + error = 0; } if (error == ERESTART) error = EINTR; @@ -2431,7 +2436,7 @@ __umtx_op_cv_wait(struct thread *td, struct _umtx_op_args *uap) } ts = &timeout; } - return (do_cv_wait(td, uap->obj, uap->uaddr1, ts)); + return (do_cv_wait(td, uap->obj, uap->uaddr1, ts, uap->val)); } static int @@ -2592,7 +2597,7 @@ __umtx_op_cv_wait_compat32(struct thread *td, struct _umtx_op_args *uap) return (EINVAL); ts = &timeout; } - return (do_cv_wait(td, uap->obj, uap->uaddr1, ts)); + return (do_cv_wait(td, uap->obj, uap->uaddr1, ts, uap->val)); } static _umtx_op_func op_table_compat32[] = { diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 454982a..99dbfc6 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -455,6 +455,7 @@ struct thread { #define TDP_GEOM 0x00010000 /* Settle GEOM before finishing syscall */ #define TDP_SOFTDEP 0x00020000 /* Stuck processing softdep worklist */ #define TDP_NORUNNINGBUF 0x00040000 /* Ignore runningbufspace check */ +#define TDP_WAKEUP 0x00080000 /* Don't sleep in umtx cond_wait */ /* * Reasons that the current thread can not be run yet. diff --git a/sys/sys/umtx.h b/sys/sys/umtx.h index cfcf740..e7e534a 100644 --- a/sys/sys/umtx.h +++ b/sys/sys/umtx.h @@ -80,6 +80,9 @@ struct ucond { #define UMTX_OP_CV_BROADCAST 10 #define UMTX_OP_MAX 11 +/* flags for UMTX_OP_CV_WAIT */ +#define UMTX_CHECK_UNPARKING 0x01 + #ifndef _KERNEL int _umtx_op(void *obj, int op, u_long val, void *uaddr, void *uaddr2); -- cgit v1.1