選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

389 行
10KB

  1. /* Copyright (c) 2002, 2004, 2010 Joerg Wunsch
  2. Copyright (c) 2010 Gerben van den Broeke
  3. All rights reserved.
  4. malloc, free, realloc from avr-libc 1.7.0
  5. with minor modifications, by Paul Stoffregen
  6. Redistribution and use in source and binary forms, with or without
  7. modification, are permitted provided that the following conditions are met:
  8. * Redistributions of source code must retain the above copyright
  9. notice, this list of conditions and the following disclaimer.
  10. * Redistributions in binary form must reproduce the above copyright
  11. notice, this list of conditions and the following disclaimer in
  12. the documentation and/or other materials provided with the
  13. distribution.
  14. * Neither the name of the copyright holders nor the names of
  15. contributors may be used to endorse or promote products derived
  16. from this software without specific prior written permission.
  17. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  21. LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  22. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  23. SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  24. INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  25. CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  27. POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #include <stdlib.h>
  30. #include <inttypes.h>
  31. #include <string.h>
  32. #include <avr/io.h>
  33. extern char __heap_start;
  34. extern char __heap_end;
  35. #define STACK_POINTER() ((char *)AVR_STACK_POINTER_REG)
  36. struct __freelist {
  37. size_t sz;
  38. struct __freelist *nx;
  39. };
  40. /*
  41. * Exported interface:
  42. *
  43. * When extending the data segment, the allocator will not try to go
  44. * beyond the current stack limit, decreased by __malloc_margin bytes.
  45. * Thus, all possible stack frames of interrupt routines that could
  46. * interrupt the current function, plus all further nested function
  47. * calls must not require more stack space, or they'll risk to collide
  48. * with the data segment.
  49. */
  50. size_t __malloc_margin = 128;
  51. char *__malloc_heap_start = &__heap_start;
  52. char *__malloc_heap_end = &__heap_end;
  53. char *__brkval = NULL; // first location not yet allocated
  54. struct __freelist *__flp; // freelist pointer (head of freelist)
  55. // this is useful for tracking the worst case memory allocation
  56. //char *__brkval_maximum = 0;
  57. void *
  58. malloc(size_t len)
  59. {
  60. struct __freelist *fp1, *fp2, *sfp1, *sfp2;
  61. char *cp;
  62. size_t s, avail;
  63. /*
  64. * Our minimum chunk size is the size of a pointer (plus the
  65. * size of the "sz" field, but we don't need to account for
  66. * this), otherwise we could not possibly fit a freelist entry
  67. * into the chunk later.
  68. */
  69. if (len < sizeof(struct __freelist) - sizeof(size_t))
  70. len = sizeof(struct __freelist) - sizeof(size_t);
  71. /*
  72. * First, walk the free list and try finding a chunk that
  73. * would match exactly. If we found one, we are done. While
  74. * walking, note down the smallest chunk we found that would
  75. * still fit the request -- we need it for step 2.
  76. *
  77. */
  78. for (s = 0, fp1 = __flp, fp2 = 0;
  79. fp1;
  80. fp2 = fp1, fp1 = fp1->nx) {
  81. if (fp1->sz < len)
  82. continue;
  83. if (fp1->sz == len) {
  84. /*
  85. * Found it. Disconnect the chunk from the
  86. * freelist, and return it.
  87. */
  88. if (fp2)
  89. fp2->nx = fp1->nx;
  90. else
  91. __flp = fp1->nx;
  92. return &(fp1->nx);
  93. }
  94. else {
  95. if (s == 0 || fp1->sz < s) {
  96. /* this is the smallest chunk found so far */
  97. s = fp1->sz;
  98. sfp1 = fp1;
  99. sfp2 = fp2;
  100. }
  101. }
  102. }
  103. /*
  104. * Step 2: If we found a chunk on the freelist that would fit
  105. * (but was too large), look it up again and use it, since it
  106. * is our closest match now. Since the freelist entry needs
  107. * to be split into two entries then, watch out that the
  108. * difference between the requested size and the size of the
  109. * chunk found is large enough for another freelist entry; if
  110. * not, just enlarge the request size to what we have found,
  111. * and use the entire chunk.
  112. */
  113. if (s) {
  114. if (s - len < sizeof(struct __freelist)) {
  115. /* Disconnect it from freelist and return it. */
  116. if (sfp2)
  117. sfp2->nx = sfp1->nx;
  118. else
  119. __flp = sfp1->nx;
  120. return &(sfp1->nx);
  121. }
  122. /*
  123. * Split them up. Note that we leave the first part
  124. * as the new (smaller) freelist entry, and return the
  125. * upper portion to the caller. This saves us the
  126. * work to fix up the freelist chain; we just need to
  127. * fixup the size of the current entry, and note down
  128. * the size of the new chunk before returning it to
  129. * the caller.
  130. */
  131. cp = (char *)sfp1;
  132. s -= len;
  133. cp += s;
  134. sfp2 = (struct __freelist *)cp;
  135. sfp2->sz = len;
  136. sfp1->sz = s - sizeof(size_t);
  137. return &(sfp2->nx);
  138. }
  139. /*
  140. * Step 3: If the request could not be satisfied from a
  141. * freelist entry, just prepare a new chunk. This means we
  142. * need to obtain more memory first. The largest address just
  143. * not allocated so far is remembered in the brkval variable.
  144. * Under Unix, the "break value" was the end of the data
  145. * segment as dynamically requested from the operating system.
  146. * Since we don't have an operating system, just make sure
  147. * that we don't collide with the stack.
  148. */
  149. if (__brkval == 0)
  150. __brkval = __malloc_heap_start;
  151. cp = __malloc_heap_end;
  152. if (cp == 0)
  153. cp = STACK_POINTER() - __malloc_margin;
  154. if (cp <= __brkval)
  155. /*
  156. * Memory exhausted.
  157. */
  158. return 0;
  159. avail = cp - __brkval;
  160. /*
  161. * Both tests below are needed to catch the case len >= 0xfffe.
  162. */
  163. if (avail >= len && avail >= len + sizeof(size_t)) {
  164. fp1 = (struct __freelist *)__brkval;
  165. __brkval += len + sizeof(size_t);
  166. //__brkval_maximum = __brkval;
  167. fp1->sz = len;
  168. return &(fp1->nx);
  169. }
  170. /*
  171. * Step 4: There's no help, just fail. :-/
  172. */
  173. return 0;
  174. }
  175. void
  176. free(void *p)
  177. {
  178. struct __freelist *fp1, *fp2, *fpnew;
  179. char *cp1, *cp2, *cpnew;
  180. /* ISO C says free(NULL) must be a no-op */
  181. if (p == 0)
  182. return;
  183. cpnew = p;
  184. cpnew -= sizeof(size_t);
  185. fpnew = (struct __freelist *)cpnew;
  186. fpnew->nx = 0;
  187. /*
  188. * Trivial case first: if there's no freelist yet, our entry
  189. * will be the only one on it. If this is the last entry, we
  190. * can reduce __brkval instead.
  191. */
  192. if (__flp == 0) {
  193. if ((char *)p + fpnew->sz == __brkval)
  194. __brkval = cpnew;
  195. else
  196. __flp = fpnew;
  197. return;
  198. }
  199. /*
  200. * Now, find the position where our new entry belongs onto the
  201. * freelist. Try to aggregate the chunk with adjacent chunks
  202. * if possible.
  203. */
  204. for (fp1 = __flp, fp2 = 0;
  205. fp1;
  206. fp2 = fp1, fp1 = fp1->nx) {
  207. if (fp1 < fpnew)
  208. continue;
  209. cp1 = (char *)fp1;
  210. fpnew->nx = fp1;
  211. if ((char *)&(fpnew->nx) + fpnew->sz == cp1) {
  212. /* upper chunk adjacent, assimilate it */
  213. fpnew->sz += fp1->sz + sizeof(size_t);
  214. fpnew->nx = fp1->nx;
  215. }
  216. if (fp2 == 0) {
  217. /* new head of freelist */
  218. __flp = fpnew;
  219. return;
  220. }
  221. break;
  222. }
  223. /*
  224. * Note that we get here either if we hit the "break" above,
  225. * or if we fell off the end of the loop. The latter means
  226. * we've got a new topmost chunk. Either way, try aggregating
  227. * with the lower chunk if possible.
  228. */
  229. fp2->nx = fpnew;
  230. cp2 = (char *)&(fp2->nx);
  231. if (cp2 + fp2->sz == cpnew) {
  232. /* lower junk adjacent, merge */
  233. fp2->sz += fpnew->sz + sizeof(size_t);
  234. fp2->nx = fpnew->nx;
  235. }
  236. /*
  237. * If there's a new topmost chunk, lower __brkval instead.
  238. */
  239. for (fp1 = __flp, fp2 = 0;
  240. fp1->nx != 0;
  241. fp2 = fp1, fp1 = fp1->nx)
  242. /* advance to entry just before end of list */;
  243. cp2 = (char *)&(fp1->nx);
  244. if (cp2 + fp1->sz == __brkval) {
  245. if (fp2 == NULL)
  246. /* Freelist is empty now. */
  247. __flp = NULL;
  248. else
  249. fp2->nx = NULL;
  250. __brkval = cp2 - sizeof(size_t);
  251. }
  252. }
  253. void *
  254. realloc(void *ptr, size_t len)
  255. {
  256. struct __freelist *fp1, *fp2, *fp3, *ofp3;
  257. char *cp, *cp1;
  258. void *memp;
  259. size_t s, incr;
  260. /* Trivial case, required by C standard. */
  261. if (ptr == 0)
  262. return malloc(len);
  263. cp1 = (char *)ptr;
  264. cp1 -= sizeof(size_t);
  265. fp1 = (struct __freelist *)cp1;
  266. cp = (char *)ptr + len; /* new next pointer */
  267. if (cp < cp1)
  268. /* Pointer wrapped across top of RAM, fail. */
  269. return 0;
  270. /*
  271. * See whether we are growing or shrinking. When shrinking,
  272. * we split off a chunk for the released portion, and call
  273. * free() on it. Therefore, we can only shrink if the new
  274. * size is at least sizeof(struct __freelist) smaller than the
  275. * previous size.
  276. */
  277. if (len <= fp1->sz) {
  278. /* The first test catches a possible unsigned int
  279. * rollover condition. */
  280. if (fp1->sz <= sizeof(struct __freelist) ||
  281. len > fp1->sz - sizeof(struct __freelist))
  282. return ptr;
  283. fp2 = (struct __freelist *)cp;
  284. fp2->sz = fp1->sz - len - sizeof(size_t);
  285. fp1->sz = len;
  286. free(&(fp2->nx));
  287. return ptr;
  288. }
  289. /*
  290. * If we get here, we are growing. First, see whether there
  291. * is space in the free list on top of our current chunk.
  292. */
  293. incr = len - fp1->sz;
  294. cp = (char *)ptr + fp1->sz;
  295. fp2 = (struct __freelist *)cp;
  296. for (s = 0, ofp3 = 0, fp3 = __flp;
  297. fp3;
  298. ofp3 = fp3, fp3 = fp3->nx) {
  299. if (fp3 == fp2 && fp3->sz + sizeof(size_t) >= incr) {
  300. /* found something that fits */
  301. if (fp3->sz + sizeof(size_t) - incr > sizeof(struct __freelist)) {
  302. /* split off a new freelist entry */
  303. cp = (char *)ptr + len;
  304. fp2 = (struct __freelist *)cp;
  305. fp2->nx = fp3->nx;
  306. fp2->sz = fp3->sz - incr;
  307. fp1->sz = len;
  308. } else {
  309. /* it just fits, so use it entirely */
  310. fp1->sz += fp3->sz + sizeof(size_t);
  311. fp2 = fp3->nx;
  312. }
  313. if (ofp3)
  314. ofp3->nx = fp2;
  315. else
  316. __flp = fp2;
  317. return ptr;
  318. }
  319. /*
  320. * Find the largest chunk on the freelist while
  321. * walking it.
  322. */
  323. if (fp3->sz > s)
  324. s = fp3->sz;
  325. }
  326. /*
  327. * If we are the topmost chunk in memory, and there was no
  328. * large enough chunk on the freelist that could be re-used
  329. * (by a call to malloc() below), quickly extend the
  330. * allocation area if possible, without need to copy the old
  331. * data.
  332. */
  333. if (__brkval == (char *)ptr + fp1->sz && len > s) {
  334. cp = (char *)ptr + len;
  335. cp1 = STACK_POINTER() - __malloc_margin;
  336. if (cp < cp1) {
  337. __brkval = cp;
  338. //__brkval_maximum = cp;
  339. fp1->sz = len;
  340. return ptr;
  341. }
  342. /* If that failed, we are out of luck. */
  343. return 0;
  344. }
  345. /*
  346. * Call malloc() for a new chunk, then copy over the data, and
  347. * release the old region.
  348. */
  349. if ((memp = malloc(len)) == 0)
  350. return 0;
  351. memcpy(memp, ptr, fp1->sz);
  352. free(ptr);
  353. return memp;
  354. }