alloc.c 5.6 KB

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