Date: Mon, 8 Nov 2010 00:38:54 +0000 (UTC) From: David Xu <davidxu@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r214966 - user/davidxu/libthr/lib/libthr/thread Message-ID: <201011080038.oA80cswJ097754@svn.freebsd.org>
index | next in thread | raw e-mail
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 {help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201011080038.oA80cswJ097754>
