#include "all.h"
/*
* Misc tools.
*/
static Lock lstatslk;
static Lstat none;
static Lstat *lstats;
static int lstatson;
int fatalaborts;
Alloc pathalloc =
{
.elsz = sizeof(Path),
.zeroing = 0,
};
void
fatal(char *fmt, ...)
{
va_list arg;
char *s;
va_start(arg, fmt);
s = vsmprint(fmt, arg);
vfprint(2, fmt, arg);
va_end(arg);
if(fs != nil && fs->dev != nil)
fprint(2, "%s: %s: fatal: %s\n", argv0, fs->dev, s);
else
fprint(2, "%s: fatal: %s\n", argv0, s);
free(s);
if(fatalaborts)
abort();
threadexitsall("fatal");
}
void
warn(char *fmt, ...)
{
va_list arg;
char *s;
va_start(arg, fmt);
s = vsmprint(fmt, arg);
va_end(arg);
if(fs != nil && fs->dev != nil)
fprint(2, "%s: %s: %s\n", argv0, fs->dev, s);
else
fprint(2, "%s: %s\n", argv0, s);
free(s);
}
void
warnerror(char *fmt, ...)
{
va_list arg;
char err[128];
va_start(arg, fmt);
vseprint(err, err+sizeof err, fmt, arg);
va_end(arg);
if(fs != nil && fs->dev != nil)
fprint(2, "%s: %s: %s\n", argv0, fs->dev, err);
else
fprint(2, "%s: %s\n", argv0, err);
error(err);
}
void
lockstats(int on)
{
if(lstats == nil && on)
lstats = mallocz(sizeof lstats[0] * Nlstats, 1);
lstatson = on;
}
void
dumplockstats(void)
{
static char *tname[] = {"qlock", "rwlock", "lock"};
int lon, i;
Lstat *lst;
lon = lstatson;
lstatson = 0;
fprint(2, "locks\tpc\tntimes\tncant\twtime\tmtime\n");
for(i = 0; i < Nlstats; i++){
lst = &lstats[i];
if(lst->ntimes != 0)
fprint(2, "src -n -s %#ullx %s\t# %s\t%d\t%d\t%ulld\t%ulld\t\n",
(uvlong)lst->pc, argv0, tname[lst->type], lst->ntimes,
lst->ncant, lst->wtime, lst->wtime/lst->ntimes);
}
lstatson = lon;
}
static Lstat*
getlstat(uintptr pc, int type)
{
Lstat *lst;
int i, h;
h = pc%Nlstats;
lock(&lstatslk);
for(i = 0; i < Nlstats; i++){
lst = &lstats[(h+i)%Nlstats];
if(lst->pc == 0){
lst->type = type;
lst->pc = pc;
}
if(lst->pc == pc){
unlock(&lstatslk);
return lst;
}
}
unlock(&lstatslk);
return &none;
}
void
xqlock(QLock *q)
{
vlong t;
Lstat *lst;
lst = nil;
t = 0;
if(lstats != nil){
lst = getlstat(getcallerpc(&q), Tqlock);
ainc(&lst->ntimes);
if(canqlock(q))
return;
ainc(&lst->ncant);
t = nsec();
}
qlock(q);
if(lstats != nil){
t = nsec() - t;
lock(&lstatslk);
lst->wtime += t;
unlock(&lstatslk);
}
}
void
xqunlock(QLock *q)
{
qunlock(q);
}
int
xcanqlock(QLock *q)
{
vlong t;
Lstat *lst;
t = 0;
if(lstats != nil){
lst = getlstat(getcallerpc(&q), Tqlock);
ainc(&lst->ntimes);
if(canqlock(q))
return 1;
ainc(&lst->ncant);
return 0;
}
return canqlock(q);
}
void
xrwlock(RWLock *rw, int iswr)
{
vlong t;
Lstat *lst;
lst = nil;
t = 0;
if(lstats != nil){
lst = getlstat(getcallerpc(&rw), Trwlock);
ainc(&lst->ntimes);
if(iswr){
if(canwlock(rw))
return;
}else
if(canrlock(rw))
return;
ainc(&lst->ncant);
t = nsec();
}
if(iswr)
wlock(rw);
else
rlock(rw);
if(lstats != nil){
t = nsec() - t;
lock(&lstatslk);
lst->wtime += t;
unlock(&lstatslk);
}
}
void
xrwunlock(RWLock *rw, int iswr)
{
if(iswr)
wunlock(rw);
else
runlock(rw);
}
void*
anew(Alloc *a)
{
Next *n;
assert(a->elsz > 0);
xqlock(a);
n = a->free;
if(n != nil){
a->free = n->next;
a->nfree--;
}else{
a->nalloc++;
n = mallocz(a->elsz, !a->zeroing);
}
xqunlock(a);
if(a->zeroing)
memset(n, 0, a->elsz);
return n;
}
void
afree(Alloc *a, void *nd)
{
Next *n;
if(nd == nil)
return;
n = nd;
xqlock(a);
n->next = a->free;
a->free = n;
a->nfree++;
xqunlock(a);
}
static void
xaddelem(Path *p, Memblk *f)
{
if(p->nf == p->naf){
p->naf += Incr;
p->f = realloc(p->f, p->naf*sizeof p->f[0]);
}
p->f[p->nf++] = f;
incref(f);
}
static Path*
duppath(Path *p)
{
Path *np;
int i;
np = newpath(p->f[0]);
for(i = 1; i < p->nf; i++)
xaddelem(np, p->f[i]);
return np;
}
void
ownpath(Path **pp)
{
Path *p;
p = *pp;
if(p->ref > 1){
*pp = duppath(p);
putpath(p);
}
}
Path*
addelem(Path **pp, Memblk *f)
{
Path *p;
ownpath(pp);
p = *pp;
xaddelem(p, f);
return p;
}
Path*
dropelem(Path **pp)
{
Path *p;
ownpath(pp);
p = *pp;
if(p->nf > 0)
mbput(p->f[--p->nf]);
return p;
}
Path*
newpath(Memblk *root)
{
Path *p;
p = anew(&pathalloc);
p->ref = 1;
xaddelem(p, root);
p->nroot = p->nf;
return p;
}
void
putpath(Path *p)
{
int i;
if(p == nil || decref(p) > 0)
return;
for(i = 0; i < p->nf; i++)
mbput(p->f[i]);
p->nf = 0;
afree(&pathalloc, p);
}
Path*
clonepath(Path *p)
{
incref(p);
return p;
}
int
pathfmt(Fmt *fmt)
{
Path *p;
int i;
p = va_arg(fmt->args, Path*);
if(p == nil)
return fmtprint(fmt, "/");
for(i = 0; i < p->nf; i++)
fmtprint(fmt, "p[%d] = %H", i, p->f[i]);
return 0;
}
|