svn commit: r214966 - user/davidxu/libthr/lib/libthr/thread
David Xu
davidxu at FreeBSD.org
Mon Nov 8 00:38:54 UTC 2010
Author: davidxu
Date: Mon Nov 8 00:38:54 2010
New Revision: 214966
URL: http://svn.freebsd.org/changeset/base/214966
Log:
Create seperated function cond_broadcast_comm and cond_signal_common.
Add c_destorying and c_refcount fields, so that condition varible can
be safely destroyed after pthread_cond_broadcast(), this is required by
POSIX.
Modified:
user/davidxu/libthr/lib/libthr/thread/thr_cond.c
user/davidxu/libthr/lib/libthr/thread/thr_private.h
Modified: user/davidxu/libthr/lib/libthr/thread/thr_cond.c
==============================================================================
--- user/davidxu/libthr/lib/libthr/thread/thr_cond.c Mon Nov 8 00:26:49 2010 (r214965)
+++ user/davidxu/libthr/lib/libthr/thread/thr_cond.c Mon Nov 8 00:38:54 2010 (r214966)
@@ -45,7 +45,8 @@ int __pthread_cond_timedwait(pthread_con
static int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
static int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime, int cancel);
-static int cond_signal_common(pthread_cond_t *cond, int broadcast);
+static int cond_signal_common(struct pthread_cond *cond);
+static int cond_broadcast_common(struct pthread_cond *cond);
/*
* Double underscore versions are cancellation points. Single underscore
@@ -139,8 +140,22 @@ _pthread_cond_destroy(pthread_cond_t *co
rval = EINVAL;
else {
cv = *cond;
- if (cv->c_waiters != 0)
- return (EBUSY);
+ _thr_umtx_lock_spin(&cv->c_lock);
+ while (cv->c_refcount != 0) {
+ cv->c_destroying = 1;
+ if (cv->c_waiters > 0) {
+ cv->c_seq++;
+ cv->c_broadcast_seq++;
+ cv->c_waiters = 0;
+ cv->c_signals = 0;
+ _thr_umtx_wake(&cv->c_seq, INT_MAX, CV_PSHARED(cv));
+ }
+ _thr_umtx_unlock(&cv->c_lock);
+ _thr_umtx_wait_uint((u_int *)&cv->c_destroying,
+ 1, NULL, CV_PSHARED(cv));
+ _thr_umtx_lock_spin(&cv->c_lock);
+ }
+ _thr_umtx_unlock(&cv->c_lock);
_thr_ucond_broadcast(&cv->c_kerncv);
*cond = THR_COND_DESTROYED;
@@ -221,6 +236,10 @@ cond_wait_user(pthread_cond_t *cond, pth
cv = *cond;
_thr_umtx_lock_spin(&cv->c_lock);
+ if (cv->c_destroying) {
+ _thr_umtx_unlock(&cv->c_lock);
+ return (EINVAL);
+ }
cv->c_waiters++;
error = _mutex_cv_unlock(mutex, &recurse);
if (__predict_false(error != 0)) {
@@ -230,6 +249,7 @@ cond_wait_user(pthread_cond_t *cond, pth
}
bseq = cv->c_broadcast_seq;
+ cv->c_refcount++;
for(;;) {
seq = cv->c_seq;
_thr_umtx_unlock(&cv->c_lock);
@@ -253,30 +273,41 @@ cond_wait_user(pthread_cond_t *cond, pth
_thr_umtx_lock_spin(&cv->c_lock);
if (cv->c_broadcast_seq != bseq) {
+ cv->c_refcount--;
error = 0;
break;
}
- if (cv->c_signaled > 0) {
- cv->c_signaled--;
+ if (cv->c_signals > 0) {
+ cv->c_refcount--;
+ cv->c_signals--;
error = 0;
break;
} else if (error == ETIMEDOUT) {
+ cv->c_refcount--;
cv->c_waiters--;
break;
} else if (cancel && SHOULD_CANCEL(curthread) &&
!THR_IN_CRITICAL(curthread)) {
cv->c_waiters--;
+ cv->c_refcount--;
+ if (cv->c_destroying && cv->c_refcount == 0) {
+ cv->c_destroying = 2;
+ _thr_umtx_wake(&cv->c_destroying, INT_MAX, CV_PSHARED(cv));
+ }
_thr_umtx_unlock(&cv->c_lock);
_mutex_cv_lock(mutex, recurse);
_pthread_exit(PTHREAD_CANCELED);
}
}
+ if (cv->c_destroying && cv->c_refcount == 0) {
+ cv->c_destroying = 2;
+ _thr_umtx_wake(&cv->c_destroying, INT_MAX, CV_PSHARED(cv));
+ }
_thr_umtx_unlock(&cv->c_lock);
_mutex_cv_lock(mutex, recurse);
return (error);
}
-
static int
cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec *abstime, int cancel)
@@ -356,38 +387,40 @@ __pthread_cond_timedwait(pthread_cond_t
}
static int
-cond_signal_common(pthread_cond_t *cond, int broadcast)
+cond_signal_common(struct pthread_cond *cv)
{
- pthread_cond_t cv;
- /*
- * If the condition variable is statically initialized, perform dynamic
- * initialization.
- */
- CHECK_AND_INIT_COND
+ _thr_ucond_signal(&cv->c_kerncv);
- if (!broadcast)
- _thr_ucond_signal(&cv->c_kerncv);
- else
- _thr_ucond_broadcast(&cv->c_kerncv);
+ if (cv->c_waiters == 0)
+ return (0);
+
+ _thr_umtx_lock_spin(&cv->c_lock);
+ if (cv->c_waiters > 0) {
+ cv->c_seq++;
+ cv->c_signals++;
+ cv->c_waiters--;
+ _thr_umtx_wake(&cv->c_seq, 1, CV_PSHARED(cv));
+ }
+ _thr_umtx_unlock(&cv->c_lock);
+ return (0);
+}
+
+static int
+cond_broadcast_common(struct pthread_cond *cv)
+{
+ _thr_ucond_broadcast(&cv->c_kerncv);
if (cv->c_waiters == 0)
return (0);
_thr_umtx_lock_spin(&cv->c_lock);
if (cv->c_waiters > 0) {
- if (!broadcast) {
- cv->c_seq++;
- cv->c_signaled++;
- cv->c_waiters--;
- _thr_umtx_wake(&cv->c_seq, 1, CV_PSHARED(cv));
- } else {
- cv->c_seq++;
- cv->c_broadcast_seq++;
- cv->c_waiters = 0;
- cv->c_signaled = 0;
- _thr_umtx_wake(&cv->c_seq, INT_MAX, CV_PSHARED(cv));
- }
+ cv->c_seq++;
+ cv->c_broadcast_seq++;
+ cv->c_waiters = 0;
+ cv->c_signals = 0;
+ _thr_umtx_wake(&cv->c_seq, INT_MAX, CV_PSHARED(cv));
}
_thr_umtx_unlock(&cv->c_lock);
return (0);
@@ -396,13 +429,27 @@ cond_signal_common(pthread_cond_t *cond,
int
_pthread_cond_signal(pthread_cond_t * cond)
{
+ pthread_cond_t cv;
- return (cond_signal_common(cond, 0));
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ CHECK_AND_INIT_COND
+
+ return (cond_signal_common(cv));
}
int
_pthread_cond_broadcast(pthread_cond_t * cond)
{
+ pthread_cond_t cv;
+
+ /*
+ * If the condition variable is statically initialized, perform dynamic
+ * initialization.
+ */
+ CHECK_AND_INIT_COND
- return (cond_signal_common(cond, 1));
+ return (cond_broadcast_common(cv));
}
Modified: user/davidxu/libthr/lib/libthr/thread/thr_private.h
==============================================================================
--- user/davidxu/libthr/lib/libthr/thread/thr_private.h Mon Nov 8 00:26:49 2010 (r214965)
+++ user/davidxu/libthr/lib/libthr/thread/thr_private.h Mon Nov 8 00:38:54 2010 (r214966)
@@ -166,9 +166,11 @@ struct pthread_cond {
*/
uint32_t c_lock;
int c_waiters;
- int c_signaled;
+ int c_signals;
uint32_t c_seq;
uint64_t c_broadcast_seq;
+ int c_refcount;
+ int c_destroying;
};
struct pthread_cond_attr {
More information about the svn-src-user
mailing list