alloc.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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->msg[0] = 0;
  84. }
  85. static void
  86. punlock(Pool *p)
  87. {
  88. Private *pv;
  89. char msg[sizeof pv->msg];
  90. pv = p->private;
  91. if(pv->msg[0] == 0){
  92. iunlock(&pv->lk);
  93. return;
  94. }
  95. memmove(msg, pv->msg, sizeof msg);
  96. iunlock(&pv->lk);
  97. iprint("%.*s", sizeof pv->msg, msg);
  98. }
  99. void
  100. poolsummary(Pool *p)
  101. {
  102. print("%s max %lud cur %lud free %lud alloc %lud\n", p->name,
  103. p->maxsize, p->cursize, p->curfree, p->curalloc);
  104. }
  105. void
  106. mallocsummary(void)
  107. {
  108. poolsummary(mainmem);
  109. poolsummary(imagmem);
  110. }
  111. /* everything from here down should be the same in libc, libdebugmalloc, and the kernel */
  112. /* - except the code for malloc(), which alternately doesn't clear or does. */
  113. /* - except the code for smalloc(), which lives only in the kernel. */
  114. /*
  115. * Npadlong is the number of 32-bit longs to leave at the beginning of
  116. * each allocated buffer for our own bookkeeping. We return to the callers
  117. * a pointer that points immediately after our bookkeeping area. Incoming pointers
  118. * must be decremented by that much, and outgoing pointers incremented.
  119. * The malloc tag is stored at MallocOffset from the beginning of the block,
  120. * and the realloc tag at ReallocOffset. The offsets are from the true beginning
  121. * of the block, not the beginning the caller sees.
  122. *
  123. * The extra if(Npadlong != 0) in various places is a hint for the compiler to
  124. * compile out function calls that would otherwise be no-ops.
  125. */
  126. /* non tracing
  127. *
  128. enum {
  129. Npadlong = 0,
  130. MallocOffset = 0,
  131. ReallocOffset = 0,
  132. };
  133. *
  134. */
  135. /* tracing */
  136. enum {
  137. Npadlong = 2,
  138. MallocOffset = 0,
  139. ReallocOffset = 1
  140. };
  141. void*
  142. smalloc(ulong size)
  143. {
  144. void *v;
  145. for(;;) {
  146. v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
  147. if(v != nil)
  148. break;
  149. tsleep(&up->sleep, return0, 0, 100);
  150. }
  151. if(Npadlong){
  152. v = (ulong*)v+Npadlong;
  153. setmalloctag(v, getcallerpc(&size));
  154. }
  155. memset(v, 0, size);
  156. return v;
  157. }
  158. void*
  159. malloc(ulong size)
  160. {
  161. void *v;
  162. v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
  163. if(v == nil)
  164. return nil;
  165. if(Npadlong){
  166. v = (ulong*)v+Npadlong;
  167. setmalloctag(v, getcallerpc(&size));
  168. setrealloctag(v, 0);
  169. }
  170. memset(v, 0, size);
  171. return v;
  172. }
  173. void*
  174. mallocz(ulong size, int clr)
  175. {
  176. void *v;
  177. v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
  178. if(Npadlong && v != nil){
  179. v = (ulong*)v+Npadlong;
  180. setmalloctag(v, getcallerpc(&size));
  181. setrealloctag(v, 0);
  182. }
  183. if(clr && v != nil)
  184. memset(v, 0, size);
  185. return v;
  186. }
  187. void*
  188. mallocalign(ulong size, ulong align, long offset, ulong span)
  189. {
  190. void *v;
  191. v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
  192. if(Npadlong && v != nil){
  193. v = (ulong*)v+Npadlong;
  194. setmalloctag(v, getcallerpc(&size));
  195. setrealloctag(v, 0);
  196. }
  197. return v;
  198. }
  199. void
  200. free(void *v)
  201. {
  202. if(v != nil)
  203. poolfree(mainmem, (ulong*)v-Npadlong);
  204. }
  205. void*
  206. realloc(void *v, ulong size)
  207. {
  208. void *nv;
  209. if(v != nil)
  210. v = (ulong*)v-Npadlong;
  211. if(Npadlong !=0 && size != 0)
  212. size += Npadlong*sizeof(ulong);
  213. if(nv = poolrealloc(mainmem, v, size)){
  214. nv = (ulong*)nv+Npadlong;
  215. setrealloctag(nv, getcallerpc(&v));
  216. if(v == nil)
  217. setmalloctag(nv, getcallerpc(&v));
  218. }
  219. return nv;
  220. }
  221. ulong
  222. msize(void *v)
  223. {
  224. return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
  225. }
  226. void*
  227. calloc(ulong n, ulong szelem)
  228. {
  229. void *v;
  230. if(v = mallocz(n*szelem, 1))
  231. setmalloctag(v, getcallerpc(&n));
  232. return v;
  233. }
  234. void
  235. setmalloctag(void *v, ulong pc)
  236. {
  237. ulong *u;
  238. USED(v, pc);
  239. if(Npadlong <= MallocOffset || v == nil)
  240. return;
  241. u = v;
  242. u[-Npadlong+MallocOffset] = pc;
  243. }
  244. void
  245. setrealloctag(void *v, ulong pc)
  246. {
  247. ulong *u;
  248. USED(v, pc);
  249. if(Npadlong <= ReallocOffset || v == nil)
  250. return;
  251. u = v;
  252. u[-Npadlong+ReallocOffset] = pc;
  253. }
  254. ulong
  255. getmalloctag(void *v)
  256. {
  257. USED(v);
  258. if(Npadlong <= MallocOffset)
  259. return ~0;
  260. return ((ulong*)v)[-Npadlong+MallocOffset];
  261. }
  262. ulong
  263. getrealloctag(void *v)
  264. {
  265. USED(v);
  266. if(Npadlong <= ReallocOffset)
  267. return ((ulong*)v)[-Npadlong+ReallocOffset];
  268. return ~0;
  269. }