If a thread is removed from umtxq while sleeping, reset error code

to zero, this gives userland a better indication that a thread needn't
to be cancelled.
This commit is contained in:
David Xu 2010-08-25 03:14:32 +00:00
parent 253953cd5b
commit df7442533c
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=211794

View File

@ -1059,8 +1059,10 @@ do_wait(struct thread *td, void *addr, u_long id,
umtxq_lock(&uq->uq_key); umtxq_lock(&uq->uq_key);
for (;;) { for (;;) {
error = umtxq_sleep(uq, "uwait", tvtohz(&tv)); error = umtxq_sleep(uq, "uwait", tvtohz(&tv));
if (!(uq->uq_flags & UQF_UMTXQ)) if (!(uq->uq_flags & UQF_UMTXQ)) {
error = 0;
break; break;
}
if (error != ETIMEDOUT) if (error != ETIMEDOUT)
break; break;
umtxq_unlock(&uq->uq_key); umtxq_unlock(&uq->uq_key);
@ -2404,25 +2406,14 @@ do_cv_wait(struct thread *td, struct ucond *cv, struct umutex *m,
} }
} }
if (error != 0) { if ((uq->uq_flags & UQF_UMTXQ) == 0)
if ((uq->uq_flags & UQF_UMTXQ) == 0) {
/*
* If we concurrently got do_cv_signal()d
* and we got an error or UNIX signals or a timeout,
* then, perform another umtxq_signal to avoid
* consuming the wakeup. This may cause supurious
* wakeup for another thread which was just queued,
* but SUSV3 explicitly allows supurious wakeup to
* occur, and indeed a kernel based implementation
* can not avoid it.
*/
if (!umtxq_signal(&uq->uq_key, 1))
error = 0; error = 0;
} else {
umtxq_remove(uq);
if (error == ERESTART) if (error == ERESTART)
error = EINTR; error = EINTR;
} }
umtxq_remove(uq);
umtxq_unlock(&uq->uq_key); umtxq_unlock(&uq->uq_key);
umtx_key_release(&uq->uq_key); umtx_key_release(&uq->uq_key);
return (error); return (error);
@ -2891,15 +2882,13 @@ do_sem_wait(struct thread *td, struct _usem *sem, struct timespec *timeout)
} }
} }
if (error != 0) { if ((uq->uq_flags & UQF_UMTXQ) == 0)
if ((uq->uq_flags & UQF_UMTXQ) == 0) {
if (!umtxq_signal(&uq->uq_key, 1))
error = 0; error = 0;
} else {
umtxq_remove(uq);
if (error == ERESTART) if (error == ERESTART)
error = EINTR; error = EINTR;
} }
umtxq_remove(uq);
umtxq_unlock(&uq->uq_key); umtxq_unlock(&uq->uq_key);
umtx_key_release(&uq->uq_key); umtx_key_release(&uq->uq_key);
return (error); return (error);