#include #include #include char *VtServerLog = "libventi/server"; int ventilogging; #define log not_the_log_library_call static char Eremoved[] = "[removed]"; enum { /* defaults */ LogChunkSize = 8192, LogSize = 65536 }; static struct { QLock lk; VtLog *hash[1024]; } vl; static uint hash(char *s) { uint h; uchar *p; h = 0; for(p=(uchar*)s; *p; p++) h = h*37 + *p; return h; } char** vtlognames(int *pn) { int i, nname, size; VtLog *l; char **s, *a, *e; qlock(&vl.lk); size = 0; nname = 0; for(i=0; inext){ nname++; size += strlen(l->name)+1; } s = vtmalloc(nname*sizeof(char*)+size); a = (char*)(s+nname); e = (char*)s+nname*sizeof(char*)+size; nname = 0; for(i=0; inext){ strcpy(a, l->name); s[nname++] = a; a += strlen(a)+1; } *pn = nname; assert(a == e); qunlock(&vl.lk); return s; } VtLog* vtlogopen(char *name, uint size) { uint h; int i, nc; char *p; VtLog *l, *last; if(!ventilogging) return nil; h = hash(name)%nelem(vl.hash); qlock(&vl.lk); last = nil; for(l=vl.hash[h]; l; last=l, l=l->next) if(strcmp(l->name, name) == 0){ if(last){ /* move to front */ last->next = l->next; l->next = vl.hash[h]; vl.hash[h] = l; } l->ref++; qunlock(&vl.lk); return l; } if(size == 0){ qunlock(&vl.lk); return nil; } /* allocate */ nc = (size+LogChunkSize-1)/LogChunkSize; l = vtmalloc(sizeof *l + nc*(sizeof(*l->chunk)+LogChunkSize) + strlen(name)+1); memset(l, 0, sizeof *l); l->chunk = (VtLogChunk*)(l+1); l->nchunk = nc; l->w = l->chunk; p = (char*)(l->chunk+nc); for(i=0; ichunk[i].p = p; l->chunk[i].wp = p; p += LogChunkSize; l->chunk[i].ep = p; } strcpy(p, name); l->name = p; /* insert */ l->next = vl.hash[h]; vl.hash[h] = l; l->ref++; l->ref++; qunlock(&vl.lk); return l; } void vtlogclose(VtLog *l) { if(l == nil) return; qlock(&vl.lk); if(--l->ref == 0){ /* must not be in hash table */ assert(l->name == Eremoved); free(l); }else assert(l->ref > 0); qunlock(&vl.lk); } void vtlogremove(char *name) { uint h; VtLog *last, *l; h = hash(name)%nelem(vl.hash); qlock(&vl.lk); last = nil; for(l=vl.hash[h]; l; last=l, l=l->next) if(strcmp(l->name, name) == 0){ if(last) last->next = l->next; else vl.hash[h] = l->next; l->name = Eremoved; l->next = nil; qunlock(&vl.lk); vtlogclose(l); return; } qunlock(&vl.lk); } static int timefmt(Fmt *fmt) { static uvlong t0; uvlong t; if(t0 == 0) t0 = nsec(); t = nsec()-t0; return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000); } void vtlogvprint(VtLog *l, char *fmt, va_list arg) { int n; char *p; VtLogChunk *c; static int first = 1; if(l == nil) return; if(first){ fmtinstall('T', timefmt); first = 0; } qlock(&l->lk); c = l->w; n = c->ep - c->wp; if(n < 512){ c++; if(c == l->chunk+l->nchunk) c = l->chunk; c->wp = c->p; l->w = c; } p = vseprint(c->wp, c->ep, fmt, arg); if(p) c->wp = p; qunlock(&l->lk); } void vtlogprint(VtLog *l, char *fmt, ...) { va_list arg; if(l == nil) return; va_start(arg, fmt); vtlogvprint(l, fmt, arg); va_end(arg); } void vtlog(char *name, char *fmt, ...) { VtLog *l; va_list arg; l = vtlogopen(name, LogSize); if(l == nil) return; va_start(arg, fmt); vtlogvprint(l, fmt, arg); va_end(arg); vtlogclose(l); } void vtlogdump(int fd, VtLog *l) { int i; VtLogChunk *c; if(l == nil) return; c = l->w; for(i=0; inchunk; i++){ if(++c == l->chunk+l->nchunk) c = l->chunk; write(fd, c->p, c->wp-c->p); } }