malloc.c 5.7 KB

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