malloc.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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. long *x;
  40. n += 8; /* 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. long *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. free(void *v)
  196. {
  197. if(v != nil)
  198. poolfree(mainmem, (ulong*)v-Npadlong);
  199. }
  200. void*
  201. realloc(void *v, ulong size)
  202. {
  203. void *nv;
  204. if(size == 0){
  205. free(v);
  206. return nil;
  207. }
  208. if(v)
  209. v = (ulong*)v-Npadlong;
  210. size += Npadlong*sizeof(ulong);
  211. if(nv = poolrealloc(mainmem, v, size)){
  212. nv = (ulong*)nv+Npadlong;
  213. setrealloctag(nv, getcallerpc(&v));
  214. if(v == nil)
  215. setmalloctag(nv, getcallerpc(&v));
  216. }
  217. return nv;
  218. }
  219. ulong
  220. msize(void *v)
  221. {
  222. return poolmsize(mainmem, (ulong*)v-Npadlong)-Npadlong*sizeof(ulong);
  223. }
  224. void*
  225. calloc(ulong n, ulong szelem)
  226. {
  227. void *v;
  228. if(v = mallocz(n*szelem, 1))
  229. setmalloctag(v, getcallerpc(&n));
  230. return v;
  231. }
  232. void
  233. setmalloctag(void *v, ulong pc)
  234. {
  235. ulong *u;
  236. USED(v, pc);
  237. if(Npadlong <= MallocOffset || v == nil)
  238. return;
  239. u = v;
  240. u[-Npadlong+MallocOffset] = pc;
  241. }
  242. void
  243. setrealloctag(void *v, ulong pc)
  244. {
  245. ulong *u;
  246. USED(v, pc);
  247. if(Npadlong <= ReallocOffset || v == nil)
  248. return;
  249. u = v;
  250. u[-Npadlong+ReallocOffset] = pc;
  251. }
  252. ulong
  253. getmalloctag(void *v)
  254. {
  255. USED(v);
  256. if(Npadlong <= MallocOffset)
  257. return ~0;
  258. return ((ulong*)v)[-Npadlong+MallocOffset];
  259. }
  260. ulong
  261. getrealloctag(void *v)
  262. {
  263. USED(v);
  264. if(Npadlong <= ReallocOffset)
  265. return ((ulong*)v)[-Npadlong+ReallocOffset];
  266. return ~0;
  267. }
  268. void*
  269. malloctopoolblock(void *v)
  270. {
  271. if(v == nil)
  272. return nil;
  273. return &((ulong*)v)[-Npadlong];
  274. }