Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <venti.h>
5 int ventilogging;
6 #define log not_the_log_library_call
8 static char Eremoved[] = "[removed]";
10 enum
11 { /* defaults */
12 LogChunkSize = 8192,
13 LogSize = 65536,
14 };
16 static struct {
17 QLock lk;
18 VtLog *hash[1024];
19 } vl;
21 static uint
22 hash(char *s)
23 {
24 uint h;
25 uchar *p;
27 h = 0;
28 for(p=(uchar*)s; *p; p++)
29 h = h*37 + *p;
30 return h;
31 }
33 char**
34 vtlognames(int *pn)
35 {
36 int i, nname, size;
37 VtLog *l;
38 char **s, *a, *e;
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 }
49 s = vtmalloc(nname*sizeof(char*)+size);
50 a = (char*)(s+nname);
51 e = (char*)s+nname*sizeof(char*)+size;
53 size = 0;
54 nname = 0;
55 for(i=0; i<nelem(vl.hash); i++)
56 for(l=vl.hash[i]; l; l=l->next){
57 strcpy(a, l->name);
58 s[nname++] = a;
59 a += strlen(a)+1;
60 }
61 *pn = nname;
62 assert(a == e);
63 qunlock(&vl.lk);
65 return s;
66 }
68 VtLog*
69 vtlogopen(char *name, uint size)
70 {
71 uint h;
72 int i, nc;
73 char *p;
74 VtLog *l, *last;
76 if(!ventilogging)
77 return nil;
79 h = hash(name)%nelem(vl.hash);
80 qlock(&vl.lk);
81 last = nil;
82 for(l=vl.hash[h]; l; last=l, l=l->next)
83 if(strcmp(l->name, name) == 0){
84 if(last){ /* move to front */
85 last->next = l->next;
86 l->next = vl.hash[h];
87 vl.hash[h] = l;
88 }
89 l->ref++;
90 qunlock(&vl.lk);
91 return l;
92 }
94 if(size == 0){
95 qunlock(&vl.lk);
96 return nil;
97 }
99 /* allocate */
100 nc = (size+LogChunkSize-1)/LogChunkSize;
101 l = vtmalloc(sizeof *l + nc*(sizeof(*l->chunk)+LogChunkSize) + strlen(name)+1);
102 memset(l, 0, sizeof *l);
103 l->chunk = (VtLogChunk*)(l+1);
104 l->nchunk = nc;
105 l->w = l->chunk;
106 p = (char*)(l->chunk+nc);
107 for(i=0; i<nc; i++){
108 l->chunk[i].p = p;
109 l->chunk[i].wp = p;
110 p += LogChunkSize;
111 l->chunk[i].ep = p;
113 strcpy(p, name);
114 l->name = p;
116 /* insert */
117 l->next = vl.hash[h];
118 vl.hash[h] = l;
119 l->ref++;
121 l->ref++;
122 qunlock(&vl.lk);
123 return l;
126 void
127 vtlogclose(VtLog *l)
129 if(l == nil)
130 return;
132 qlock(&vl.lk);
133 if(--l->ref == 0){
134 /* must not be in hash table */
135 assert(l->name == Eremoved);
136 free(l);
137 }else
138 assert(l->ref > 0);
139 qunlock(&vl.lk);
142 void
143 vtlogremove(char *name)
145 uint h;
146 VtLog *last, *l;
148 h = hash(name)%nelem(vl.hash);
149 qlock(&vl.lk);
150 last = nil;
151 for(l=vl.hash[h]; l; last=l, l=l->next)
152 if(strcmp(l->name, name) == 0){
153 if(last)
154 last->next = l->next;
155 else
156 vl.hash[h] = l->next;
157 l->name = Eremoved;
158 l->next = nil;
159 qunlock(&vl.lk);
160 vtlogclose(l);
161 return;
163 qunlock(&vl.lk);
166 static int
167 timefmt(Fmt *fmt)
169 static uvlong t0;
170 uvlong t;
172 if(t0 == 0)
173 t0 = nsec();
174 t = nsec()-t0;
175 return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000);
178 void
179 vtlogvprint(VtLog *l, char *fmt, va_list arg)
181 int n;
182 char *p;
183 VtLogChunk *c;
184 static int first = 1;
186 if(l == nil)
187 return;
189 if(first){
190 fmtinstall('T', timefmt);
191 first = 0;
195 qlock(&l->lk);
196 c = l->w;
197 n = c->ep - c->wp;
198 if(n < 512){
199 c++;
200 if(c == l->chunk+l->nchunk)
201 c = l->chunk;
202 c->wp = c->p;
203 l->w = c;
205 p = vseprint(c->wp, c->ep, fmt, arg);
206 if(p)
207 c->wp = p;
208 qunlock(&l->lk);
211 void
212 vtlogprint(VtLog *l, char *fmt, ...)
214 va_list arg;
216 if(l == nil)
217 return;
219 va_start(arg, fmt);
220 vtlogvprint(l, fmt, arg);
221 va_end(arg);
224 void
225 vtlog(char *name, char *fmt, ...)
227 VtLog *l;
228 va_list arg;
230 l = vtlogopen(name, LogSize);
231 if(l == nil)
232 return;
233 va_start(arg, fmt);
234 vtlogvprint(l, fmt, arg);
235 va_end(arg);
236 vtlogclose(l);
239 void
240 vtlogdump(int fd, VtLog *l)
242 int i;
243 VtLogChunk *c;
245 if(l == nil)
246 return;
248 c = l->w;
249 for(i=0; i<l->nchunk; i++){
250 if(++c == l->chunk+l->nchunk)
251 c = l->chunk;
252 write(fd, c->p, c->wp-c->p);