malloc.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <pool.h>
  4. static void* sbrkalloc(ulong);
  5. static int sbrkmerge(void*, void*);
  6. static void plock(Pool*);
  7. static void punlock(Pool*);
  8. static void pprint(Pool*, char*, ...);
  9. static void ppanic(Pool*, char*, ...);
  10. typedef struct Private Private;
  11. struct Private {
  12. Lock lk;
  13. int printfd; /* gets debugging output if set */
  14. };
  15. Private sbrkmempriv;
  16. static Pool sbrkmem = {
  17. .name= "sbrkmem",
  18. .maxsize= 2UL*1024*1024*1024,
  19. .minarena= 4*1024,
  20. .quantum= 32,
  21. .alloc= sbrkalloc,
  22. .merge= sbrkmerge,
  23. .flags= 0,
  24. .lock= plock,
  25. .unlock= punlock,
  26. .print= pprint,
  27. .panic= ppanic,
  28. .private= &sbrkmempriv,
  29. };
  30. Pool *mainmem = &sbrkmem;
  31. Pool *imagmem = &sbrkmem;
  32. /*
  33. * we do minimal bookkeeping so we can tell pool
  34. * whether two blocks are adjacent and thus mergeable.
  35. */
  36. static void*
  37. sbrkalloc(ulong n)
  38. {
  39. ulong *x;
  40. n += 2*sizeof(ulong); /* two longs for us */
  41. x = sbrk(n);
  42. if((int)x == -1)
  43. return nil;
  44. x[0] = (n+7)&~7; /* sbrk rounds size up to mult. of 8 */
  45. x[1] = 0xDeadBeef;
  46. return x+2;
  47. }
  48. static int
  49. sbrkmerge(void *x, void *y)
  50. {
  51. ulong *lx, *ly;
  52. lx = x;
  53. if(lx[-1] != 0xDeadBeef)
  54. abort();
  55. if((uchar*)lx+lx[-2] == (uchar*)y) {
  56. ly = y;
  57. lx[-2] += ly[-2];
  58. return 1;
  59. }
  60. return 0;
  61. }
  62. static void
  63. plock(Pool *p)
  64. {
  65. Private *pv;
  66. pv = p->private;
  67. lock(&pv->lk);
  68. }
  69. static void
  70. punlock(Pool *p)
  71. {
  72. Private *pv;
  73. pv = p->private;
  74. unlock(&pv->lk);
  75. }
  76. static int
  77. checkenv(void)
  78. {
  79. int n, fd;
  80. char buf[20];
  81. fd = open("/env/MALLOCFD", OREAD);
  82. if(fd < 0)
  83. return -1;
  84. if((n = read(fd, buf, sizeof buf)) < 0) {
  85. close(fd);
  86. return -1;
  87. }
  88. if(n >= sizeof buf)
  89. n = sizeof(buf)-1;
  90. buf[n] = 0;
  91. n = atoi(buf);
  92. if(n == 0)
  93. n = -1;
  94. return n;
  95. }
  96. static void
  97. pprint(Pool *p, char *fmt, ...)
  98. {
  99. va_list v;
  100. Private *pv;
  101. pv = p->private;
  102. if(pv->printfd == 0)
  103. pv->printfd = checkenv();
  104. if(pv->printfd <= 0)
  105. pv->printfd = 2;
  106. va_start(v, fmt);
  107. vfprint(pv->printfd, fmt, v);
  108. va_end(v);
  109. }
  110. static char panicbuf[256];
  111. static void
  112. ppanic(Pool *p, char *fmt, ...)
  113. {
  114. va_list v;
  115. int n;
  116. char *msg;
  117. Private *pv;
  118. pv = p->private;
  119. assert(canlock(&pv->lk)==0);
  120. if(pv->printfd == 0)
  121. pv->printfd = checkenv();
  122. if(pv->printfd <= 0)
  123. pv->printfd = 2;
  124. msg = panicbuf;
  125. va_start(v, fmt);
  126. n = vseprint(msg, msg+sizeof panicbuf, fmt, v) - msg;
  127. write(2, "panic: ", 7);
  128. write(2, msg, n);
  129. write(2, "\n", 1);
  130. if(pv->printfd != 2){
  131. write(pv->printfd, "panic: ", 7);
  132. write(pv->printfd, msg, n);
  133. write(pv->printfd, "\n", 1);
  134. }
  135. va_end(v);
  136. unlock(&pv->lk);
  137. abort();
  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. /*
  142. * Npadlong is the number of 32-bit longs to leave at the beginning of
  143. * each allocated buffer for our own bookkeeping. We return to the callers
  144. * a pointer that points immediately after our bookkeeping area. Incoming pointers
  145. * must be decremented by that much, and outgoing pointers incremented.
  146. * The malloc tag is stored at MallocOffset from the beginning of the block,
  147. * and the realloc tag at ReallocOffset. The offsets are from the true beginning
  148. * of the block, not the beginning the caller sees.
  149. *
  150. * The extra if(Npadlong != 0) in various places is a hint for the compiler to
  151. * compile out function calls that would otherwise be no-ops.
  152. */
  153. /* non tracing
  154. *
  155. enum {
  156. Npadlong = 0,
  157. MallocOffset = 0,
  158. ReallocOffset = 0,
  159. };
  160. *
  161. */
  162. /* tracing */
  163. enum {
  164. Npadlong = 2,
  165. MallocOffset = 0,
  166. ReallocOffset = 1
  167. };
  168. void*
  169. malloc(ulong size)
  170. {
  171. void *v;
  172. v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
  173. if(Npadlong && v != nil) {
  174. v = (ulong*)v+Npadlong;
  175. setmalloctag(v, getcallerpc(&size));
  176. setrealloctag(v, 0);
  177. }
  178. return v;
  179. }
  180. void*
  181. mallocz(ulong size, int clr)
  182. {
  183. void *v;
  184. v = poolalloc(mainmem, size+Npadlong*sizeof(ulong));
  185. if(Npadlong && v != nil){
  186. v = (ulong*)v+Npadlong;
  187. setmalloctag(v, getcallerpc(&size));
  188. setrealloctag(v, 0);
  189. }
  190. if(clr && v != nil)
  191. memset(v, 0, size);
  192. return v;
  193. }
  194. void*
  195. mallocalign(ulong size, ulong align, long offset, ulong span)
  196. {
  197. void *v;
  198. v = poolallocalign(mainmem, size+Npadlong*sizeof(ulong), align, offset-Npadlong*sizeof(ulong), span);
  199. if(Npadlong && v != nil){
  200. v = (ulong*)v+Npadlong;
  201. setmalloctag(v, getcallerpc(&size));
  202. setrealloctag(v, 0);
  203. }
  204. return v;
  205. }
  206. void
  207. free(void *v)
  208. {
  209. if(v != nil)
  210. poolfree(mainmem, (ulong*)v-Npadlong);
  211. }
  212. void*
  213. realloc(void *v, ulong size)
  214. {
  215. void *nv;
  216. if(size == 0){
  217. free(v);
  218. return nil;
  219. }
  220. if(v)
  221. v = (ulong*)v-Npadlong;
  222. size += Npadlong*sizeof(ulong);
  223. if(nv = poolrealloc(mainmem, v, size)){
  224. nv = (ulong*)nv+Npadlong;
  225. setrealloctag(nv, getcallerpc(&v));
  226. if(v == nil)
  227. setmalloctag(nv, getcallerpc(&v));
  228. }
  229. return nv;
  230. }
  231. ulong
  232. msize(void *v)
  233. {
  234. return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
  235. }
  236. void*
  237. calloc(ulong n, ulong szelem)
  238. {
  239. void *v;
  240. if(v = mallocz(n*szelem, 1))
  241. setmalloctag(v, getcallerpc(&n));
  242. return v;
  243. }
  244. void
  245. setmalloctag(void *v, ulong pc)
  246. {
  247. ulong *u;
  248. USED(v, pc);
  249. if(Npadlong <= MallocOffset || v == nil)
  250. return;
  251. u = v;
  252. u[-Npadlong+MallocOffset] = pc;
  253. }
  254. void
  255. setrealloctag(void *v, ulong pc)
  256. {
  257. ulong *u;
  258. USED(v, pc);
  259. if(Npadlong <= ReallocOffset || v == nil)
  260. return;
  261. u = v;
  262. u[-Npadlong+ReallocOffset] = pc;
  263. }
  264. ulong
  265. getmalloctag(void *v)
  266. {
  267. USED(v);
  268. if(Npadlong <= MallocOffset)
  269. return ~0;
  270. return ((ulong*)v)[-Npadlong+MallocOffset];
  271. }
  272. ulong
  273. getrealloctag(void *v)
  274. {
  275. USED(v);
  276. if(Npadlong <= ReallocOffset)
  277. return ((ulong*)v)[-Npadlong+ReallocOffset];
  278. return ~0;
  279. }
  280. void*
  281. malloctopoolblock(void *v)
  282. {
  283. if(v == nil)
  284. return nil;
  285. return &((ulong*)v)[-Npadlong];
  286. }