malloc.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. /* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
  2. * This file is part of the Linux-8086 C library and is distributed
  3. * under the GNU Library General Public License.
  4. */
  5. /*
  6. * This is a combined alloca/malloc package. It uses a classic algorithm
  7. * and so may be seen to be quite slow compared to more modern routines
  8. * with 'nasty' distributions.
  9. */
  10. #include <malloc.h>
  11. #include <errno.h>
  12. #define MCHUNK 2048 /* Allocation unit in 'mem' elements */
  13. #define XLAZY_FREE /* If set frees can be infinitly defered */
  14. #define XMINALLOC 32 /* Smallest chunk to alloc in 'mem's */
  15. #define XVERBOSE /* Lots of noise, debuging ? */
  16. #undef malloc
  17. #define MAX_INT ((int)(((unsigned)-1)>>1))
  18. #ifdef VERBOSE
  19. #define noise __noise
  20. #else
  21. #define noise(y,x)
  22. #endif
  23. typedef union mem_cell
  24. {
  25. union mem_cell *next; /* A pointer to the next mem */
  26. unsigned int size; /* An int >= sizeof pointer */
  27. char *depth; /* For the alloca hack */
  28. }
  29. mem;
  30. #define m_size(p) ((p) [0].size) /* For malloc */
  31. #define m_next(p) ((p) [1].next) /* For malloc and alloca */
  32. #define m_deep(p) ((p) [0].depth) /* For alloca */
  33. extern void *__mini_malloc __P ((size_t));
  34. extern void *(*__alloca_alloc) __P ((size_t));
  35. extern mem *__freed_list;
  36. #ifdef L_free
  37. /* Start the alloca with just the dumb version of malloc */
  38. void *(*__alloca_alloc) __P ((size_t)) = __mini_malloc;
  39. mem *__freed_list = 0;
  40. #ifdef VERBOSE
  41. /* NB: Careful here, stdio may use malloc - so we can't */
  42. static
  43. phex(val)
  44. {
  45. static char hex[] = "0123456789ABCDEF";
  46. int i;
  47. for (i = sizeof(int)*8-4; i >= 0; i -= 4)
  48. write(2, hex + ((val >> i) & 0xF), 1);
  49. }
  50. noise(y, x)
  51. char *y;
  52. mem *x;
  53. {
  54. write(2, "Malloc ", 7);
  55. phex(x);
  56. write(2, " sz ", 4);
  57. if(x) phex(m_size(x)); else phex(0);
  58. write(2, " nxt ", 5);
  59. if(x) phex(m_next(x)); else phex(0);
  60. write(2, " is ", 4);
  61. write(2, y, strlen(y));
  62. write(2, "\n", 1);
  63. }
  64. #endif
  65. #endif
  66. #ifdef L_alloca
  67. /* This alloca is based on the same concept as the EMACS fallback alloca.
  68. * It should probably be considered Copyright the FSF under the GPL.
  69. */
  70. static mem *alloca_stack = 0;
  71. void *
  72. alloca(size)
  73. size_t size;
  74. {
  75. auto char probe; /* Probes stack depth: */
  76. register mem *hp;
  77. /*
  78. * Reclaim garbage, defined as all alloca'd storage that was allocated
  79. * from deeper in the stack than currently.
  80. */
  81. for (hp = alloca_stack; hp != 0;)
  82. if (m_deep(hp) < &probe)
  83. {
  84. register mem *np = m_next(hp);
  85. free((void *) hp); /* Collect garbage. */
  86. hp = np; /* -> next header. */
  87. }
  88. else
  89. break; /* Rest are not deeper. */
  90. alloca_stack = hp; /* -> last valid storage. */
  91. if (size == 0)
  92. return 0; /* No allocation required. */
  93. hp = (mem *) (*__alloca_alloc) (sizeof(mem)*2 + size);
  94. if (hp == 0)
  95. return hp;
  96. m_next(hp) = alloca_stack;
  97. m_deep(hp) = &probe;
  98. alloca_stack = hp;
  99. /* User storage begins just after header. */
  100. return (void *) (hp + 2);
  101. }
  102. #endif /* L_alloca */
  103. #ifdef L_free
  104. void
  105. free(ptr)
  106. void *ptr;
  107. {
  108. register mem *top;
  109. register mem *chk = (mem *) ptr;
  110. if (chk == 0)
  111. return; /* free(NULL) - be nice */
  112. chk--;
  113. try_this:;
  114. top = (mem *) sbrk(0);
  115. if (chk + m_size(chk) == top)
  116. {
  117. noise("FREE brk", chk);
  118. brk(top-m_size(chk));
  119. /*
  120. * Adding this code allow free to release blocks in any order; they
  121. * can still only be allocated from the top of the heap tho.
  122. */
  123. #ifdef __MINI_MALLOC__
  124. if (__alloca_alloc == __mini_malloc && __freed_list)
  125. {
  126. mem *prev, *curr;
  127. chk = __freed_list;
  128. __freed_list = m_next(__freed_list);
  129. goto try_this;
  130. }
  131. #endif
  132. }
  133. else
  134. { /* Nope, not sure where this goes, leave
  135. * it for malloc to deal with */
  136. #ifdef __MINI_MALLOC__
  137. if( __freed_list || chk > __freed_list )
  138. { m_next(chk) = __freed_list; __freed_list = chk; }
  139. else
  140. {
  141. register mem *prev;
  142. prev=__freed_list;
  143. for(top=__freed_list; top && top > chk; prev=top, top=m_next(top))
  144. ;
  145. m_next(chk) = top;
  146. m_next(prev) = chk;
  147. }
  148. #else
  149. m_next(chk) = __freed_list;
  150. __freed_list = chk;
  151. #endif
  152. noise("ADD LIST", chk);
  153. }
  154. }
  155. void *
  156. __mini_malloc(size)
  157. size_t size;
  158. {
  159. register mem *ptr;
  160. register unsigned int sz;
  161. /* First time round this _might_ be odd, But we won't do that! */
  162. sz = (unsigned int) sbrk(0);
  163. if (sz & (sizeof(mem) - 1))
  164. sbrk(4 - (sz & (sizeof(mem) - 1)));
  165. if (size <= 0)
  166. return 0;
  167. /* Minor oops here, sbrk has a signed argument */
  168. if( size > (((unsigned)-1)>>1)-sizeof(mem)*3 )
  169. {
  170. errno = ENOMEM;
  171. return 0;
  172. }
  173. size += sizeof(mem) * 2 - 1; /* Round up and leave space for size field */
  174. size /= sizeof(mem);
  175. ptr = (mem *) sbrk(size * sizeof(mem));
  176. if ((int) ptr == -1)
  177. return 0;
  178. m_size(ptr) = size;
  179. noise("CREATE", ptr);
  180. return ptr + 1;
  181. }
  182. #endif /* L_free */
  183. #ifdef L_malloc
  184. /*
  185. * The chunk_list pointer is either NULL or points to a chunk in a
  186. * circular list of all the free blocks in memory
  187. */
  188. #define Static static
  189. static mem *chunk_list = 0;
  190. Static void __insert_chunk();
  191. Static mem *__search_chunk();
  192. void *
  193. malloc(size)
  194. size_t size;
  195. {
  196. register mem *ptr = 0;
  197. register unsigned int sz;
  198. if (size == 0)
  199. return 0; /* ANSI STD */
  200. sz = size + sizeof(mem) * 2 - 1;
  201. sz /= sizeof(mem);
  202. #ifdef MINALLOC
  203. if (sz < MINALLOC)
  204. sz = MINALLOC;
  205. #endif
  206. #ifdef VERBOSE
  207. {
  208. static mem arr[2];
  209. m_size(arr) = sz;
  210. noise("WANTED", arr);
  211. }
  212. #endif
  213. __alloca_alloc = malloc; /* We'll be messing with the heap now TVM */
  214. #ifdef LAZY_FREE
  215. ptr = __search_chunk(sz);
  216. if (ptr == 0)
  217. {
  218. #endif
  219. /* First deal with the freed list */
  220. if (__freed_list)
  221. {
  222. while (__freed_list)
  223. {
  224. ptr = __freed_list;
  225. __freed_list = m_next(__freed_list);
  226. if (m_size(ptr) == sz) /* Oh! Well that's lucky ain't it
  227. * :-) */
  228. {
  229. noise("LUCKY MALLOC", ptr);
  230. return ptr + 1;
  231. }
  232. __insert_chunk(ptr);
  233. }
  234. ptr = m_next(chunk_list);
  235. if (ptr + m_size(ptr) == (void *) sbrk(0))
  236. {
  237. /* Time to free for real */
  238. m_next(chunk_list) = m_next(ptr);
  239. if (ptr == m_next(ptr))
  240. chunk_list = 0;
  241. free(ptr + 1);
  242. }
  243. #ifdef LAZY_FREE
  244. ptr = __search_chunk(sz);
  245. #endif
  246. }
  247. #ifndef LAZY_FREE
  248. ptr = __search_chunk(sz);
  249. #endif
  250. if (ptr == 0)
  251. {
  252. #ifdef MCHUNK
  253. unsigned int alloc;
  254. alloc = sizeof(mem) * (MCHUNK * ((sz + MCHUNK - 1) / MCHUNK) - 1);
  255. ptr = __mini_malloc(alloc);
  256. if (ptr)
  257. __insert_chunk(ptr - 1);
  258. else /* Oooo, near end of RAM */
  259. {
  260. unsigned int needed = alloc;
  261. for(alloc/=2; alloc>256 && needed; )
  262. {
  263. ptr = __mini_malloc(alloc);
  264. if (ptr)
  265. {
  266. if( alloc > needed ) needed = 0; else needed -= alloc;
  267. __insert_chunk(ptr - 1);
  268. }
  269. else alloc/=2;
  270. }
  271. }
  272. ptr = __search_chunk(sz);
  273. if (ptr == 0)
  274. #endif
  275. {
  276. #ifndef MCHUNK
  277. ptr = __mini_malloc(size);
  278. #endif
  279. #ifdef VERBOSE
  280. if( ptr == 0 )
  281. noise("MALLOC FAIL", 0);
  282. else
  283. noise("MALLOC NOW", ptr - 1);
  284. #endif
  285. return ptr;
  286. }
  287. }
  288. #ifdef LAZY_FREE
  289. }
  290. #endif
  291. #ifdef VERBOSE
  292. ptr[1].size = 0x55555555;
  293. #endif
  294. noise("MALLOC RET", ptr);
  295. return ptr + 1;
  296. }
  297. /*
  298. * This function takes a pointer to a block of memory and inserts it into
  299. * the chain of memory chunks
  300. */
  301. Static void
  302. __insert_chunk(mem_chunk)
  303. mem *mem_chunk;
  304. {
  305. register mem *p1, *p2;
  306. if (chunk_list == 0) /* Simple case first */
  307. {
  308. m_next(mem_chunk) = chunk_list = mem_chunk;
  309. noise("FIRST CHUNK", mem_chunk);
  310. return;
  311. }
  312. p1 = mem_chunk;
  313. p2 = chunk_list;
  314. do
  315. {
  316. if (p1 > p2)
  317. {
  318. if (m_next(p2) <= p2)
  319. { /* We're at the top of the chain, p1 is
  320. * higher */
  321. if (p2 + m_size(p2) == p1)
  322. { /* Good, stick 'em together */
  323. noise("INSERT CHUNK", mem_chunk);
  324. m_size(p2) += m_size(p1);
  325. noise("JOIN 1", p2);
  326. }
  327. else
  328. {
  329. m_next(p1) = m_next(p2);
  330. m_next(p2) = p1;
  331. noise("INSERT CHUNK", mem_chunk);
  332. noise("FROM", p2);
  333. }
  334. return;
  335. }
  336. if (m_next(p2) > p1)
  337. {
  338. /* In chain, p1 between p2 and next */
  339. m_next(p1) = m_next(p2);
  340. m_next(p2) = p1;
  341. noise("INSERT CHUNK", mem_chunk);
  342. noise("FROM", p2);
  343. /* Try to join above */
  344. if (p1 + m_size(p1) == m_next(p1))
  345. {
  346. m_size(p1) += m_size(m_next(p1));
  347. m_next(p1) = m_next(m_next(p1));
  348. noise("JOIN 2", p1);
  349. }
  350. /* Try to join below */
  351. if (p2 + m_size(p2) == p1)
  352. {
  353. m_size(p2) += m_size(p1);
  354. m_next(p2) = m_next(p1);
  355. noise("JOIN 3", p2);
  356. }
  357. chunk_list = p2; /* Make sure it's valid */
  358. return;
  359. }
  360. }
  361. else if (p1 < p2)
  362. {
  363. if (m_next(p2) <= p2 && p1 < m_next(p2))
  364. {
  365. /* At top of chain, next is bottom of chain, p1 is below next */
  366. m_next(p1) = m_next(p2);
  367. m_next(p2) = p1;
  368. noise("INSERT CHUNK", mem_chunk);
  369. noise("FROM", p2);
  370. chunk_list = p2;
  371. if (p1 + m_size(p1) == m_next(p1))
  372. {
  373. if (p2 == m_next(p1))
  374. chunk_list = p1;
  375. m_size(p1) += m_size(m_next(p1));
  376. m_next(p1) = m_next(m_next(p1));
  377. noise("JOIN 4", p1);
  378. }
  379. return;
  380. }
  381. }
  382. chunk_list = p2; /* Save for search */
  383. p2 = m_next(p2);
  384. }
  385. while (p2 != chunk_list);
  386. /* If we get here we have a problem, ignore it, maybe it'll go away */
  387. noise("DROPPED CHUNK", mem_chunk);
  388. }
  389. /*
  390. * This function will search for a chunk in memory of at least 'mem_size'
  391. * when found, if the chunk is too big it'll be split, and pointer to the
  392. * chunk returned. If none is found NULL is returned.
  393. */
  394. Static mem *
  395. __search_chunk(mem_size)
  396. unsigned int mem_size;
  397. {
  398. register mem *p1, *p2;
  399. if (chunk_list == 0) /* Simple case first */
  400. return 0;
  401. /* Search for a block >= the size we want */
  402. p1 = m_next(chunk_list);
  403. p2 = chunk_list;
  404. do
  405. {
  406. noise("CHECKED", p1);
  407. if (m_size(p1) >= mem_size)
  408. break;
  409. p2 = p1;
  410. p1 = m_next(p1);
  411. }
  412. while (p2 != chunk_list);
  413. /* None found, exit */
  414. if (m_size(p1) < mem_size)
  415. return 0;
  416. /* If it's exactly right remove it */
  417. if (m_size(p1) < mem_size + 2)
  418. {
  419. noise("FOUND RIGHT", p1);
  420. chunk_list = m_next(p2) = m_next(p1);
  421. if (chunk_list == p1)
  422. chunk_list = 0;
  423. return p1;
  424. }
  425. noise("SPLIT", p1);
  426. /* Otherwise split it */
  427. m_next(p2) = p1 + mem_size;
  428. chunk_list = p2;
  429. p2 = m_next(p2);
  430. m_size(p2) = m_size(p1) - mem_size;
  431. m_next(p2) = m_next(p1);
  432. m_size(p1) = mem_size;
  433. if (chunk_list == p1)
  434. chunk_list = p2;
  435. #ifdef VERBOSE
  436. p1[1].size = 0xAAAAAAAA;
  437. #endif
  438. noise("INSERT CHUNK", p2);
  439. noise("FOUND CHUNK", p1);
  440. noise("LIST IS", chunk_list);
  441. return p1;
  442. }
  443. #endif /* L_malloc */
  444. #ifdef L_calloc
  445. void *
  446. calloc(elm, sz)
  447. unsigned int elm, sz;
  448. {
  449. register unsigned int v;
  450. register void *ptr;
  451. ptr = malloc(v = elm * sz);
  452. if (ptr)
  453. memset(ptr, 0, v);
  454. return ptr;
  455. }
  456. #endif /* L_calloc */
  457. #ifdef L_realloc
  458. void *
  459. realloc(ptr, size)
  460. void *ptr;
  461. size_t size;
  462. {
  463. void *nptr;
  464. unsigned int osize;
  465. if (ptr == 0)
  466. return malloc(size);
  467. osize = (m_size(((mem *) ptr) - 1) - 1) * sizeof(mem);
  468. if (size <= osize)
  469. {
  470. return ptr;
  471. }
  472. nptr = malloc(size);
  473. if (nptr == 0)
  474. return 0;
  475. memcpy(nptr, ptr, osize);
  476. free(ptr);
  477. return nptr;
  478. }
  479. #endif /* L_realloc */