|
|
@ -114,16 +114,30 @@ bool ck_completion_timeout(void *fn, void *fnarg, int timeout) |
|
|
|
return !ret; |
|
|
|
return !ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int _cond_wait(pthread_cond_t *cond, mutex_t *lock, const char *file, const char *func, const int line) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
/* Place holders for when we add lock debugging */ |
|
|
|
ret = pthread_cond_wait(cond, &lock->mutex); |
|
|
|
#define GETLOCK(_lock, _file, _func, _line) |
|
|
|
lock->file = file; |
|
|
|
#define GOTLOCK(_lock, _file, _func, _line) |
|
|
|
lock->func = func; |
|
|
|
#define TRYLOCK(_lock, _file, _func, _line) |
|
|
|
lock->line = line; |
|
|
|
#define DIDLOCK(_ret, _lock, _file, _func, _line) |
|
|
|
return ret; |
|
|
|
#define GUNLOCK(_lock, _file, _func, _line) |
|
|
|
} |
|
|
|
#define INITLOCK(_typ, _lock, _file, _func, _line) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int _mutex_timedlock(pthread_mutex_t *lock, int timeout, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line) |
|
|
|
int _cond_timedwait(pthread_cond_t *cond, mutex_t *lock, const struct timespec *abstime, const char *file, const char *func, const int line) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ret = pthread_cond_timedwait(cond, &lock->mutex, abstime); |
|
|
|
|
|
|
|
lock->file = file; |
|
|
|
|
|
|
|
lock->func = func; |
|
|
|
|
|
|
|
lock->line = line; |
|
|
|
|
|
|
|
return ret; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int _mutex_timedlock(mutex_t *lock, int timeout, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
tv_t now; |
|
|
|
tv_t now; |
|
|
|
ts_t abs; |
|
|
|
ts_t abs; |
|
|
@ -133,53 +147,63 @@ int _mutex_timedlock(pthread_mutex_t *lock, int timeout, __maybe_unused const ch |
|
|
|
tv_to_ts(&abs, &now); |
|
|
|
tv_to_ts(&abs, &now); |
|
|
|
abs.tv_sec += timeout; |
|
|
|
abs.tv_sec += timeout; |
|
|
|
|
|
|
|
|
|
|
|
TRYLOCK(lock, file, func, line); |
|
|
|
ret = pthread_mutex_timedlock(&lock->mutex, &abs); |
|
|
|
ret = pthread_mutex_timedlock(lock, &abs); |
|
|
|
if (!ret) { |
|
|
|
DIDLOCK(ret, lock, file, func, line); |
|
|
|
lock->file = file; |
|
|
|
|
|
|
|
lock->func = func; |
|
|
|
|
|
|
|
lock->line = line; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* Make every locking attempt warn if we're unable to get the lock for more
|
|
|
|
/* Make every locking attempt warn if we're unable to get the lock for more
|
|
|
|
* than 10 seconds and fail if we can't get it for longer than a minute. */ |
|
|
|
* than 10 seconds and fail if we can't get it for longer than a minute. */ |
|
|
|
void _mutex_lock(pthread_mutex_t *lock, const char *file, const char *func, const int line) |
|
|
|
void _mutex_lock(mutex_t *lock, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ret, retries = 0; |
|
|
|
int ret, retries = 0; |
|
|
|
|
|
|
|
|
|
|
|
GETLOCK(lock, file, func, line); |
|
|
|
|
|
|
|
retry: |
|
|
|
retry: |
|
|
|
ret = _mutex_timedlock(lock, 10, file, func, line); |
|
|
|
ret = _mutex_timedlock(lock, 10, file, func, line); |
|
|
|
if (unlikely(ret)) { |
|
|
|
if (unlikely(ret)) { |
|
|
|
if (likely(ret == ETIMEDOUT)) { |
|
|
|
if (likely(ret == ETIMEDOUT)) { |
|
|
|
LOGERR("WARNING: Prolonged mutex lock contention from %s %s:%d", file, func, line); |
|
|
|
LOGERR("WARNING: Prolonged mutex lock contention from %s %s:%d, held by %s %s:%d", |
|
|
|
|
|
|
|
file, func, line, lock->file, lock->func, lock->line); |
|
|
|
if (++retries < 6) |
|
|
|
if (++retries < 6) |
|
|
|
goto retry; |
|
|
|
goto retry; |
|
|
|
quitfrom(1, file, func, line, "FAILED TO GRAB MUTEX!"); |
|
|
|
quitfrom(1, file, func, line, "FAILED TO GRAB MUTEX!"); |
|
|
|
} |
|
|
|
} |
|
|
|
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON LOCK!"); |
|
|
|
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON LOCK!"); |
|
|
|
} |
|
|
|
} |
|
|
|
GOTLOCK(lock, file, func, line); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _mutex_unlock(pthread_mutex_t *lock, const char *file, const char *func, const int line) |
|
|
|
/* Does not unset lock->file/func/line since they're only relevant when the lock is held */ |
|
|
|
|
|
|
|
void _mutex_unlock(mutex_t *lock, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (unlikely(pthread_mutex_unlock(lock))) |
|
|
|
if (unlikely(pthread_mutex_unlock(&lock->mutex))) |
|
|
|
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON UNLOCK!"); |
|
|
|
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON UNLOCK!"); |
|
|
|
GUNLOCK(lock, file, func, line); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int _mutex_trylock(pthread_mutex_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line) |
|
|
|
int _mutex_trylock(mutex_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
|
|
TRYLOCK(lock, file, func, line); |
|
|
|
ret = pthread_mutex_trylock(&lock->mutex); |
|
|
|
ret = pthread_mutex_trylock(lock); |
|
|
|
if (!ret) { |
|
|
|
DIDLOCK(ret, lock, file, func, line); |
|
|
|
lock->file = file; |
|
|
|
|
|
|
|
lock->func = func; |
|
|
|
|
|
|
|
lock->line = line; |
|
|
|
|
|
|
|
} |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int _wr_timedlock(pthread_rwlock_t *lock, int timeout, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line) |
|
|
|
void mutex_destroy(mutex_t *lock) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
pthread_mutex_destroy(&lock->mutex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int wr_timedlock(pthread_rwlock_t *lock, int timeout) |
|
|
|
{ |
|
|
|
{ |
|
|
|
tv_t now; |
|
|
|
tv_t now; |
|
|
|
ts_t abs; |
|
|
|
ts_t abs; |
|
|
@ -189,41 +213,45 @@ int _wr_timedlock(pthread_rwlock_t *lock, int timeout, __maybe_unused const char |
|
|
|
tv_to_ts(&abs, &now); |
|
|
|
tv_to_ts(&abs, &now); |
|
|
|
abs.tv_sec += timeout; |
|
|
|
abs.tv_sec += timeout; |
|
|
|
|
|
|
|
|
|
|
|
TRYLOCK(lock, file, func, line); |
|
|
|
|
|
|
|
ret = pthread_rwlock_timedwrlock(lock, &abs); |
|
|
|
ret = pthread_rwlock_timedwrlock(lock, &abs); |
|
|
|
DIDLOCK(ret, lock, file, func, line); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _wr_lock(pthread_rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
void _wr_lock(rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ret, retries = 0; |
|
|
|
int ret, retries = 0; |
|
|
|
|
|
|
|
|
|
|
|
GETLOCK(lock, file, func, line); |
|
|
|
|
|
|
|
retry: |
|
|
|
retry: |
|
|
|
ret = _wr_timedlock(lock, 10, file, func, line); |
|
|
|
ret = wr_timedlock(&lock->rwlock, 10); |
|
|
|
if (unlikely(ret)) { |
|
|
|
if (unlikely(ret)) { |
|
|
|
if (likely(ret == ETIMEDOUT)) { |
|
|
|
if (likely(ret == ETIMEDOUT)) { |
|
|
|
LOGERR("WARNING: Prolonged write lock contention from %s %s:%d", file, func, line); |
|
|
|
LOGERR("WARNING: Prolonged write lock contention from %s %s:%d, held by %s %s:%d", |
|
|
|
|
|
|
|
file, func, line, lock->file, lock->func, lock->line); |
|
|
|
if (++retries < 6) |
|
|
|
if (++retries < 6) |
|
|
|
goto retry; |
|
|
|
goto retry; |
|
|
|
quitfrom(1, file, func, line, "FAILED TO GRAB WRITE LOCK!"); |
|
|
|
quitfrom(1, file, func, line, "FAILED TO GRAB WRITE LOCK!"); |
|
|
|
} |
|
|
|
} |
|
|
|
quitfrom(1, file, func, line, "WTF ERROR ON WRITE LOCK!"); |
|
|
|
quitfrom(1, file, func, line, "WTF ERROR ON WRITE LOCK!"); |
|
|
|
} |
|
|
|
} |
|
|
|
GOTLOCK(lock, file, func, line); |
|
|
|
lock->file = file; |
|
|
|
|
|
|
|
lock->func = func; |
|
|
|
|
|
|
|
lock->line = line; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int _wr_trylock(pthread_rwlock_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line) |
|
|
|
int _wr_trylock(rwlock_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
TRYLOCK(lock, file, func, line); |
|
|
|
int ret = pthread_rwlock_trywrlock(&lock->rwlock); |
|
|
|
int ret = pthread_rwlock_trywrlock(lock); |
|
|
|
|
|
|
|
DIDLOCK(ret, lock, file, func, line); |
|
|
|
if (!ret) { |
|
|
|
|
|
|
|
lock->file = file; |
|
|
|
|
|
|
|
lock->func = func; |
|
|
|
|
|
|
|
lock->line = line; |
|
|
|
|
|
|
|
} |
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int _rd_timedlock(pthread_rwlock_t *lock, int timeout, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line) |
|
|
|
static int rd_timedlock(pthread_rwlock_t *lock, int timeout) |
|
|
|
{ |
|
|
|
{ |
|
|
|
tv_t now; |
|
|
|
tv_t now; |
|
|
|
ts_t abs; |
|
|
|
ts_t abs; |
|
|
@ -233,74 +261,60 @@ int _rd_timedlock(pthread_rwlock_t *lock, int timeout, __maybe_unused const char |
|
|
|
tv_to_ts(&abs, &now); |
|
|
|
tv_to_ts(&abs, &now); |
|
|
|
abs.tv_sec += timeout; |
|
|
|
abs.tv_sec += timeout; |
|
|
|
|
|
|
|
|
|
|
|
TRYLOCK(lock, file, func, line); |
|
|
|
|
|
|
|
ret = pthread_rwlock_timedrdlock(lock, &abs); |
|
|
|
ret = pthread_rwlock_timedrdlock(lock, &abs); |
|
|
|
DIDLOCK(ret, lock, file, func, line); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _rd_lock(pthread_rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
void _rd_lock(rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ret, retries = 0; |
|
|
|
int ret, retries = 0; |
|
|
|
|
|
|
|
|
|
|
|
GETLOCK(lock, file, func, line); |
|
|
|
|
|
|
|
retry: |
|
|
|
retry: |
|
|
|
ret = _rd_timedlock(lock, 10, file, func, line); |
|
|
|
ret = rd_timedlock(&lock->rwlock, 10); |
|
|
|
if (unlikely(ret)) { |
|
|
|
if (unlikely(ret)) { |
|
|
|
if (likely(ret == ETIMEDOUT)) { |
|
|
|
if (likely(ret == ETIMEDOUT)) { |
|
|
|
LOGERR("WARNING: Prolonged read lock contention from %s %s:%d", file, func, line); |
|
|
|
LOGERR("WARNING: Prolonged read lock contention from %s %s:%d, held by %s %s:%d", |
|
|
|
|
|
|
|
file, func, line, lock->file, lock->func, lock->line); |
|
|
|
if (++retries < 6) |
|
|
|
if (++retries < 6) |
|
|
|
goto retry; |
|
|
|
goto retry; |
|
|
|
quitfrom(1, file, func, line, "FAILED TO GRAB READ LOCK!"); |
|
|
|
quitfrom(1, file, func, line, "FAILED TO GRAB READ LOCK!"); |
|
|
|
} |
|
|
|
} |
|
|
|
quitfrom(1, file, func, line, "WTF ERROR ON READ LOCK!"); |
|
|
|
quitfrom(1, file, func, line, "WTF ERROR ON READ LOCK!"); |
|
|
|
} |
|
|
|
} |
|
|
|
GOTLOCK(lock, file, func, line); |
|
|
|
lock->file = file; |
|
|
|
|
|
|
|
lock->func = func; |
|
|
|
|
|
|
|
lock->line = line; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _rw_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
void _rw_unlock(rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (unlikely(pthread_rwlock_unlock(lock))) |
|
|
|
if (unlikely(pthread_rwlock_unlock(&lock->rwlock))) |
|
|
|
quitfrom(1, file, func, line, "WTF RWLOCK ERROR ON UNLOCK!"); |
|
|
|
quitfrom(1, file, func, line, "WTF RWLOCK ERROR ON UNLOCK!"); |
|
|
|
GUNLOCK(lock, file, func, line); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _rd_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
void _rd_unlock(rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
_rw_unlock(lock, file, func, line); |
|
|
|
_rw_unlock(lock, file, func, line); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _wr_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
void _wr_unlock(rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
_rw_unlock(lock, file, func, line); |
|
|
|
_rw_unlock(lock, file, func, line); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _mutex_init(pthread_mutex_t *lock, const char *file, const char *func, const int line) |
|
|
|
void _mutex_init(mutex_t *lock, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (unlikely(pthread_mutex_init(lock, NULL))) |
|
|
|
if (unlikely(pthread_mutex_init(&lock->mutex, NULL))) |
|
|
|
quitfrom(1, file, func, line, "Failed to pthread_mutex_init"); |
|
|
|
quitfrom(1, file, func, line, "Failed to pthread_mutex_init"); |
|
|
|
INITLOCK(lock, CGLOCK_MUTEX, file, func, line); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void mutex_destroy(pthread_mutex_t *lock) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
/* Ignore return code. This only invalidates the mutex on linux but
|
|
|
|
|
|
|
|
* releases resources on windows. */ |
|
|
|
|
|
|
|
pthread_mutex_destroy(lock); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _rwlock_init(pthread_rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
void _rwlock_init(rwlock_t *lock, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (unlikely(pthread_rwlock_init(lock, NULL))) |
|
|
|
if (unlikely(pthread_rwlock_init(&lock->rwlock, NULL))) |
|
|
|
quitfrom(1, file, func, line, "Failed to pthread_rwlock_init"); |
|
|
|
quitfrom(1, file, func, line, "Failed to pthread_rwlock_init"); |
|
|
|
INITLOCK(lock, CGLOCK_RW, file, func, line); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void rwlock_destroy(pthread_rwlock_t *lock) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
pthread_rwlock_destroy(lock); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void _cond_init(pthread_cond_t *cond, const char *file, const char *func, const int line) |
|
|
|
void _cond_init(pthread_cond_t *cond, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
@ -314,11 +328,6 @@ void _cklock_init(cklock_t *lock, const char *file, const char *func, const int |
|
|
|
_rwlock_init(&lock->rwlock, file, func, line); |
|
|
|
_rwlock_init(&lock->rwlock, file, func, line); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void cklock_destroy(cklock_t *lock) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
rwlock_destroy(&lock->rwlock); |
|
|
|
|
|
|
|
mutex_destroy(&lock->mutex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read lock variant of cklock. Cannot be promoted. */ |
|
|
|
/* Read lock variant of cklock. Cannot be promoted. */ |
|
|
|
void _ck_rlock(cklock_t *lock, const char *file, const char *func, const int line) |
|
|
|
void _ck_rlock(cklock_t *lock, const char *file, const char *func, const int line) |
|
|
@ -386,6 +395,13 @@ void _ck_wunlock(cklock_t *lock, const char *file, const char *func, const int l |
|
|
|
_mutex_unlock(&lock->mutex, file, func, line); |
|
|
|
_mutex_unlock(&lock->mutex, file, func, line); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void cklock_destroy(cklock_t *lock) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
pthread_rwlock_destroy(&lock->rwlock.rwlock); |
|
|
|
|
|
|
|
pthread_mutex_destroy(&lock->mutex.mutex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void _cksem_init(sem_t *sem, const char *file, const char *func, const int line) |
|
|
|
void _cksem_init(sem_t *sem, const char *file, const char *func, const int line) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int ret; |
|
|
|
int ret; |
|
|
|