log.c 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <venti.h>
  12. char *VtServerLog = "libventi/server";
  13. int ventilogging;
  14. #define log not_the_log_library_call
  15. static char Eremoved[] = "[removed]";
  16. enum
  17. { /* defaults */
  18. LogChunkSize = 8192,
  19. LogSize = 65536
  20. };
  21. static struct {
  22. QLock lk;
  23. VtLog *hash[1024];
  24. } vl;
  25. static uint
  26. hash(char *s)
  27. {
  28. uint h;
  29. uint8_t *p;
  30. h = 0;
  31. for(p=(uint8_t*)s; *p; p++)
  32. h = h*37 + *p;
  33. return h;
  34. }
  35. char**
  36. vtlognames(int *pn)
  37. {
  38. int i, nname, size;
  39. VtLog *l;
  40. char **s, *a, *e;
  41. qlock(&vl.lk);
  42. size = 0;
  43. nname = 0;
  44. for(i=0; i<nelem(vl.hash); i++)
  45. for(l=vl.hash[i]; l; l=l->next){
  46. nname++;
  47. size += strlen(l->name)+1;
  48. }
  49. s = vtmalloc(nname*sizeof(char*)+size);
  50. a = (char*)(s+nname);
  51. e = (char*)s+nname*sizeof(char*)+size;
  52. nname = 0;
  53. for(i=0; i<nelem(vl.hash); i++)
  54. for(l=vl.hash[i]; l; l=l->next){
  55. strcpy(a, l->name);
  56. s[nname++] = a;
  57. a += strlen(a)+1;
  58. }
  59. *pn = nname;
  60. assert(a == e);
  61. qunlock(&vl.lk);
  62. return s;
  63. }
  64. VtLog*
  65. vtlogopen(char *name, uint size)
  66. {
  67. uint h;
  68. int i, nc;
  69. char *p;
  70. VtLog *l, *last;
  71. if(!ventilogging)
  72. return nil;
  73. h = hash(name)%nelem(vl.hash);
  74. qlock(&vl.lk);
  75. last = nil;
  76. for(l=vl.hash[h]; l; last=l, l=l->next)
  77. if(strcmp(l->name, name) == 0){
  78. if(last){ /* move to front */
  79. last->next = l->next;
  80. l->next = vl.hash[h];
  81. vl.hash[h] = l;
  82. }
  83. l->ref++;
  84. qunlock(&vl.lk);
  85. return l;
  86. }
  87. if(size == 0){
  88. qunlock(&vl.lk);
  89. return nil;
  90. }
  91. /* allocate */
  92. nc = (size+LogChunkSize-1)/LogChunkSize;
  93. l = vtmalloc(sizeof *l + nc*(sizeof(*l->chunk)+LogChunkSize) + strlen(name)+1);
  94. memset(l, 0, sizeof *l);
  95. l->chunk = (VtLogChunk*)(l+1);
  96. l->nchunk = nc;
  97. l->w = l->chunk;
  98. p = (char*)(l->chunk+nc);
  99. for(i=0; i<nc; i++){
  100. l->chunk[i].p = p;
  101. l->chunk[i].wp = p;
  102. p += LogChunkSize;
  103. l->chunk[i].ep = p;
  104. }
  105. strcpy(p, name);
  106. l->name = p;
  107. /* insert */
  108. l->next = vl.hash[h];
  109. vl.hash[h] = l;
  110. l->ref++;
  111. l->ref++;
  112. qunlock(&vl.lk);
  113. return l;
  114. }
  115. void
  116. vtlogclose(VtLog *l)
  117. {
  118. if(l == nil)
  119. return;
  120. qlock(&vl.lk);
  121. if(--l->ref == 0){
  122. /* must not be in hash table */
  123. assert(l->name == Eremoved);
  124. free(l);
  125. }else
  126. assert(l->ref > 0);
  127. qunlock(&vl.lk);
  128. }
  129. void
  130. vtlogremove(char *name)
  131. {
  132. uint h;
  133. VtLog *last, *l;
  134. h = hash(name)%nelem(vl.hash);
  135. qlock(&vl.lk);
  136. last = nil;
  137. for(l=vl.hash[h]; l; last=l, l=l->next)
  138. if(strcmp(l->name, name) == 0){
  139. if(last)
  140. last->next = l->next;
  141. else
  142. vl.hash[h] = l->next;
  143. l->name = Eremoved;
  144. l->next = nil;
  145. qunlock(&vl.lk);
  146. vtlogclose(l);
  147. return;
  148. }
  149. qunlock(&vl.lk);
  150. }
  151. static int
  152. timefmt(Fmt *fmt)
  153. {
  154. static uint64_t t0;
  155. uint64_t t;
  156. if(t0 == 0)
  157. t0 = nsec();
  158. t = nsec()-t0;
  159. return fmtprint(fmt, "T+%d.%04d", (uint)(t/1000000000), (uint)(t%1000000000)/100000);
  160. }
  161. void
  162. vtlogvprint(VtLog *l, char *fmt, ...)
  163. {
  164. int n;
  165. char *p;
  166. VtLogChunk *c;
  167. static int first = 1;
  168. va_list arg;
  169. if(l == nil)
  170. return;
  171. if(first){
  172. fmtinstall('T', timefmt);
  173. first = 0;
  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. va_start(arg, fmt);
  186. p = vseprint(c->wp, c->ep, fmt, arg);
  187. va_end(arg);
  188. if(p)
  189. c->wp = p;
  190. qunlock(&l->lk);
  191. }
  192. void
  193. vtlogprint(VtLog *l, char *fmt, ...)
  194. {
  195. va_list arg;
  196. if(l == nil)
  197. return;
  198. va_start(arg, fmt);
  199. vtlogvprint(l, fmt, arg);
  200. va_end(arg);
  201. }
  202. void
  203. vtlog(char *name, char *fmt, ...)
  204. {
  205. VtLog *l;
  206. va_list arg;
  207. l = vtlogopen(name, LogSize);
  208. if(l == nil)
  209. return;
  210. va_start(arg, fmt);
  211. vtlogvprint(l, fmt, arg);
  212. va_end(arg);
  213. vtlogclose(l);
  214. }
  215. void
  216. vtlogdump(int fd, VtLog *l)
  217. {
  218. int i;
  219. VtLogChunk *c;
  220. if(l == nil)
  221. return;
  222. c = l->w;
  223. for(i=0; i<l->nchunk; i++){
  224. if(++c == l->chunk+l->nchunk)
  225. c = l->chunk;
  226. write(fd, c->p, c->wp-c->p);
  227. }
  228. }