Browse Source

Add full lock tracking for mutexes and rwlocks

master
Con Kolivas 10 years ago
parent
commit
42f14a9536
  1. 4
      src/ckdb.c
  2. 2
      src/ckdb.h
  3. 8
      src/ckpool.c
  4. 2
      src/ckpool.h
  5. 4
      src/connector.c
  6. 10
      src/generator.c
  7. 131
      src/libckpool.c
  8. 68
      src/libckpool.h
  9. 12
      src/stratifier.c

4
src/ckdb.c

@ -301,7 +301,7 @@ K_STORE *logqueue_store;
// WORKQUEUE
K_LIST *workqueue_free;
K_STORE *workqueue_store;
pthread_mutex_t wq_waitlock;
mutex_t wq_waitlock;
pthread_cond_t wq_waitcond;
// HEARTBEATQUEUE
@ -3247,7 +3247,7 @@ static void *listener(void *arg)
timeraddspec(&abs, &tsdiff);
mutex_lock(&wq_waitlock);
pthread_cond_timedwait(&wq_waitcond, &wq_waitlock, &abs);
cond_timedwait(&wq_waitcond, &wq_waitlock, &abs);
mutex_unlock(&wq_waitlock);
}
}

2
src/ckdb.h

@ -654,7 +654,7 @@ typedef struct workqueue {
extern K_LIST *workqueue_free;
extern K_STORE *workqueue_store;
extern pthread_mutex_t wq_waitlock;
extern mutex_t wq_waitlock;
extern pthread_cond_t wq_waitcond;
// HEARTBEATQUEUE

8
src/ckpool.c

@ -120,7 +120,7 @@ static void *ckmsg_queue(void *arg)
tv_to_ts(&abs, &now);
abs.tv_sec++;
if (!ckmsgq->msgs)
pthread_cond_timedwait(ckmsgq->cond, ckmsgq->lock, &abs);
cond_timedwait(ckmsgq->cond, ckmsgq->lock, &abs);
msg = ckmsgq->msgs;
if (msg)
DL_DELETE(ckmsgq->msgs, msg);
@ -141,7 +141,7 @@ ckmsgq_t *create_ckmsgq(ckpool_t *ckp, const char *name, const void *func)
strncpy(ckmsgq->name, name, 15);
ckmsgq->func = func;
ckmsgq->ckp = ckp;
ckmsgq->lock = ckalloc(sizeof(pthread_mutex_t));
ckmsgq->lock = ckalloc(sizeof(mutex_t));
ckmsgq->cond = ckalloc(sizeof(pthread_cond_t));
mutex_init(ckmsgq->lock);
cond_init(ckmsgq->cond);
@ -153,11 +153,11 @@ ckmsgq_t *create_ckmsgq(ckpool_t *ckp, const char *name, const void *func)
ckmsgq_t *create_ckmsgqs(ckpool_t *ckp, const char *name, const void *func, const int count)
{
ckmsgq_t *ckmsgq = ckzalloc(sizeof(ckmsgq_t) * count);
pthread_mutex_t *lock;
mutex_t *lock;
pthread_cond_t *cond;
int i;
lock = ckalloc(sizeof(pthread_mutex_t));
lock = ckalloc(sizeof(mutex_t));
cond = ckalloc(sizeof(pthread_cond_t));
mutex_init(lock);
cond_init(cond);

2
src/ckpool.h

@ -34,7 +34,7 @@ struct ckmsgq {
ckpool_t *ckp;
char name[16];
pthread_t pth;
pthread_mutex_t *lock;
mutex_t *lock;
pthread_cond_t *cond;
ckmsg_t *msgs;
void (*func)(ckpool_t *, void *);

4
src/connector.c

@ -95,7 +95,7 @@ struct connector_data {
int64_t sends_delayed;
/* For protecting the pending sends list */
pthread_mutex_t sender_lock;
mutex_t sender_lock;
pthread_cond_t sender_cond;
};
@ -481,7 +481,7 @@ void *sender(void *arg)
ts_realtime(&timeout_ts);
timeraddspec(&timeout_ts, &polltime);
pthread_cond_timedwait(&cdata->sender_cond, &cdata->sender_lock, &timeout_ts);
cond_timedwait(&cdata->sender_cond, &cdata->sender_lock, &timeout_ts);
}
sender_send = cdata->sender_sends;
if (sender_send)

10
src/generator.c

@ -106,18 +106,18 @@ struct proxy_instance {
bool diffed; /* Received new diff */
bool reconnect; /* We need to drop and reconnect */
pthread_mutex_t notify_lock;
mutex_t notify_lock;
notify_instance_t *notify_instances;
notify_instance_t *current_notify;
pthread_t pth_precv;
pthread_t pth_psend;
pthread_mutex_t psend_lock;
mutex_t psend_lock;
pthread_cond_t psend_cond;
stratum_msg_t *psends;
pthread_mutex_t share_lock;
mutex_t share_lock;
share_msg_t *shares;
int64_t share_id;
@ -128,7 +128,7 @@ struct proxy_instance {
/* Private data for the generator */
struct generator_data {
pthread_mutex_t lock; /* Lock protecting linked lists */
mutex_t lock; /* Lock protecting linked lists */
proxy_instance_t *proxy_list; /* Linked list of all active proxies */
int proxy_notify_id; // Globally increasing notify id
ckmsgq_t *srvchk; // Server check message queue
@ -1344,7 +1344,7 @@ static void *proxy_send(void *arg)
mutex_lock(&proxi->psend_lock);
if (!proxi->psends)
pthread_cond_wait(&proxi->psend_cond, &proxi->psend_lock);
cond_wait(&proxi->psend_cond, &proxi->psend_lock);
msg = proxi->psends;
if (likely(msg))
DL_DELETE(proxi->psends, msg);

131
src/libckpool.c

@ -114,8 +114,30 @@ bool ck_completion_timeout(void *fn, void *fnarg, int timeout)
return !ret;
}
int _cond_wait(pthread_cond_t *cond, mutex_t *lock, const char *file, const char *func, const int line)
{
int ret;
ret = pthread_cond_wait(cond, &lock->mutex);
lock->file = file;
lock->func = func;
lock->line = line;
return ret;
}
int mutex_timedlock(pthread_mutex_t *lock, int timeout)
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;
ts_t abs;
@ -125,22 +147,28 @@ int mutex_timedlock(pthread_mutex_t *lock, int timeout)
tv_to_ts(&abs, &now);
abs.tv_sec += timeout;
ret = pthread_mutex_timedlock(lock, &abs);
ret = pthread_mutex_timedlock(&lock->mutex, &abs);
if (!ret) {
lock->file = file;
lock->func = func;
lock->line = line;
}
return ret;
}
/* 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. */
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;
retry:
ret = mutex_timedlock(lock, 10);
ret = _mutex_timedlock(lock, 10, file, func, line);
if (unlikely(ret)) {
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)
goto retry;
quitfrom(1, file, func, line, "FAILED TO GRAB MUTEX!");
@ -149,22 +177,33 @@ retry:
}
}
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!");
}
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;
ret = pthread_mutex_trylock(lock);
ret = pthread_mutex_trylock(&lock->mutex);
if (!ret) {
lock->file = file;
lock->func = func;
lock->line = line;
}
return ret;
}
int wr_timedlock(pthread_rwlock_t *lock, int timeout)
void mutex_destroy(mutex_t *lock)
{
pthread_mutex_destroy(&lock->mutex);
}
static int wr_timedlock(pthread_rwlock_t *lock, int timeout)
{
tv_t now;
ts_t abs;
@ -179,31 +218,40 @@ int wr_timedlock(pthread_rwlock_t *lock, int timeout)
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;
retry:
ret = wr_timedlock(lock, 10);
ret = wr_timedlock(&lock->rwlock, 10);
if (unlikely(ret)) {
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)
goto retry;
quitfrom(1, file, func, line, "FAILED TO GRAB WRITE LOCK!");
}
quitfrom(1, file, func, line, "WTF ERROR ON WRITE LOCK!");
}
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)
{
int ret = pthread_rwlock_trywrlock(lock);
int ret = pthread_rwlock_trywrlock(&lock->rwlock);
if (!ret) {
lock->file = file;
lock->func = func;
lock->line = line;
}
return ret;
}
int rd_timedlock(pthread_rwlock_t *lock, int timeout)
static int rd_timedlock(pthread_rwlock_t *lock, int timeout)
{
tv_t now;
ts_t abs;
@ -218,62 +266,55 @@ int rd_timedlock(pthread_rwlock_t *lock, int timeout)
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;
retry:
ret = rd_timedlock(lock, 10);
ret = rd_timedlock(&lock->rwlock, 10);
if (unlikely(ret)) {
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)
goto retry;
quitfrom(1, file, func, line, "FAILED TO GRAB READ LOCK!");
}
quitfrom(1, file, func, line, "WTF ERROR ON READ LOCK!");
}
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!");
}
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);
}
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);
}
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");
}
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");
}
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)
{
@ -287,11 +328,6 @@ void _cklock_init(cklock_t *lock, const char *file, const char *func, const int
_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. */
void _ck_rlock(cklock_t *lock, const char *file, const char *func, const int line)
@ -359,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);
}
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)
{
int ret;

68
src/libckpool.h

@ -145,6 +145,9 @@ static inline void flip_80(void *dest_p, const void *src_p)
dest[i] = bswap_32(src[i]);
}
#define cond_wait(_cond, _lock) _cond_wait(_cond, _lock, __FILE__, __func__, __LINE__)
#define cond_timedwait(_cond, _lock, _abstime) _cond_timedwait(_cond, _lock, _abstime, __FILE__, __func__, __LINE__)
#define mutex_timedlock(_lock, _timeout) _mutex_timedlock(_lock, _timeout, __FILE__, __func__, __LINE__)
#define mutex_lock(_lock) _mutex_lock(_lock, __FILE__, __func__, __LINE__)
#define mutex_unlock_noyield(_lock) _mutex_unlock_noyield(_lock, __FILE__, __func__, __LINE__)
#define mutex_unlock(_lock) _mutex_unlock(_lock, __FILE__, __func__, __LINE__)
@ -274,10 +277,31 @@ static const char __maybe_unused *share_errs[] = {
#define SHARE_ERR(x) share_errs[((x) + 9)]
/* ck locks, a write biased variant of rwlocks */
struct cklock {
typedef struct ckmutex mutex_t;
struct ckmutex {
pthread_mutex_t mutex;
const char *file;
const char *func;
int line;
};
typedef struct ckrwlock rwlock_t;
struct ckrwlock {
pthread_rwlock_t rwlock;
const char *file;
const char *func;
int line;
};
/* ck locks, a write biased variant of rwlocks */
struct cklock {
mutex_t mutex;
rwlock_t rwlock;
const char *file;
const char *func;
int line;
};
typedef struct cklock cklock_t;
@ -385,29 +409,28 @@ void create_pthread(pthread_t *thread, void *(*start_routine)(void *), void *arg
void join_pthread(pthread_t thread);
bool ck_completion_timeout(void *fn, void *fnarg, int timeout);
int mutex_timedlock(pthread_mutex_t *lock, int timeout);
void _mutex_lock(pthread_mutex_t *lock, const char *file, const char *func, const int line);
void _mutex_unlock_noyield(pthread_mutex_t *lock, const char *file, const char *func, const int line);
void _mutex_unlock(pthread_mutex_t *lock, const char *file, const char *func, const int line);
int _mutex_trylock(pthread_mutex_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line);
int wr_timedlock(pthread_rwlock_t *lock, int timeout);
void _wr_lock(pthread_rwlock_t *lock, const char *file, const char *func, const int line);
int _wr_trylock(pthread_rwlock_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line);
int rd_timedlock(pthread_rwlock_t *lock, int timeout);
void _rd_lock(pthread_rwlock_t *lock, const char *file, const char *func, const int line);
void _rw_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line);
void _rd_unlock_noyield(pthread_rwlock_t *lock, const char *file, const char *func, const int line);
void _wr_unlock_noyield(pthread_rwlock_t *lock, const char *file, const char *func, const int line);
void _rd_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line);
void _wr_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line);
void _mutex_init(pthread_mutex_t *lock, const char *file, const char *func, const int line);
void mutex_destroy(pthread_mutex_t *lock);
void _rwlock_init(pthread_rwlock_t *lock, const char *file, const char *func, const int line);
void rwlock_destroy(pthread_rwlock_t *lock);
int _cond_wait(pthread_cond_t *cond, mutex_t *lock, const char *file, const char *func, 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 _mutex_timedlock(mutex_t *lock, int timeout, const char *file, const char *func, const int line);
void _mutex_lock(mutex_t *lock, const char *file, const char *func, const int line);
void _mutex_unlock_noyield(mutex_t *lock, const char *file, const char *func, const int line);
void _mutex_unlock(mutex_t *lock, const char *file, const char *func, const int line);
int _mutex_trylock(mutex_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line);
void mutex_destroy(mutex_t *lock);
void _wr_lock(rwlock_t *lock, const char *file, const char *func, const int line);
int _wr_trylock(rwlock_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line);
void _rd_lock(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);
void _rd_unlock_noyield(rwlock_t *lock, const char *file, const char *func, const int line);
void _wr_unlock_noyield(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);
void _wr_unlock(rwlock_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);
void _rwlock_init(rwlock_t *lock, 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);
void _cklock_init(cklock_t *lock, const char *file, const char *func, const int line);
void cklock_destroy(cklock_t *lock);
void _ck_rlock(cklock_t *lock, const char *file, const char *func, const int line);
void _ck_ilock(cklock_t *lock, const char *file, const char *func, const int line);
void _ck_uilock(cklock_t *lock, const char *file, const char *func, const int line);
@ -418,6 +441,7 @@ void _ck_dwilock(cklock_t *lock, const char *file, const char *func, const int l
void _ck_dlock(cklock_t *lock, const char *file, const char *func, const int line);
void _ck_runlock(cklock_t *lock, const char *file, const char *func, const int line);
void _ck_wunlock(cklock_t *lock, const char *file, const char *func, const int line);
void cklock_destroy(cklock_t *lock);
void _cksem_init(sem_t *sem, const char *file, const char *func, const int line);
void _cksem_post(sem_t *sem, const char *file, const char *func, const int line);

12
src/stratifier.c

@ -285,10 +285,10 @@ struct stratifier_data {
pool_stats_t stats;
/* Protects changes to pool stats */
pthread_mutex_t stats_lock;
mutex_t stats_lock;
/* Serialises sends/receives to ckdb if possible */
pthread_mutex_t ckdb_lock;
mutex_t ckdb_lock;
bool ckdb_offline;
@ -336,14 +336,14 @@ struct stratifier_data {
cklock_t instance_lock;
share_t *shares;
pthread_mutex_t share_lock;
mutex_t share_lock;
int64_t shares_generated;
/* Linked list of block solves, added to during submission, removed on
* accept/reject. It is likely we only ever have one solve on here but
* you never know... */
pthread_mutex_t block_lock;
mutex_t block_lock;
ckmsg_t *block_solves;
/* Generator message priority */
@ -3676,7 +3676,7 @@ static void parse_ckdb_cmd(ckpool_t *ckp, const char *cmd)
}
/* Test a value under lock and set it, returning the original value */
static bool test_and_set(bool *val, pthread_mutex_t *lock)
static bool test_and_set(bool *val, mutex_t *lock)
{
bool ret;
@ -3688,7 +3688,7 @@ static bool test_and_set(bool *val, pthread_mutex_t *lock)
return ret;
}
static bool test_and_clear(bool *val, pthread_mutex_t *lock)
static bool test_and_clear(bool *val, mutex_t *lock)
{
bool ret;

Loading…
Cancel
Save