Browse Source

Optional lock tracking and stats via the API

nfactor-troky
Kano 11 years ago committed by Con Kolivas
parent
commit
d3d3fc1316
  1. 13
      API-README
  2. 400
      api.c
  3. 10
      cgminer.c
  4. 175
      miner.h

13
API-README

@ -437,6 +437,12 @@ The list of requests - a (*) means it requires privileged access - and replies:
AVA+BTB opt=freq val=256 to 1024 - chip frequency AVA+BTB opt=freq val=256 to 1024 - chip frequency
BTB opt=millivolts val=1000 to 1400 - corevoltage BTB opt=millivolts val=1000 to 1400 - corevoltage
lockstats none There is no reply section just the STATUS section
stating the results of the request
A warning reply means lock stats are not compiled
into cgminer
The API writes all the lock stats to stderr
When you enable, disable or restart a GPU, PGA or ASC, you will also get When you enable, disable or restart a GPU, PGA or ASC, you will also get
Thread messages in the cgminer status window Thread messages in the cgminer status window
@ -491,6 +497,13 @@ miner.php - an example web page to access the API
Feature Changelog for external applications using the API: Feature Changelog for external applications using the API:
API V1.31 (cgminer v3.6.3)
Added API command:
'lockstats' - display cgminer dev lock stats if compiled in
---------
API V1.30 (cgminer v3.4.3) API V1.30 (cgminer v3.4.3)
Added API command: Added API command:

400
api.c

@ -136,7 +136,7 @@ static const char SEPARATOR = '|';
#define SEPSTR "|" #define SEPSTR "|"
static const char GPUSEP = ','; static const char GPUSEP = ',';
static const char *APIVERSION = "1.30"; static const char *APIVERSION = "1.31";
static const char *DEAD = "Dead"; static const char *DEAD = "Dead";
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) || defined(HAVE_AN_ASIC) #if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) || defined(HAVE_AN_ASIC)
static const char *SICK = "Sick"; static const char *SICK = "Sick";
@ -425,6 +425,8 @@ static const char *JSON_PARAMETER = "parameter";
#define MSG_INVNEG 121 #define MSG_INVNEG 121
#define MSG_SETQUOTA 122 #define MSG_SETQUOTA 122
#define MSG_LOCKOK 123
#define MSG_LOCKDIS 124
enum code_severity { enum code_severity {
SEVERITY_ERR, SEVERITY_ERR,
@ -629,6 +631,8 @@ struct CODES {
{ SEVERITY_SUCC, MSG_ASCSETOK, PARAM_BOTH, "ASC %d set OK" }, { SEVERITY_SUCC, MSG_ASCSETOK, PARAM_BOTH, "ASC %d set OK" },
{ SEVERITY_ERR, MSG_ASCSETERR, PARAM_BOTH, "ASC %d set failed: %s" }, { SEVERITY_ERR, MSG_ASCSETERR, PARAM_BOTH, "ASC %d set failed: %s" },
#endif #endif
{ SEVERITY_SUCC, MSG_LOCKOK, PARAM_NONE, "Lock stats created" },
{ SEVERITY_WARN, MSG_LOCKDIS, PARAM_NONE, "Lock stats not enabled" },
{ SEVERITY_FAIL, 0, 0, NULL } { SEVERITY_FAIL, 0, 0, NULL }
}; };
@ -1426,6 +1430,399 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p
io_add(io_data, JSON_CLOSE); io_add(io_data, JSON_CLOSE);
} }
#if LOCK_TRACKING
#define LOCK_FMT_FFL " - called from %s %s():%d"
#define LOCKMSG(fmt, ...) fprintf(stderr, "APILOCK: " fmt "\n", ##__VA_ARGS__)
#define LOCKMSGMORE(fmt, ...) fprintf(stderr, " " fmt "\n", ##__VA_ARGS__)
#define LOCKMSGFFL(fmt, ...) fprintf(stderr, "APILOCK: " fmt LOCK_FMT_FFL "\n", ##__VA_ARGS__, file, func, linenum)
#define LOCKMSGFLUSH() fflush(stderr)
typedef struct lockstat {
uint64_t lock_id;
const char *file;
const char *func;
int linenum;
struct timeval tv;
} LOCKSTAT;
typedef struct lockline {
struct lockline *prev;
struct lockstat *stat;
struct lockline *next;
} LOCKLINE;
typedef struct lockinfo {
void *lock;
enum cglock_typ typ;
const char *file;
const char *func;
int linenum;
uint64_t gets;
uint64_t gots;
uint64_t tries;
uint64_t dids;
uint64_t didnts; // should be tries - dids
uint64_t unlocks;
LOCKSTAT lastgot;
LOCKLINE *lockgets;
LOCKLINE *locktries;
} LOCKINFO;
typedef struct locklist {
LOCKINFO *info;
struct locklist *next;
} LOCKLIST;
static uint64_t lock_id = 1;
static LOCKLIST *lockhead;
static void lockmsgnow()
{
struct timeval now;
struct tm *tm;
time_t dt;
cgtime(&now);
dt = now.tv_sec;
tm = localtime(&dt);
LOCKMSG("%d-%02d-%02d %02d:%02d:%02d",
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
}
static LOCKLIST *newlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum)
{
LOCKLIST *list;
list = calloc(1, sizeof(*list));
if (!list)
quithere(1, "OOM list");
list->info = calloc(1, sizeof(*(list->info)));
if (!list->info)
quithere(1, "OOM info");
list->next = lockhead;
lockhead = list;
list->info->lock = lock;
list->info->typ = typ;
list->info->file = file;
list->info->func = func;
list->info->linenum = linenum;
return list;
}
static LOCKINFO *findlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum)
{
LOCKLIST *look;
look = lockhead;
while (look) {
if (look->info->lock == lock)
break;
look = look->next;
}
if (!look)
look = newlock(lock, typ, file, func, linenum);
return look->info;
}
static void addgettry(LOCKINFO *info, uint64_t id, const char *file, const char *func, const int linenum, bool get)
{
LOCKSTAT *stat;
LOCKLINE *line;
stat = calloc(1, sizeof(*stat));
if (!stat)
quithere(1, "OOM stat");
line = calloc(1, sizeof(*line));
if (!line)
quithere(1, "OOM line");
if (get)
info->gets++;
else
info->tries++;
stat->lock_id = id;
stat->file = file;
stat->func = func;
stat->linenum = linenum;
cgtime(&stat->tv);
line->stat = stat;
if (get) {
line->next = info->lockgets;
if (info->lockgets)
info->lockgets->prev = line;
info->lockgets = line;
} else {
line->next = info->locktries;
if (info->locktries)
info->locktries->prev = line;
info->locktries = line;
}
}
static void markgotdid(LOCKINFO *info, uint64_t id, const char *file, const char *func, const int linenum, bool got, int ret)
{
LOCKLINE *line;
if (got)
info->gots++;
else {
if (ret == 0)
info->dids++;
else
info->didnts++;
}
if (got || ret == 0) {
info->lastgot.lock_id = id;
info->lastgot.file = file;
info->lastgot.func = func;
info->lastgot.linenum = linenum;
cgtime(&info->lastgot.tv);
}
if (got)
line = info->lockgets;
else
line = info->locktries;
while (line) {
if (line->stat->lock_id == id)
break;
line = line->next;
}
if (!line) {
lockmsgnow();
LOCKMSGFFL("ERROR attempt to mark a lock as '%s' that wasn't '%s' id=%"PRIu64,
got ? "got" : "did/didnt", got ? "get" : "try", id);
}
// Unlink it
if (line->prev)
line->prev->next = line->next;
if (line->next)
line->next->prev = line->prev;
if (got) {
if (info->lockgets == line)
info->lockgets = line->next;
} else {
if (info->locktries == line)
info->locktries = line->next;
}
free(line->stat);
free(line);
}
// Yes this uses locks also ... ;/
static void locklock()
{
if (unlikely(pthread_mutex_lock(&lockstat_lock)))
quithere(1, "WTF MUTEX ERROR ON LOCK! errno=%d", errno);
}
static void lockunlock()
{
if (unlikely(pthread_mutex_unlock(&lockstat_lock)))
quithere(1, "WTF MUTEX ERROR ON UNLOCK! errno=%d", errno);
}
uint64_t api_getlock(void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
uint64_t id;
locklock();
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
id = lock_id++;
addgettry(info, id, file, func, linenum, true);
lockunlock();
return id;
}
void api_gotlock(uint64_t id, void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
locklock();
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
markgotdid(info, id, file, func, linenum, true, 0);
lockunlock();
}
uint64_t api_trylock(void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
uint64_t id;
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
id = lock_id++;
addgettry(info, id, file, func, linenum, false);
return id;
}
void api_didlock(uint64_t id, int ret, void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
locklock();
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
markgotdid(info, id, file, func, linenum, false, ret);
lockunlock();
}
void api_gunlock(void *lock, const char *file, const char *func, const int linenum)
{
LOCKINFO *info;
locklock();
info = findlock(lock, CGLOCK_UNKNOWN, file, func, linenum);
info->unlocks++;
lockunlock();
}
void api_initlock(void *lock, enum cglock_typ typ, const char *file, const char *func, const int linenum)
{
locklock();
findlock(lock, typ, file, func, linenum);
lockunlock();
}
void dsp_det(char *msg, LOCKSTAT *stat)
{
struct tm *tm;
time_t dt;
dt = stat->tv.tv_sec;
tm = localtime(&dt);
LOCKMSGMORE("%s id=%"PRIu64" by %s %s():%d at %d-%02d-%02d %02d:%02d:%02d",
msg,
stat->lock_id,
stat->file,
stat->func,
stat->linenum,
tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour,
tm->tm_min,
tm->tm_sec);
}
void dsp_lock(LOCKINFO *info)
{
LOCKLINE *line;
char *status;
LOCKMSG("Lock %p created by %s %s():%d",
info->lock,
info->file,
info->func,
info->linenum);
LOCKMSGMORE("gets:%"PRIu64" gots:%"PRIu64" tries:%"PRIu64
" dids:%"PRIu64" didnts:%"PRIu64" unlocks:%"PRIu64,
info->gets,
info->gots,
info->tries,
info->dids,
info->didnts,
info->unlocks);
if (info->gots > 0 || info->dids > 0) {
if (info->unlocks < info->gots + info->dids)
status = "Last got/did still HELD";
else
status = "Last got/did (idle)";
dsp_det(status, &(info->lastgot));
} else
LOCKMSGMORE("... unused ...");
if (info->lockgets) {
LOCKMSGMORE("BLOCKED gets (%"PRIu64")", info->gets - info->gots);
line = info->lockgets;
while (line) {
dsp_det("", line->stat);
line = line->next;
}
} else
LOCKMSGMORE("no blocked gets");
if (info->locktries) {
LOCKMSGMORE("BLOCKED tries (%"PRIu64")", info->tries - info->dids - info->didnts);
line = info->lockgets;
while (line) {
dsp_det("", line->stat);
line = line->next;
}
} else
LOCKMSGMORE("no blocked tries");
}
void show_locks()
{
LOCKLIST *list;
locklock();
lockmsgnow();
list = lockhead;
if (!list)
LOCKMSG("no locks?!?\n");
else {
while (list) {
dsp_lock(list->info);
list = list->next;
}
}
LOCKMSGFLUSH();
lockunlock();
}
#endif
static void lockstats(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
{
#if LOCK_TRACKING
show_locks();
message(io_data, MSG_LOCKOK, 0, NULL, isjson);
#else
message(io_data, MSG_LOCKDIS, 0, NULL, isjson);
#endif
}
static void apiversion(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group) static void apiversion(struct io_data *io_data, __maybe_unused SOCKETTYPE c, __maybe_unused char *param, bool isjson, __maybe_unused char group)
{ {
struct api_data *root = NULL; struct api_data *root = NULL;
@ -3872,6 +4269,7 @@ struct CMDS {
{ "ascset", ascset, true }, { "ascset", ascset, true },
#endif #endif
{ "asccount", asccount, false }, { "asccount", asccount, false },
{ "lockstats", lockstats, true },
{ NULL, NULL, false } { NULL, NULL, false }
}; };

10
cgminer.c

@ -208,6 +208,10 @@ static int new_devices;
static int new_threads; static int new_threads;
int hotplug_time = 5; int hotplug_time = 5;
#if LOCK_TRACKING
pthread_mutex_t lockstat_lock;
#endif
#ifdef USE_USBUTILS #ifdef USE_USBUTILS
pthread_mutex_t cgusb_lock; pthread_mutex_t cgusb_lock;
pthread_mutex_t cgusbres_lock; pthread_mutex_t cgusbres_lock;
@ -7840,6 +7844,12 @@ int main(int argc, char *argv[])
if (unlikely(curl_global_init(CURL_GLOBAL_ALL))) if (unlikely(curl_global_init(CURL_GLOBAL_ALL)))
quit(1, "Failed to curl_global_init"); quit(1, "Failed to curl_global_init");
#if LOCK_TRACKING
// Must be first
if (unlikely(pthread_mutex_init(&lockstat_lock, NULL)))
quithere(1, "Failed to pthread_mutex_init lockstat_lock errno=%d", errno);
#endif
initial_args = malloc(sizeof(char *) * (argc + 1)); initial_args = malloc(sizeof(char *) * (argc + 1));
for (i = 0; i < argc; i++) for (i = 0; i < argc; i++)
initial_args[i] = strdup(argv[i]); initial_args[i] = strdup(argv[i]);

175
miner.h

@ -737,74 +737,143 @@ endian_flip128(void __maybe_unused *dest_p, const void __maybe_unused *src_p)
extern void _quit(int status); 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__) * Set this to non-zero to enable lock tracking
#define wr_lock(_lock) _wr_lock(_lock, __FILE__, __func__, __LINE__) * Use the API lockstats command to see the locking status on stderr
#define rd_lock(_lock) _rd_lock(_lock, __FILE__, __func__, __LINE__) * i.e. in your log file if you 2> log.log - but not on the screen
#define rw_unlock(_lock) _rw_unlock(_lock, __FILE__, __func__, __LINE__) * API lockstats is privilidged but will always exist and will return
#define mutex_init(_lock) _mutex_init(_lock, __FILE__, __func__, __LINE__) * success if LOCK_TRACKING is enabled and warning if disabled
#define rwlock_init(_lock) _rwlock_init(_lock, __FILE__, __func__, __LINE__) * 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) 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))) if (unlikely(pthread_mutex_lock(lock)))
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON LOCK! errno=%d", errno); 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) 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))) if (unlikely(pthread_mutex_unlock(lock)))
quitfrom(1, file, func, line, "WTF MUTEX ERROR ON UNLOCK! errno=%d", errno); 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(); 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) 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))) if (unlikely(pthread_rwlock_wrlock(lock)))
quitfrom(1, file, func, line, "WTF WRLOCK ERROR ON LOCK! errno=%d", errno); 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) 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))) if (unlikely(pthread_rwlock_rdlock(lock)))
quitfrom(1, file, func, line, "WTF RDLOCK ERROR ON LOCK! errno=%d", errno); 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) static inline void _rw_unlock(pthread_rwlock_t *lock, const char *file, const char *func, const int line)
{ {
if (unlikely(pthread_rwlock_unlock(lock))) if (unlikely(pthread_rwlock_unlock(lock)))
quitfrom(1, file, func, line, "WTF RWLOCK ERROR ON UNLOCK! errno=%d", errno); 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(); 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(); 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))) if (unlikely(pthread_mutex_init(lock, NULL)))
quitfrom(1, file, func, line, "Failed to pthread_mutex_init errno=%d", errno); 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) 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))) if (unlikely(pthread_rwlock_init(lock, NULL)))
quitfrom(1, file, func, line, "Failed to pthread_rwlock_init errno=%d", errno); 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); _mutex_init(&lock->mutex, file, func, line);
rwlock_init(&lock->rwlock); _rwlock_init(&lock->rwlock, file, func, line);
} }
/* Read lock variant of cglock. Cannot be promoted. */ /* 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); _mutex_lock(&lock->mutex, file, func, line);
rd_lock(&lock->rwlock); _rd_lock(&lock->rwlock, file, func, line);
mutex_unlock_noyield(&lock->mutex); _mutex_unlock_noyield(&lock->mutex, file, func, line);
} }
/* Intermediate variant of cglock - behaves as a read lock but can be promoted /* Intermediate variant of cglock - behaves as a read lock but can be promoted
* to a write lock or demoted to read lock. */ * 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 */ /* 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 */ /* 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); _mutex_lock(&lock->mutex, file, func, line);
wr_lock(&lock->rwlock); _wr_lock(&lock->rwlock, file, func, line);
} }
/* Downgrade write variant to a read lock */ /* 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); _wr_unlock_noyield(&lock->rwlock, file, func, line);
rd_lock(&lock->rwlock); _rd_lock(&lock->rwlock, file, func, line);
mutex_unlock_noyield(&lock->mutex); _mutex_unlock_noyield(&lock->mutex, file, func, line);
} }
/* Demote a write variant to an intermediate variant */ /* 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 */ /* 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); _rd_lock(&lock->rwlock, file, func, line);
mutex_unlock_noyield(&lock->mutex); _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 /* This drops the read lock and grabs a write lock. It does NOT protect data
* between the two locks! */ * 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); _rd_unlock_noyield(&lock->rwlock, file, func, line);
cg_wlock(lock); _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); _wr_unlock_noyield(&lock->rwlock, file, func, line);
mutex_unlock(&lock->mutex); _mutex_unlock(&lock->mutex, file, func, line);
} }
struct pool; struct pool;
@ -942,6 +1013,10 @@ extern bool opt_bfl_noncerange;
#endif #endif
extern int swork_id; extern int swork_id;
#if LOCK_TRACKING
extern pthread_mutex_t lockstat_lock;
#endif
extern pthread_rwlock_t netacc_lock; extern pthread_rwlock_t netacc_lock;
extern const uint32_t sha256_init_state[]; extern const uint32_t sha256_init_state[];

Loading…
Cancel
Save