/** * @brief Allocates a block of memory from the heap by using the first-fit * algorithm. * @details The allocated block is guaranteed to be properly aligned for a * pointer data type (@p stkalign_t). * * @param[in] heapp pointer to a heap descriptor or @p NULL in order to * access the default heap. * @param[in] size the size of the block to be allocated. Note that the * allocated block may be a bit bigger than the requested * size for alignment and fragmentation reasons. * @return A pointer to the allocated block. * @retval NULL if the block cannot be allocated. * * @api */ void *chHeapAlloc(memory_heap_t *heapp, size_t size) { union heap_header *qp, *hp, *fp; if (heapp == NULL) { heapp = &default_heap; } size = MEM_ALIGN_NEXT(size); qp = &heapp->h_free; H_LOCK(heapp); while (qp->h.u.next != NULL) { hp = qp->h.u.next; if (hp->h.size >= size) { if (hp->h.size < (size + sizeof(union heap_header))) { /* Gets the whole block even if it is slightly bigger than the requested size because the fragment would be too small to be useful.*/ qp->h.u.next = hp->h.u.next; } else { /* Block bigger enough, must split it.*/ /*lint -save -e9087 [11.3] Safe cast.*/ fp = (void *)((uint8_t *)(hp) + sizeof(union heap_header) + size); /*lint -restore*/ fp->h.u.next = hp->h.u.next; fp->h.size = (hp->h.size - sizeof(union heap_header)) - size; qp->h.u.next = fp; hp->h.size = size; } hp->h.u.heap = heapp; H_UNLOCK(heapp); /*lint -save -e9087 [11.3] Safe cast.*/ return (void *)(hp + 1); /*lint -restore*/ } qp = hp; } H_UNLOCK(heapp); /* More memory is required, tries to get it from the associated provider else fails.*/ if (heapp->h_provider != NULL) { hp = heapp->h_provider(size + sizeof(union heap_header)); if (hp != NULL) { hp->h.u.heap = heapp; hp->h.size = size; hp++; /*lint -save -e9087 [11.3] Safe cast.*/ return (void *)hp; /*lint -restore*/ } } return NULL; }
void chHeapFree(void *p) { chDbgCheck(p != NULL, "chHeapFree"); H_LOCK(); free(p); H_UNLOCK(); }
void *chHeapAlloc(MemoryHeap *heapp, size_t size) { void *p; chDbgCheck(heapp == NULL, "chHeapAlloc"); H_LOCK(); p = malloc(size); H_UNLOCK(); return p; }
/** * @brief Reports the heap status. * @note This function is meant to be used in the test suite, it should * not be really useful for the application code. * @note This function is not implemented when the @p CH_USE_MALLOC_HEAP * configuration option is used (it always returns zero). * * @param[in] heapp pointer to a heap descriptor or @p NULL in order to * access the default heap. * @param[in] sizep pointer to a variable that will receive the total * fragmented free space * @return The number of fragments in the heap. * * @api */ size_t chHeapStatus(MemoryHeap *heapp, size_t *sizep) { union heap_header *qp; size_t n, sz; if (heapp == NULL) heapp = &default_heap; H_LOCK(heapp); sz = 0; for (n = 0, qp = &heapp->h_free; qp->h.u.next; n++, qp = qp->h.u.next) sz += qp->h.u.next->h.size; if (sizep) *sizep = sz; H_UNLOCK(heapp); return n; }
/** * @brief Frees a previously allocated memory block. * * @param[in] p pointer to the memory block to be freed * * @api */ void chHeapFree(void *p) { union heap_header *qp, *hp; MemoryHeap *heapp; chDbgCheck(p != NULL, "chHeapFree"); hp = (union heap_header *)p - 1; heapp = hp->h.u.heap; qp = &heapp->h_free; H_LOCK(heapp); while (TRUE) { chDbgAssert((hp < qp) || (hp >= LIMIT(qp)), "chHeapFree(), #1", "within free block"); if (((qp == &heapp->h_free) || (hp > qp)) && ((qp->h.u.next == NULL) || (hp < qp->h.u.next))) { /* Insertion after qp.*/ hp->h.u.next = qp->h.u.next; qp->h.u.next = hp; /* Verifies if the newly inserted block should be merged.*/ if (LIMIT(hp) == hp->h.u.next) { /* Merge with the next block.*/ hp->h.size += hp->h.u.next->h.size + sizeof(union heap_header); hp->h.u.next = hp->h.u.next->h.u.next; } if ((LIMIT(qp) == hp)) { /* Merge with the previous block.*/ qp->h.size += hp->h.size + sizeof(union heap_header); qp->h.u.next = hp->h.u.next; } break; } qp = qp->h.u.next; } H_UNLOCK(heapp); return; }
/** * @brief Frees a previously allocated memory block. * * @param[in] p pointer to the memory block to be freed * * @api */ void chHeapFree(void *p) { union heap_header *qp, *hp; memory_heap_t *heapp; chDbgCheck(p != NULL); /*lint -save -e9087 [11.3] Safe cast.*/ hp = (union heap_header *)p - 1; /*lint -restore*/ heapp = hp->h.u.heap; qp = &heapp->h_free; H_LOCK(heapp); while (true) { chDbgAssert((hp < qp) || (hp >= LIMIT(qp)), "within free block"); if (((qp == &heapp->h_free) || (hp > qp)) && ((qp->h.u.next == NULL) || (hp < qp->h.u.next))) { /* Insertion after qp.*/ hp->h.u.next = qp->h.u.next; qp->h.u.next = hp; /* Verifies if the newly inserted block should be merged.*/ if (LIMIT(hp) == hp->h.u.next) { /* Merge with the next block.*/ hp->h.size += hp->h.u.next->h.size + sizeof(union heap_header); hp->h.u.next = hp->h.u.next->h.u.next; } if ((LIMIT(qp) == hp)) { /* Merge with the previous block.*/ qp->h.size += hp->h.size + sizeof(union heap_header); qp->h.u.next = hp->h.u.next; } break; } qp = qp->h.u.next; } H_UNLOCK(heapp); return; }
/** * @brief Reports the heap status. * @note This function is meant to be used in the test suite, it should * not be really useful for the application code. * * @param[in] heapp pointer to a heap descriptor or @p NULL in order to * access the default heap. * @param[in] sizep pointer to a variable that will receive the total * fragmented free space * @return The number of fragments in the heap. * * @api */ size_t chHeapStatus(memory_heap_t *heapp, size_t *sizep) { union heap_header *qp; size_t n, sz; if (heapp == NULL) { heapp = &default_heap; } H_LOCK(heapp); sz = 0; n = 0; qp = &heapp->h_free; while (qp->h.u.next != NULL) { sz += qp->h.u.next->h.size; n++; qp = qp->h.u.next; } if (sizep != NULL) { *sizep = sz; } H_UNLOCK(heapp); return n; }