You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

109 lines
2.4KB

  1. /*
  2. * This file is a part of SMalloc.
  3. * SMalloc is MIT licensed.
  4. * Copyright (c) 2017 Andrey Rys.
  5. */
  6. #include "smalloc_i.h"
  7. void *sm_malloc_pool(struct smalloc_pool *spool, size_t n)
  8. {
  9. struct smalloc_hdr *basehdr, *shdr, *dhdr;
  10. char *s;
  11. int found;
  12. size_t x;
  13. again: if (!smalloc_verify_pool(spool)) {
  14. errno = EINVAL;
  15. return NULL;
  16. }
  17. if (n == 0) n++; /* return a block successfully */
  18. if (n > SIZE_MAX
  19. || n > (spool->pool_size - HEADER_SZ)) goto oom;
  20. shdr = basehdr = spool->pool;
  21. while (CHAR_PTR(shdr)-CHAR_PTR(basehdr) < spool->pool_size) {
  22. /*
  23. * Already allocated block.
  24. * Skip it by jumping over it.
  25. */
  26. if (smalloc_is_alloc(spool, shdr)) {
  27. s = CHAR_PTR(HEADER_TO_USER(shdr));
  28. s += shdr->rsz + HEADER_SZ;
  29. shdr = HEADER_PTR(s);
  30. continue;
  31. }
  32. /*
  33. * Free blocks ahead!
  34. * Do a second search over them to find out if they're
  35. * really large enough to fit the new allocation.
  36. */
  37. else {
  38. dhdr = shdr; found = 0;
  39. while (CHAR_PTR(dhdr)-CHAR_PTR(basehdr) < spool->pool_size) {
  40. /* pre calculate free block size */
  41. x = CHAR_PTR(dhdr)-CHAR_PTR(shdr);
  42. /*
  43. * ugh, found next allocated block.
  44. * skip this candidate then.
  45. */
  46. if (smalloc_is_alloc(spool, dhdr))
  47. goto allocblock;
  48. /*
  49. * did not see allocated block yet,
  50. * but this free block is of enough size
  51. * - finally, use it.
  52. */
  53. if (n + HEADER_SZ <= x) {
  54. x -= HEADER_SZ;
  55. found = 1;
  56. goto outfound;
  57. }
  58. dhdr++;
  59. }
  60. outfound: if (found) {
  61. uintptr_t tag;
  62. /* allocate and return this block */
  63. shdr->rsz = x;
  64. shdr->usz = n;
  65. shdr->tag = tag = smalloc_mktag(shdr);
  66. if (spool->do_zero) memset(HEADER_TO_USER(shdr), 0, shdr->rsz);
  67. s = CHAR_PTR(HEADER_TO_USER(shdr));
  68. s += shdr->usz;
  69. for (x = 0;
  70. x < sizeof(struct smalloc_hdr);
  71. x += sizeof(uintptr_t)) {
  72. tag = smalloc_uinthash(tag);
  73. memcpy(s+x, &tag, sizeof(uintptr_t));
  74. }
  75. memset(s+x, 0xff, shdr->rsz - shdr->usz);
  76. return HEADER_TO_USER(shdr);
  77. }
  78. /* continue first search for next free block */
  79. allocblock: shdr = dhdr;
  80. continue;
  81. }
  82. shdr++;
  83. }
  84. oom: if (spool->oomfn) {
  85. x = spool->oomfn(spool, n);
  86. if (x > spool->pool_size) {
  87. spool->pool_size = x;
  88. if (sm_align_pool(spool)) goto again;
  89. }
  90. }
  91. errno = ENOMEM;
  92. return NULL;
  93. }
  94. void *sm_malloc(size_t n)
  95. {
  96. return sm_malloc_pool(&smalloc_curr_pool, n);
  97. }