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