@ -737,74 +737,143 @@ endian_flip128(void __maybe_unused *dest_p, const void __maybe_unused *src_p)
@@ -737,74 +737,143 @@ endian_flip128(void __maybe_unused *dest_p, const void __maybe_unused *src_p)
extern void _quit ( int status ) ;
/*
* 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
@@ -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;
@@ -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 [ ] ;
@ -1329,6 +1404,8 @@ struct work {
@@ -1329,6 +1404,8 @@ struct work {
int subid ;
// Allow devices to flag work for their own purposes
bool devflag ;
// Allow devices to timestamp work for their own purposes
struct timeval tv_stamp ;
struct timeval tv_getwork ;
struct timeval tv_getwork_reply ;