1 #include <u.h> 2 #include <libc.h> 3 #include <venti.h> 4 5 char *VtServerLog = "libventi/server"; 6 7 int ventilogging; 8 #define log not_the_log_library_call 9 10 static char Eremoved[] = "[removed]"; 11 12 enum 13 { /* defaults */ 14 LogChunkSize = 8192, 15 LogSize = 65536 16 }; 17 18 static struct { 19 QLock lk; 20 VtLog *hash[1024]; 21 } vl; 22 23 static uint 24 hash(char *s) 25 { 26 uint h; 27 uchar *p; 28 29 h = 0; 30 for(p=(uchar*)s; *p; p++) 31 h = h*37 + *p; 32 return h; 33 } 34 35 char** 36 vtlognames(int *pn) 37 { 38 int i, nname, size; 39 VtLog *l; 40 char **s, *a, *e; 41 42 qlock(&vl.lk); 43 size = 0; 44 nname = 0; 45 for(i=0; i<nelem(vl.hash); i++) 46 for(l=vl.hash[i]; l; l=l->next){ 47 nname++; 48 size += strlen(l->name)+1; 49 } 50 51 s = vtmalloc(nname*sizeof(char*)+size); 52 a = (char*)(s+nname); 53 e = (char*)s+nname*sizeof(char*)+size; 54 55 nname = 0; 56 for(i=0; i<nelem(vl.hash); i++) 57 for(l=vl.hash[i]; l; l=l->next){ 58 strcpy(a, l->name); 59 s[nname++] = a; 60 a += strlen(a)+1; 61 } 62 *pn = nname; 63 assert(a == e); 64 qunlock(&vl.lk); 65 66 return s; 67 } 68 69 VtLog* 70 vtlogopen(char *name, uint size) 71 { 72 uint h; 73 int i, nc; 74 char *p; 75 VtLog *l, *last; 76 77 if(!ventilogging) 78 return nil; 79 80 h = hash(name)%nelem(vl.hash); 81 qlock(&vl.lk); 82 last = nil; 83 for(l=vl.hash[h]; l; last=l, l=l->next) 84 if(strcmp(l->name, name) == 0){ 85 if(last){ /* move to front */ 86 last->next = l->next; 87 l->next = vl.hash[h]; 88 vl.hash[h] = l; 89 } 90 l->ref++; 91 qunlock(&vl.lk); 92 return l; 93 } 94 95 if(size == 0){ 96 qunlock(&vl.lk); 97 return nil; 98 } 99 100 /* allocate */ 101 nc = (size+LogChunkSize-1)/LogChunkSize; 102 l = vtmalloc(sizeof *l + nc*(sizeof(*l->chunk)+LogChunkSize) + strlen(name)+1); 103 memset(l, 0, sizeof *l); 104 l->chunk = (VtLogChunk*)(l+1); 105 l->nchunk = nc; 106 l->w = l->chunk; 107 p = (char*)(l->chunk+nc); 108 for(i=0; i<nc; i++){ 109 l->chunk[i].p = p; 110 l->chunk[i].wp = p; 111 p += LogChunkSize; 112 l->chunk[i].ep = p; 113 } 114 strcpy(p, name); 115 l->name = p; 116 117 /* insert */ 118 l->next = vl.hash[h]; 119 vl.hash[h] = l; 120 l->ref++; 121 122 l->ref++; 123 qunlock(&vl.lk); 124 return l; 125 } 126 127 void 128 vtlogclose(VtLog *l) 129 { 130 if(l == nil) 131 return; 132 133 qlock(&vl.lk); 134 if(--l->ref == 0){ 135 /* must not be in hash table */ 136 assert(l->name == Eremoved); 137 free(l); 138 }else 139 assert(l->ref > 0); 140 qunlock(&vl.lk); 141 } 142 143 void 144 vtlogremove(char *name) 145 { 146 uint h; 147 VtLog *last, *l; 148 149 h = hash(name)%nelem(vl.hash); 150 qlock(&vl.lk); 151 last = nil; 152 for(l=vl.hash[h]; l; last=l, l=l->next) 153 if(strcmp(l->name, name) == 0){ 154 if(last) 155 last->next = l->next; 156 else 157 vl.hash[h] = l->next; 158 l->name = Eremoved; 159 l->next = nil; 160 qunlock(&vl.lk); 161 vtlogclose(l); 162 return; 163 } 164 qunlock(&vl.lk); 165 } 166 167 static int 168 timefmt(Fmt *fmt) 169 { 170 static uvlong t0; 171 uvlong t; 172 Tm tm; 173 174 if(fmt->flags&FmtSharp){ 175 if(t0 == 0) 176 t0 = nsec(); 177 t = nsec()-t0; 178 return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000); 179 }else{ 180 tm = *localtime(time(0)); 181 return fmtprint(fmt, "%04d/%02d%02d %02d:%02d:%02d", 182 1900+tm.year, tm.mon+1, tm.mday, tm.hour, tm.min, tm.sec); 183 } 184 } 185 186 void 187 vtlogvprint(VtLog *l, char *fmt, va_list arg) 188 { 189 int n; 190 char *p; 191 VtLogChunk *c; 192 static int first = 1; 193 194 if(l == nil) 195 return; 196 197 if(first){ 198 fmtinstall('T', timefmt); 199 first = 0; 200 } 201 202 203 qlock(&l->lk); 204 c = l->w; 205 n = c->ep - c->wp; 206 if(n < 512){ 207 c++; 208 if(c == l->chunk+l->nchunk) 209 c = l->chunk; 210 c->wp = c->p; 211 l->w = c; 212 } 213 p = vseprint(c->wp, c->ep, fmt, arg); 214 if(p) 215 c->wp = p; 216 qunlock(&l->lk); 217 } 218 219 void 220 vtlogprint(VtLog *l, char *fmt, ...) 221 { 222 va_list arg; 223 224 if(l == nil) 225 return; 226 227 va_start(arg, fmt); 228 vtlogvprint(l, fmt, arg); 229 va_end(arg); 230 } 231 232 void 233 vtlog(char *name, char *fmt, ...) 234 { 235 VtLog *l; 236 va_list arg; 237 238 l = vtlogopen(name, LogSize); 239 if(l == nil) 240 return; 241 va_start(arg, fmt); 242 vtlogvprint(l, fmt, arg); 243 va_end(arg); 244 vtlogclose(l); 245 } 246 247 void 248 vtlogdump(int fd, VtLog *l) 249 { 250 int i; 251 VtLogChunk *c; 252 253 if(l == nil) 254 return; 255 256 c = l->w; 257 for(i=0; i<l->nchunk; i++){ 258 if(++c == l->chunk+l->nchunk) 259 c = l->chunk; 260 write(fd, c->p, c->wp-c->p); 261 } 262 } 263 264