diff options
author | davidxu <davidxu@FreeBSD.org> | 2010-12-22 05:01:52 +0000 |
---|---|---|
committer | davidxu <davidxu@FreeBSD.org> | 2010-12-22 05:01:52 +0000 |
commit | 437ad27f9c81f522301de0affe1fc5fef37d8828 (patch) | |
tree | d717e6b5f295c555e1deef8497d4130bec1843cf /lib/libthr/thread/thr_umtx.c | |
parent | 24b08bca030970592bc5241517b0462f603b05b1 (diff) | |
download | FreeBSD-src-437ad27f9c81f522301de0affe1fc5fef37d8828.zip FreeBSD-src-437ad27f9c81f522301de0affe1fc5fef37d8828.tar.gz |
MFp4:
- Add flags CVWAIT_ABSTIME and CVWAIT_CLOCKID for umtx kernel based
condition variable, this should eliminate an extra system call to get
current time.
- Add sub-function UMTX_OP_NWAKE_PRIVATE to wake up N channels in single
system call. Create userland sleep queue for condition variable, in most
cases, thread will wait in the queue, the pthread_cond_signal will defer
thread wakeup until the mutex is unlocked, it tries to avoid an extra
system call and a extra context switch in time window of pthread_cond_signal
and pthread_mutex_unlock.
The changes are part of process-shared mutex project.
Diffstat (limited to 'lib/libthr/thread/thr_umtx.c')
-rw-r--r-- | lib/libthr/thread/thr_umtx.c | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/lib/libthr/thread/thr_umtx.c b/lib/libthr/thread/thr_umtx.c index dabfa35..33c3637 100644 --- a/lib/libthr/thread/thr_umtx.c +++ b/lib/libthr/thread/thr_umtx.c @@ -74,6 +74,39 @@ __thr_umutex_lock(struct umutex *mtx, uint32_t id) return _umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0, 0, 0); } +#define SPINLOOPS 1000 + +int +__thr_umutex_lock_spin(struct umutex *mtx, uint32_t id) +{ + uint32_t owner; + + if (!_thr_is_smp) + return __thr_umutex_lock(mtx, id); + + if ((mtx->m_flags & (UMUTEX_PRIO_PROTECT | UMUTEX_PRIO_INHERIT)) == 0) { + for (;;) { + int count = SPINLOOPS; + while (count--) { + owner = mtx->m_owner; + if ((owner & ~UMUTEX_CONTESTED) == 0) { + if (atomic_cmpset_acq_32( + &mtx->m_owner, + owner, id|owner)) { + return (0); + } + } + CPU_SPINWAIT; + } + + /* wait in kernel */ + _umtx_op_err(mtx, UMTX_OP_MUTEX_WAIT, 0, 0, 0); + } + } + + return _umtx_op_err(mtx, UMTX_OP_MUTEX_LOCK, 0, 0, 0); +} + int __thr_umutex_timedlock(struct umutex *mtx, uint32_t id, const struct timespec *ets) @@ -164,6 +197,26 @@ _thr_umtx_wait_uint(volatile u_int *mtx, u_int id, const struct timespec *timeou } int +_thr_umtx_timedwait_uint(volatile u_int *mtx, u_int id, int clockid, + const struct timespec *abstime, int shared) +{ + struct timespec ts, ts2, *tsp; + + if (abstime != NULL) { + clock_gettime(clockid, &ts); + TIMESPEC_SUB(&ts2, abstime, &ts); + if (ts2.tv_sec < 0 || ts2.tv_nsec <= 0) + return (ETIMEDOUT); + tsp = &ts2; + } else { + tsp = NULL; + } + return _umtx_op_err(__DEVOLATILE(void *, mtx), + shared ? UMTX_OP_WAIT_UINT : UMTX_OP_WAIT_UINT_PRIVATE, id, NULL, + tsp); +} + +int _thr_umtx_wake(volatile void *mtx, int nr_wakeup, int shared) { return _umtx_op_err(__DEVOLATILE(void *, mtx), shared ? UMTX_OP_WAKE : UMTX_OP_WAKE_PRIVATE, |