|
|
@@ -737,74 +737,143 @@ endian_flip128(void __maybe_unused *dest_p, const void __maybe_unused *src_p)
|
|
|
|
|
|
extern void _quit(int status);
|
|
|
|
|
|
-#define mutex_lock(_lock) _mutex_lock(_lock, __FILE__, __func__, __LINE__)
|
|
|
-#define mutex_unlock_noyield(_lock) _mutex_unlock_noyield(_lock, __FILE__, __func__, __LINE__)
|
|
|
-#define wr_lock(_lock) _wr_lock(_lock, __FILE__, __func__, __LINE__)
|
|
|
-#define rd_lock(_lock) _rd_lock(_lock, __FILE__, __func__, __LINE__)
|
|
|
-#define rw_unlock(_lock) _rw_unlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
-#define mutex_init(_lock) _mutex_init(_lock, __FILE__, __func__, __LINE__)
|
|
|
-#define rwlock_init(_lock) _rwlock_init(_lock, __FILE__, __func__, __LINE__)
|
|
|
+/*
|
|
|
+ * Set this to non-zero to enable lock tracking
|
|
|
+ * Use the API lockstats command to see the locking status on stderr
|
|
|
+ * i.e. in your log file if you 2> log.log - but not on the screen
|
|
|
+ * API lockstats is privilidged but will always exist and will return
|
|
|
+ * success if LOCK_TRACKING is enabled and warning if disabled
|
|
|
+ * In production code, this should never be enabled since it will slow down all locking
|
|
|
+ * So, e.g. use it to track down a deadlock - after a reproducable deadlock occurs
|
|
|
+ * ... Of course if the API code itself deadlocks, it wont help :)
|
|
|
+ */
|
|
|
+#define LOCK_TRACKING 0
|
|
|
+
|
|
|
+#if LOCK_TRACKING
|
|
|
+enum cglock_typ {
|
|
|
+ CGLOCK_MUTEX,
|
|
|
+ CGLOCK_RW,
|
|
|
+ CGLOCK_UNKNOWN
|
|
|
+};
|
|
|
+
|
|
|
+extern uint64_t api_getlock(void *lock, const char *file, const char *func, const int line);
|
|
|
+extern void api_gotlock(uint64_t id, void *lock, const char *file, const char *func, const int line);
|
|
|
+extern uint64_t api_trylock(void *lock, const char *file, const char *func, const int line);
|
|
|
+extern void api_didlock(uint64_t id, int ret, void *lock, const char *file, const char *func, const int line);
|
|
|
+extern void api_gunlock(void *lock, const char *file, const char *func, const int line);
|
|
|
+extern void api_initlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int line);
|
|
|
+
|
|
|
+#define GETLOCK(_lock, _file, _func, _line) uint64_t _id1 = api_getlock((void *)(_lock), _file, _func, _line)
|
|
|
+#define GOTLOCK(_lock, _file, _func, _line) api_gotlock(_id1, (void *)(_lock), _file, _func, _line)
|
|
|
+#define TRYLOCK(_lock, _file, _func, _line) uint64_t _id2 = api_trylock((void *)(_lock), _file, _func, _line)
|
|
|
+#define DIDLOCK(_ret, _lock, _file, _func, _line) api_didlock(_id2, _ret, (void *)(_lock), _file, _func, _line)
|
|
|
+#define GUNLOCK(_lock, _file, _func, _line) api_gunlock((void *)(_lock), _file, _func, _line)
|
|
|
+#define INITLOCK(_lock, _typ, _file, _func, _line) api_initlock((void *)(_lock), _typ, _file, _func, _line)
|
|
|
+#else
|
|
|
+#define GETLOCK(_lock, _file, _func, _line)
|
|
|
+#define GOTLOCK(_lock, _file, _func, _line)
|
|
|
+#define TRYLOCK(_lock, _file, _func, _line)
|
|
|
+#define DIDLOCK(_ret, _lock, _file, _func, _line)
|
|
|
+#define GUNLOCK(_lock, _file, _func, _line)
|
|
|
+#define INITLOCK(_typ, _lock, _file, _func, _line)
|
|
|
+#endif
|
|
|
+
|
|
|
+#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__)
|
|
|
+#define mutex_trylock(_lock) _mutex_trylock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define wr_lock(_lock) _wr_lock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define rd_lock(_lock) _rd_lock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define rw_unlock(_lock) _rw_unlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define rd_unlock_noyield(_lock) _rd_unlock_noyield(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define wr_unlock_noyield(_lock) _wr_unlock_noyield(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define rd_unlock(_lock) _rd_unlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define wr_unlock(_lock) _wr_unlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define mutex_init(_lock) _mutex_init(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define rwlock_init(_lock) _rwlock_init(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cglock_init(_lock) _cglock_init(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_rlock(_lock) _cg_rlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_ilock(_lock) _cg_ilock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_ulock(_lock) _cg_ulock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_wlock(_lock) _cg_wlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_dwlock(_lock) _cg_dwlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_dwilock(_lock) _cg_dwilock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_dlock(_lock) _cg_dlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_runlock(_lock) _cg_runlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_ruwlock(_lock) _cg_ruwlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
+#define cg_wunlock(_lock) _cg_wunlock(_lock, __FILE__, __func__, __LINE__)
|
|
|
|
|
|
static inline void _mutex_lock(pthread_mutex_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
+ GETLOCK(lock, file, func, line);
|
|
|
if (unlikely(pthread_mutex_lock(lock)))
|
|
|
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON LOCK! errno=%d", errno);
|
|
|
+ GOTLOCK(lock, file, func, line);
|
|
|
}
|
|
|
|
|
|
static inline void _mutex_unlock_noyield(pthread_mutex_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
if (unlikely(pthread_mutex_unlock(lock)))
|
|
|
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON UNLOCK! errno=%d", errno);
|
|
|
+ GUNLOCK(lock, file, func, line);
|
|
|
}
|
|
|
|
|
|
-static inline void mutex_unlock(pthread_mutex_t *lock)
|
|
|
+static inline void _mutex_unlock(pthread_mutex_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- mutex_unlock_noyield(lock);
|
|
|
+ _mutex_unlock_noyield(lock, file, func, line);
|
|
|
sched_yield();
|
|
|
}
|
|
|
|
|
|
-static inline int mutex_trylock(pthread_mutex_t *lock)
|
|
|
+static inline int _mutex_trylock(pthread_mutex_t *lock, __maybe_unused const char *file, __maybe_unused const char *func, __maybe_unused const int line)
|
|
|
{
|
|
|
- return pthread_mutex_trylock(lock);
|
|
|
+ TRYLOCK(lock, file, func, line);
|
|
|
+ int ret = pthread_mutex_trylock(lock);
|
|
|
+ DIDLOCK(ret, lock, file, func, line);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static inline void _wr_lock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
+ GETLOCK(lock, file, func, line);
|
|
|
if (unlikely(pthread_rwlock_wrlock(lock)))
|
|
|
quitfrom(1, file, func, line, "WTF WRLOCK ERROR ON LOCK! errno=%d", errno);
|
|
|
+ GOTLOCK(lock, file, func, line);
|
|
|
}
|
|
|
|
|
|
static inline void _rd_lock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
+ GETLOCK(lock, file, func, line);
|
|
|
if (unlikely(pthread_rwlock_rdlock(lock)))
|
|
|
quitfrom(1, file, func, line, "WTF RDLOCK ERROR ON LOCK! errno=%d", errno);
|
|
|
+ GOTLOCK(lock, file, func, line);
|
|
|
}
|
|
|
|
|
|
static inline void _rw_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
if (unlikely(pthread_rwlock_unlock(lock)))
|
|
|
quitfrom(1, file, func, line, "WTF RWLOCK ERROR ON UNLOCK! errno=%d", errno);
|
|
|
+ GUNLOCK(lock, file, func, line);
|
|
|
}
|
|
|
|
|
|
-static inline void rd_unlock_noyield(pthread_rwlock_t *lock)
|
|
|
+static inline void _rd_unlock_noyield(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- rw_unlock(lock);
|
|
|
+ _rw_unlock(lock, file, func, line);
|
|
|
}
|
|
|
|
|
|
-static inline void wr_unlock_noyield(pthread_rwlock_t *lock)
|
|
|
+static inline void _wr_unlock_noyield(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- rw_unlock(lock);
|
|
|
+ _rw_unlock(lock, file, func, line);
|
|
|
}
|
|
|
|
|
|
-static inline void rd_unlock(pthread_rwlock_t *lock)
|
|
|
+static inline void _rd_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- rw_unlock(lock);
|
|
|
+ _rw_unlock(lock, file, func, line);
|
|
|
sched_yield();
|
|
|
}
|
|
|
|
|
|
-static inline void wr_unlock(pthread_rwlock_t *lock)
|
|
|
+static inline void _wr_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- rw_unlock(lock);
|
|
|
+ _rw_unlock(lock, file, func, line);
|
|
|
sched_yield();
|
|
|
}
|
|
|
|
|
|
@@ -812,86 +881,88 @@ static inline void _mutex_init(pthread_mutex_t *lock, const char *file, const ch
|
|
|
{
|
|
|
if (unlikely(pthread_mutex_init(lock, NULL)))
|
|
|
quitfrom(1, file, func, line, "Failed to pthread_mutex_init errno=%d", errno);
|
|
|
+ INITLOCK(lock, CGLOCK_MUTEX, file, func, line);
|
|
|
}
|
|
|
|
|
|
static inline void _rwlock_init(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
if (unlikely(pthread_rwlock_init(lock, NULL)))
|
|
|
quitfrom(1, file, func, line, "Failed to pthread_rwlock_init errno=%d", errno);
|
|
|
+ INITLOCK(lock, CGLOCK_RW, file, func, line);
|
|
|
}
|
|
|
|
|
|
-static inline void cglock_init(cglock_t *lock)
|
|
|
+static inline void _cglock_init(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- mutex_init(&lock->mutex);
|
|
|
- rwlock_init(&lock->rwlock);
|
|
|
+ _mutex_init(&lock->mutex, file, func, line);
|
|
|
+ _rwlock_init(&lock->rwlock, file, func, line);
|
|
|
}
|
|
|
|
|
|
/* Read lock variant of cglock. Cannot be promoted. */
|
|
|
-static inline void cg_rlock(cglock_t *lock)
|
|
|
+static inline void _cg_rlock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- mutex_lock(&lock->mutex);
|
|
|
- rd_lock(&lock->rwlock);
|
|
|
- mutex_unlock_noyield(&lock->mutex);
|
|
|
+ _mutex_lock(&lock->mutex, file, func, line);
|
|
|
+ _rd_lock(&lock->rwlock, file, func, line);
|
|
|
+ _mutex_unlock_noyield(&lock->mutex, file, func, line);
|
|
|
}
|
|
|
|
|
|
/* Intermediate variant of cglock - behaves as a read lock but can be promoted
|
|
|
* to a write lock or demoted to read lock. */
|
|
|
-static inline void cg_ilock(cglock_t *lock)
|
|
|
+static inline void _cg_ilock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- mutex_lock(&lock->mutex);
|
|
|
+ _mutex_lock(&lock->mutex, file, func, line);
|
|
|
}
|
|
|
|
|
|
/* Upgrade intermediate variant to a write lock */
|
|
|
-static inline void cg_ulock(cglock_t *lock)
|
|
|
+static inline void _cg_ulock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- wr_lock(&lock->rwlock);
|
|
|
+ _wr_lock(&lock->rwlock, file, func, line);
|
|
|
}
|
|
|
|
|
|
/* Write lock variant of cglock */
|
|
|
-static inline void cg_wlock(cglock_t *lock)
|
|
|
+static inline void _cg_wlock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- mutex_lock(&lock->mutex);
|
|
|
- wr_lock(&lock->rwlock);
|
|
|
+ _mutex_lock(&lock->mutex, file, func, line);
|
|
|
+ _wr_lock(&lock->rwlock, file, func, line);
|
|
|
}
|
|
|
|
|
|
/* Downgrade write variant to a read lock */
|
|
|
-static inline void cg_dwlock(cglock_t *lock)
|
|
|
+static inline void _cg_dwlock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- wr_unlock_noyield(&lock->rwlock);
|
|
|
- rd_lock(&lock->rwlock);
|
|
|
- mutex_unlock_noyield(&lock->mutex);
|
|
|
+ _wr_unlock_noyield(&lock->rwlock, file, func, line);
|
|
|
+ _rd_lock(&lock->rwlock, file, func, line);
|
|
|
+ _mutex_unlock_noyield(&lock->mutex, file, func, line);
|
|
|
}
|
|
|
|
|
|
/* Demote a write variant to an intermediate variant */
|
|
|
-static inline void cg_dwilock(cglock_t *lock)
|
|
|
+static inline void _cg_dwilock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- wr_unlock(&lock->rwlock);
|
|
|
+ _wr_unlock(&lock->rwlock, file, func, line);
|
|
|
}
|
|
|
|
|
|
/* Downgrade intermediate variant to a read lock */
|
|
|
-static inline void cg_dlock(cglock_t *lock)
|
|
|
+static inline void _cg_dlock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- rd_lock(&lock->rwlock);
|
|
|
- mutex_unlock_noyield(&lock->mutex);
|
|
|
+ _rd_lock(&lock->rwlock, file, func, line);
|
|
|
+ _mutex_unlock_noyield(&lock->mutex, file, func, line);
|
|
|
}
|
|
|
|
|
|
-static inline void cg_runlock(cglock_t *lock)
|
|
|
+static inline void _cg_runlock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- rd_unlock(&lock->rwlock);
|
|
|
+ _rd_unlock(&lock->rwlock, file, func, line);
|
|
|
}
|
|
|
|
|
|
/* This drops the read lock and grabs a write lock. It does NOT protect data
|
|
|
* between the two locks! */
|
|
|
-static inline void cg_ruwlock(cglock_t *lock)
|
|
|
+static inline void _cg_ruwlock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- rd_unlock_noyield(&lock->rwlock);
|
|
|
- cg_wlock(lock);
|
|
|
+ _rd_unlock_noyield(&lock->rwlock, file, func, line);
|
|
|
+ _cg_wlock(lock, file, func, line);
|
|
|
}
|
|
|
|
|
|
-static inline void cg_wunlock(cglock_t *lock)
|
|
|
+static inline void _cg_wunlock(cglock_t *lock, const char *file, const char *func, const int line)
|
|
|
{
|
|
|
- wr_unlock_noyield(&lock->rwlock);
|
|
|
- mutex_unlock(&lock->mutex);
|
|
|
+ _wr_unlock_noyield(&lock->rwlock, file, func, line);
|
|
|
+ _mutex_unlock(&lock->mutex, file, func, line);
|
|
|
}
|
|
|
|
|
|
struct pool;
|
|
|
@@ -942,6 +1013,10 @@ extern bool opt_bfl_noncerange;
|
|
|
#endif
|
|
|
extern int swork_id;
|
|
|
|
|
|
+#if LOCK_TRACKING
|
|
|
+extern pthread_mutex_t lockstat_lock;
|
|
|
+#endif
|
|
|
+
|
|
|
extern pthread_rwlock_t netacc_lock;
|
|
|
|
|
|
extern const uint32_t sha256_init_state[];
|