alloc.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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 "../port/lib.h"
  11. #include "mem.h"
  12. #include "dat.h"
  13. #include "fns.h"
  14. #include <pool.h>
  15. extern void* xalloc(ulong);
  16. extern void xinit(void);
  17. extern int xmerge(void*, void*);
  18. static void poolprint(Pool*, char*, ...);
  19. static void ppanic(Pool*, char*, ...);
  20. static void plock(Pool*);
  21. static void punlock(Pool*);
  22. typedef struct Private Private;
  23. struct Private {
  24. Lock lk;
  25. char* end;
  26. char msg[256]; /* a rock for messages to be printed at unlock */
  27. };
  28. static Private pmainpriv;
  29. static Pool pmainmem = {
  30. .name= "Main",
  31. .maxsize= 4*1024*1024,
  32. .minarena= 128*1024,
  33. .quantum= 32,
  34. .alloc= xalloc,
  35. .merge= xmerge,
  36. .flags= /*POOL_TOLERANCE|POOL_ANTAGONISM|POOL_PARANOIA|*/0,
  37. .lock= plock,
  38. .unlock= punlock,
  39. .print= poolprint,
  40. .panic= ppanic,
  41. .private= &pmainpriv,
  42. };
  43. static Private pimagpriv;
  44. static Pool pimagmem = {
  45. .name= "Image",
  46. .maxsize= 16*1024*1024,
  47. .minarena= 2*1024*1024,
  48. .quantum= 32,
  49. .alloc= xalloc,
  50. .merge= xmerge,
  51. .flags= 0,
  52. .lock= plock,
  53. .unlock= punlock,
  54. .print= poolprint,
  55. .panic= ppanic,
  56. .private= &pimagpriv,
  57. };
  58. Pool* mainmem = &pmainmem;
  59. Pool* imagmem = &pimagmem;
  60. /*
  61. * because we can't print while we're holding the locks,
  62. * we have the save the message and print it once we let go.
  63. */
  64. static void
  65. poolprint(Pool *p, char *fmt, ...)
  66. {
  67. va_list v;
  68. Private *pv;
  69. pv = p->private;
  70. va_start(v, fmt);
  71. pv->end = vseprint(pv->end, &pv->msg[sizeof pv->msg], fmt, v);
  72. va_end(v);
  73. }
  74. static void
  75. ppanic(Pool *p, char *fmt, ...)
  76. {
  77. va_list v;
  78. Private *pv;
  79. char msg[sizeof pv->msg];
  80. pv = p->private;
  81. va_start(v, fmt);
  82. vseprint(pv->end, &pv->msg[sizeof pv->msg], fmt, v);
  83. va_end(v);
  84. memmove(msg, pv->msg, sizeof msg);
  85. iunlock(&pv->lk);
  86. panic("%s", msg);
  87. }
  88. static void
  89. plock(Pool *p)
  90. {
  91. Private *pv;
  92. pv = p->private;
  93. ilock(&pv->lk);
  94. pv->lk.pc = getcallerpc(&p);
  95. pv->end = pv->msg;
  96. }
  97. static void
  98. punlock(Pool *p)
  99. {
  100. Private *pv;
  101. char msg[sizeof pv->msg];
  102. pv = p->private;
  103. if(pv->end == pv->msg){
  104. iunlock(&pv->lk);
  105. return;
  106. }
  107. memmove(msg, pv->msg, sizeof msg);
  108. pv->end = pv->msg;
  109. iunlock(&pv->lk);
  110. iprint("%.*s", sizeof pv->msg, msg);
  111. }
  112. static char*
  113. poolsummary(Pool* p, char* s, char* e)
  114. {
  115. return seprint(s, e, "%s max %lud cur %lud free %lud alloc %lud\n",
  116. p->name, p->maxsize, p->cursize, p->curfree, p->curalloc);
  117. }
  118. void
  119. mallocsummary(void)
  120. {
  121. char buf[256], *p;
  122. p = poolsummary(mainmem, buf, buf+sizeof(buf));
  123. poolsummary(imagmem, p, buf+sizeof(buf));
  124. print(buf);
  125. }
  126. int32_t
  127. mallocreadsummary(Chan*, void *a, int32_t n, int32_t offset)
  128. {
  129. char buf[256], *p;
  130. p = poolsummary(mainmem, buf, buf+sizeof(buf));
  131. poolsummary(imagmem, p, buf+sizeof(buf));
  132. return readstr(offset, a, n, buf);
  133. }
  134. void
  135. mallocinit(void)
  136. {
  137. xinit();
  138. }
  139. /* everything from here down should be the same in libc, libdebugmalloc, and the kernel */
  140. /* - except the code for malloc(), which alternately doesn't clear or does. */
  141. /* - except the code for smalloc(), which lives only in the kernel. */
  142. /*
  143. * Npadlong is the number of 32-bit longs to leave at the beginning of
  144. * each allocated buffer for our own bookkeeping. We return to the callers
  145. * a pointer that points immediately after our bookkeeping area. Incoming pointers
  146. * must be decremented by that much, and outgoing pointers incremented.
  147. * The malloc tag is stored at MallocOffset from the beginning of the block,
  148. * and the realloc tag at ReallocOffset. The offsets are from the true beginning
  149. * of the block, not the beginning the caller sees.
  150. *
  151. * The extra if(Npadlong != 0) in various places is a hint for the compiler to
  152. * compile out function calls that would otherwise be no-ops.
  153. */
  154. /* non tracing
  155. *
  156. enum {
  157. Npadlong = 0,
  158. MallocOffset = 0,
  159. ReallocOffset = 0,
  160. };
  161. *
  162. */
  163. /* tracing */
  164. enum {
  165. Npadlong = 2,
  166. MallocOffset = 0,
  167. ReallocOffset = 1
  168. };
  169. void*
  170. smalloc(uint32_t size)
  171. {
  172. void *v;
  173. for(;;) {
  174. v = poolalloc(mainmem, size+Npadlong*sizeof(uint32_t));
  175. if(v != nil)
  176. break;
  177. tsleep(&up->sleep, return0, 0, 100);
  178. }
  179. if(Npadlong){
  180. v = (uint32_t*)v+Npadlong;
  181. setmalloctag(v, getcallerpc(&size));
  182. }
  183. memset(v, 0, size);
  184. return v;
  185. }
  186. void*
  187. malloc(uint32_t size)
  188. {
  189. void *v;
  190. v = poolalloc(mainmem, size+Npadlong*sizeof(uint32_t));
  191. if(v == nil)
  192. return nil;
  193. if(Npadlong){
  194. v = (uint32_t*)v+Npadlong;
  195. setmalloctag(v, getcallerpc(&size));
  196. setrealloctag(v, 0);
  197. }
  198. memset(v, 0, size);
  199. return v;
  200. }
  201. void*
  202. mallocz(uint32_t size, int clr)
  203. {
  204. void *v;
  205. v = poolalloc(mainmem, size+Npadlong*sizeof(uint32_t));
  206. if(Npadlong && v != nil){
  207. v = (uint32_t*)v+Npadlong;
  208. setmalloctag(v, getcallerpc(&size));
  209. setrealloctag(v, 0);
  210. }
  211. if(clr && v != nil)
  212. memset(v, 0, size);
  213. return v;
  214. }
  215. void*
  216. mallocalign(uint32_t size, uint32_t align, int32_t offset, uint32_t span)
  217. {
  218. void *v;
  219. v = poolallocalign(mainmem, size+Npadlong*sizeof(uint32_t), align,
  220. offset-Npadlong*sizeof(uint32_t), span);
  221. if(Npadlong && v != nil){
  222. v = (uint32_t*)v+Npadlong;
  223. setmalloctag(v, getcallerpc(&size));
  224. setrealloctag(v, 0);
  225. }
  226. return v;
  227. }
  228. void
  229. free(void *v)
  230. {
  231. if(v != nil)
  232. poolfree(mainmem, (uint32_t*)v-Npadlong);
  233. }
  234. void*
  235. realloc(void *v, uint32_t size)
  236. {
  237. void *nv;
  238. if(v != nil)
  239. v = (uint32_t*)v-Npadlong;
  240. if(Npadlong !=0 && size != 0)
  241. size += Npadlong*sizeof(uint32_t);
  242. if(nv = poolrealloc(mainmem, v, size)){
  243. nv = (uint32_t*)nv+Npadlong;
  244. setrealloctag(nv, getcallerpc(&v));
  245. if(v == nil)
  246. setmalloctag(nv, getcallerpc(&v));
  247. }
  248. return nv;
  249. }
  250. uint32_t
  251. msize(void *v)
  252. {
  253. return poolmsize(mainmem, (uint32_t*)v-Npadlong)-Npadlong*sizeof(uint32_t);
  254. }
  255. void
  256. setmalloctag(void *v, uint32_t pc)
  257. {
  258. uint32_t *u;
  259. USED(v, pc);
  260. if(Npadlong <= MallocOffset || v == nil)
  261. return;
  262. u = v;
  263. u[-Npadlong+MallocOffset] = pc;
  264. }
  265. void
  266. setrealloctag(void *v, uint32_t pc)
  267. {
  268. uint32_t *u;
  269. USED(v, pc);
  270. if(Npadlong <= ReallocOffset || v == nil)
  271. return;
  272. u = v;
  273. u[-Npadlong+ReallocOffset] = pc;
  274. }
  275. uint32_t
  276. getmalloctag(void *v)
  277. {
  278. USED(v);
  279. if(Npadlong <= MallocOffset)
  280. return ~0;
  281. return ((uint32_t*)v)[-Npadlong+MallocOffset];
  282. }
  283. uint32_t
  284. getrealloctag(void *v)
  285. {
  286. USED(v);
  287. if(Npadlong <= ReallocOffset)
  288. return ((uint32_t*)v)[-Npadlong+ReallocOffset];
  289. return ~0;
  290. }