mirror of
https://github.com/GOSTSec/sgminer
synced 2025-01-10 14:58:01 +00:00
Optional lock tracking and stats via the API
This commit is contained in:
parent
bc0bb822bc
commit
c2073f0944
13
API-README
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
|
||||
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
|
||||
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:
|
||||
|
||||
|
||||
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)
|
||||
|
||||
Added API command:
|
||||
|
400
api.c
400
api.c
@ -136,7 +136,7 @@ static const char SEPARATOR = '|';
|
||||
#define SEPSTR "|"
|
||||
static const char GPUSEP = ',';
|
||||
|
||||
static const char *APIVERSION = "1.30";
|
||||
static const char *APIVERSION = "1.31";
|
||||
static const char *DEAD = "Dead";
|
||||
#if defined(HAVE_OPENCL) || defined(HAVE_AN_FPGA) || defined(HAVE_AN_ASIC)
|
||||
static const char *SICK = "Sick";
|
||||
@ -425,6 +425,8 @@ static const char *JSON_PARAMETER = "parameter";
|
||||
|
||||
#define MSG_INVNEG 121
|
||||
#define MSG_SETQUOTA 122
|
||||
#define MSG_LOCKOK 123
|
||||
#define MSG_LOCKDIS 124
|
||||
|
||||
enum code_severity {
|
||||
SEVERITY_ERR,
|
||||
@ -629,6 +631,8 @@ struct CODES {
|
||||
{ SEVERITY_SUCC, MSG_ASCSETOK, PARAM_BOTH, "ASC %d set OK" },
|
||||
{ SEVERITY_ERR, MSG_ASCSETERR, PARAM_BOTH, "ASC %d set failed: %s" },
|
||||
#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 }
|
||||
};
|
||||
|
||||
@ -1426,6 +1430,399 @@ static void message(struct io_data *io_data, int messageid, int paramid, char *p
|
||||
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)
|
||||
{
|
||||
struct api_data *root = NULL;
|
||||
@ -3872,6 +4269,7 @@ struct CMDS {
|
||||
{ "ascset", ascset, true },
|
||||
#endif
|
||||
{ "asccount", asccount, false },
|
||||
{ "lockstats", lockstats, true },
|
||||
{ NULL, NULL, false }
|
||||
};
|
||||
|
||||
|
10
cgminer.c
10
cgminer.c
@ -208,6 +208,10 @@ static int new_devices;
|
||||
static int new_threads;
|
||||
int hotplug_time = 5;
|
||||
|
||||
#if LOCK_TRACKING
|
||||
pthread_mutex_t lockstat_lock;
|
||||
#endif
|
||||
|
||||
#ifdef USE_USBUTILS
|
||||
pthread_mutex_t cgusb_lock;
|
||||
pthread_mutex_t cgusbres_lock;
|
||||
@ -7836,6 +7840,12 @@ int main(int argc, char *argv[])
|
||||
if (unlikely(curl_global_init(CURL_GLOBAL_ALL)))
|
||||
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));
|
||||
for (i = 0; i < argc; i++)
|
||||
initial_args[i] = strdup(argv[i]);
|
||||
|
175
miner.h
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);
|
||||
|
||||
#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[];
|
||||
|
Loading…
Reference in New Issue
Block a user