memheap.c 32.6 KB
Newer Older
1
/*
mysterywolf's avatar
mysterywolf 已提交
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
B
Bernard Xiong 已提交
3
 *
4 5 6 7 8
 * SPDX-License-Identifier: Apache-2.0
 */

/*
 * File      : memheap.c
9 10 11 12
 *
 * Change Logs:
 * Date           Author       Notes
 * 2012-04-10     Bernard      first implementation
13
 * 2012-10-16     Bernard      add the mutex lock for heap object.
14 15
 * 2012-12-29     Bernard      memheap can be used as system heap.
 *                             change mutex lock to semaphore lock.
B
Bernard Xiong 已提交
16
 * 2013-04-10     Bernard      add rt_memheap_realloc function.
B
Bernard Xiong 已提交
17
 * 2013-05-24     Bernard      fix the rt_memheap_realloc issue.
18
 * 2013-07-11     Grissiom     fix the memory block splitting issue.
19
 * 2013-07-15     Grissiom     optimize rt_memheap_realloc
20
 * 2021-06-03     Flybreak     Fix the crash problem after opening Oz optimization on ac6.
21
 */
22

23
#include <rthw.h>
24 25 26 27 28
#include <rtthread.h>

#ifdef RT_USING_MEMHEAP

/* dynamic pool magic and mask */
29 30 31 32
#define RT_MEMHEAP_MAGIC        0x1ea01ea0
#define RT_MEMHEAP_MASK         0xfffffffe
#define RT_MEMHEAP_USED         0x01
#define RT_MEMHEAP_FREED        0x00
33

34 35
#define RT_MEMHEAP_IS_USED(i)   ((i)->magic & RT_MEMHEAP_USED)
#define RT_MEMHEAP_MINIALLOC    12
36

37
#define RT_MEMHEAP_SIZE         RT_ALIGN(sizeof(struct rt_memheap_item), RT_ALIGN_SIZE)
38
#define MEMITEM_SIZE(item)      ((rt_ubase_t)item->next - (rt_ubase_t)item - RT_MEMHEAP_SIZE)
39 40 41 42 43 44
#define MEMITEM(ptr)            (struct rt_memheap_item*)((rt_uint8_t*)ptr - RT_MEMHEAP_SIZE)

#ifdef RT_USING_MEMTRACE
rt_inline void rt_memheap_setname(struct rt_memheap_item *item, const char *name)
{
    int index;
G
guozhanxin 已提交
45
    rt_uint8_t *ptr;
46

G
guozhanxin 已提交
47 48
    ptr = (rt_uint8_t *) & (item->next_free);
    for (index = 0; index < sizeof(void *); index ++)
49 50 51 52 53
    {
        if (name[index] == '\0') break;
        ptr[index] = name[index];
    }
    if (name[index] == '\0') ptr[index] = '\0';
G
guozhanxin 已提交
54
    else
55
    {
G
guozhanxin 已提交
56 57
        ptr = (rt_uint8_t *) & (item->prev_free);
        for (index = 0; index < sizeof(void *) && (index + sizeof(void *)) < RT_NAME_MAX; index ++)
58
        {
G
guozhanxin 已提交
59 60
            if (name[sizeof(void *) + index] == '\0') break;
            ptr[index] = name[sizeof(void *) + index];
61 62
        }

G
guozhanxin 已提交
63
        if (name[sizeof(void *) + index] == '\0') ptr[index] = '\0';
64 65 66
    }
}

G
guozhanxin 已提交
67
void rt_mem_set_tag(void *ptr, const char *name)
68
{
G
guozhanxin 已提交
69
    struct rt_memheap_item *item;
70 71 72 73 74 75 76

    if (ptr && name)
    {
        item = MEMITEM(ptr);
        rt_memheap_setname(item, name);
    }
}
77
#endif /* RT_USING_MEMTRACE */
78 79 80 81 82 83 84 85 86

/*
 * The initialized memory pool will be:
 * +-----------------------------------+--------------------------+
 * | whole freed memory block          | Used Memory Block Tailer |
 * +-----------------------------------+--------------------------+
 *
 * block_list --> whole freed memory block
 *
87 88
 * The length of Used Memory Block Tailer is 0,
 * which is prevents block merging across list
89
 */
90 91 92
rt_err_t rt_memheap_init(struct rt_memheap *memheap,
                         const char        *name,
                         void              *start_addr,
B
Bernard Xiong 已提交
93
                         rt_size_t         size)
94
{
95
    struct rt_memheap_item *item;
96

97
    RT_ASSERT(memheap != RT_NULL);
98

99 100
    /* initialize pool object */
    rt_object_init(&(memheap->parent), RT_Object_Class_MemHeap, name);
101

102 103
    memheap->start_addr     = start_addr;
    memheap->pool_size      = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
104
    memheap->available_size = memheap->pool_size - (2 * RT_MEMHEAP_SIZE);
105
    memheap->max_used_size  = memheap->pool_size - memheap->available_size;
106

107 108
    /* initialize the free list header */
    item            = &(memheap->free_header);
109
    item->magic     = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
110 111 112 113 114 115 116 117 118 119 120
    item->pool_ptr  = memheap;
    item->next      = RT_NULL;
    item->prev      = RT_NULL;
    item->next_free = item;
    item->prev_free = item;

    /* set the free list to free list header */
    memheap->free_list = item;

    /* initialize the first big memory block */
    item            = (struct rt_memheap_item *)start_addr;
121
    item->magic     = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
122 123 124 125 126 127
    item->pool_ptr  = memheap;
    item->next      = RT_NULL;
    item->prev      = RT_NULL;
    item->next_free = item;
    item->prev_free = item;

C
cliff-cmc 已提交
128 129
#ifdef RT_USING_MEMTRACE
    rt_memset(item->owner_thread_name, ' ', sizeof(item->owner_thread_name));
130
#endif /* RT_USING_MEMTRACE */
C
cliff-cmc 已提交
131

132
    item->next = (struct rt_memheap_item *)
133
                 ((rt_uint8_t *)item + memheap->available_size + RT_MEMHEAP_SIZE);
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
    item->prev = item->next;

    /* block list header */
    memheap->block_list = item;

    /* place the big memory block to free list */
    item->next_free = memheap->free_list->next_free;
    item->prev_free = memheap->free_list;
    memheap->free_list->next_free->prev_free = item;
    memheap->free_list->next_free            = item;

    /* move to the end of memory pool to build a small tailer block,
     * which prevents block merging
     */
    item = item->next;
    /* it's a used memory block */
150
    item->magic     = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED);
151 152 153 154 155 156
    item->pool_ptr  = memheap;
    item->next      = (struct rt_memheap_item *)start_addr;
    item->prev      = (struct rt_memheap_item *)start_addr;
    /* not in free list */
    item->next_free = item->prev_free = RT_NULL;

157
    /* initialize semaphore lock */
158
    rt_sem_init(&(memheap->lock), name, 1, RT_IPC_FLAG_PRIO);
159 160

    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
161
                 ("memory heap: start addr 0x%08x, size %d, free list header 0x%08x\n",
162
                  start_addr, size, &(memheap->free_header)));
163

164
    return RT_EOK;
165
}
166
RTM_EXPORT(rt_memheap_init);
167

168
rt_err_t rt_memheap_detach(struct rt_memheap *heap)
169
{
170
    RT_ASSERT(heap);
171 172
    RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
    RT_ASSERT(rt_object_is_systemobject(&heap->parent));
mysterywolf's avatar
mysterywolf 已提交
173

Moral-Hao's avatar
Moral-Hao 已提交
174
    rt_sem_detach(&heap->lock);
175
    rt_object_detach(&(heap->parent));
176

177 178
    /* Return a successful completion. */
    return RT_EOK;
179
}
180
RTM_EXPORT(rt_memheap_detach);
181

B
Bernard Xiong 已提交
182
void *rt_memheap_alloc(struct rt_memheap *heap, rt_size_t size)
183
{
184 185 186 187 188
    rt_err_t result;
    rt_uint32_t free_size;
    struct rt_memheap_item *header_ptr;

    RT_ASSERT(heap != RT_NULL);
189
    RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);
190 191 192 193 194 195

    /* align allocated size */
    size = RT_ALIGN(size, RT_ALIGN_SIZE);
    if (size < RT_MEMHEAP_MINIALLOC)
        size = RT_MEMHEAP_MINIALLOC;

196 197
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate %d on heap:%8.*s",
                                    size, RT_NAME_MAX, heap->parent.name));
198 199 200 201 202 203 204

    if (size < heap->available_size)
    {
        /* search on free list */
        free_size = 0;

        /* lock memheap */
205
        result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
206 207 208 209 210 211 212 213 214 215 216 217
        if (result != RT_EOK)
        {
            rt_set_errno(result);

            return RT_NULL;
        }

        /* get the first free memory block */
        header_ptr = heap->free_list->next_free;
        while (header_ptr != heap->free_list && free_size < size)
        {
            /* get current freed memory block size */
B
Bernard Xiong 已提交
218
            free_size = MEMITEM_SIZE(header_ptr);
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
            if (free_size < size)
            {
                /* move to next free memory block */
                header_ptr = header_ptr->next_free;
            }
        }

        /* determine if the memory is available. */
        if (free_size >= size)
        {
            /* a block that satisfies the request has been found. */

            /* determine if the block needs to be split. */
            if (free_size >= (size + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC))
            {
                struct rt_memheap_item *new_ptr;

                /* split the block. */
                new_ptr = (struct rt_memheap_item *)
                          (((rt_uint8_t *)header_ptr) + size + RT_MEMHEAP_SIZE);

                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
241
                             ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
242 243 244 245
                              header_ptr,
                              header_ptr->next,
                              header_ptr->prev,
                              new_ptr));
246

247
                /* mark the new block as a memory block and freed. */
248
                new_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
249 250 251 252

                /* put the pool pointer into the new block. */
                new_ptr->pool_ptr = heap;

C
cliff-cmc 已提交
253 254
#ifdef RT_USING_MEMTRACE
                rt_memset(new_ptr->owner_thread_name, ' ', sizeof(new_ptr->owner_thread_name));
255
#endif /* RT_USING_MEMTRACE */
C
cliff-cmc 已提交
256

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
                /* break down the block list */
                new_ptr->prev          = header_ptr;
                new_ptr->next          = header_ptr->next;
                header_ptr->next->prev = new_ptr;
                header_ptr->next       = new_ptr;

                /* remove header ptr from free list */
                header_ptr->next_free->prev_free = header_ptr->prev_free;
                header_ptr->prev_free->next_free = header_ptr->next_free;
                header_ptr->next_free = RT_NULL;
                header_ptr->prev_free = RT_NULL;

                /* insert new_ptr to free list */
                new_ptr->next_free = heap->free_list->next_free;
                new_ptr->prev_free = heap->free_list;
                heap->free_list->next_free->prev_free = new_ptr;
                heap->free_list->next_free            = new_ptr;
274
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x\n",
275 276
                                                new_ptr->next_free,
                                                new_ptr->prev_free));
277

278 279 280 281
                /* decrement the available byte count.  */
                heap->available_size = heap->available_size -
                                       size -
                                       RT_MEMHEAP_SIZE;
282 283
                if (heap->pool_size - heap->available_size > heap->max_used_size)
                    heap->max_used_size = heap->pool_size - heap->available_size;
284 285 286 287 288
            }
            else
            {
                /* decrement the entire free size from the available bytes count. */
                heap->available_size = heap->available_size - free_size;
289 290
                if (heap->pool_size - heap->available_size > heap->max_used_size)
                    heap->max_used_size = heap->pool_size - heap->available_size;
291 292 293

                /* remove header_ptr from free list */
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
294
                             ("one block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x\n",
295 296 297
                              header_ptr,
                              header_ptr->next_free,
                              header_ptr->prev_free));
298

299 300 301 302 303
                header_ptr->next_free->prev_free = header_ptr->prev_free;
                header_ptr->prev_free->next_free = header_ptr->next_free;
                header_ptr->next_free = RT_NULL;
                header_ptr->prev_free = RT_NULL;
            }
304

305
            /* Mark the allocated block as not available. */
306
            header_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED);
307

C
cliff-cmc 已提交
308 309 310 311 312
#ifdef RT_USING_MEMTRACE
            if (rt_thread_self())
                rt_memcpy(header_ptr->owner_thread_name, rt_thread_self()->name, sizeof(header_ptr->owner_thread_name));
            else
                rt_memcpy(header_ptr->owner_thread_name, "NONE", sizeof(header_ptr->owner_thread_name));
313
#endif /* RT_USING_MEMTRACE */
C
cliff-cmc 已提交
314

315 316 317
            /* release lock */
            rt_sem_release(&(heap->lock));

318 319
            /* Return a memory address to the caller.  */
            RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
320
                         ("alloc mem: memory[0x%08x], heap[0x%08x], size: %d\n",
321 322
                          (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE),
                          header_ptr,
323
                          size));
324

325
            return (void *)((rt_uint8_t *)header_ptr + RT_MEMHEAP_SIZE);
326
        }
327

328
        /* release lock */
329
        rt_sem_release(&(heap->lock));
330
    }
331

332
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("allocate memory: failed\n"));
333 334 335 336

    /* Return the completion status.  */
    return RT_NULL;
}
337
RTM_EXPORT(rt_memheap_alloc);
338

Y
yiyue.fang 已提交
339
void *rt_memheap_realloc(struct rt_memheap *heap, void *ptr, rt_size_t newsize)
B
Bernard Xiong 已提交
340
{
B
Bernard Xiong 已提交
341
    rt_err_t result;
Y
yiyue.fang 已提交
342 343 344 345
    rt_size_t oldsize;
    struct rt_memheap_item *header_ptr;
    struct rt_memheap_item *new_ptr;

346 347 348
    RT_ASSERT(heap);
    RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);

Y
yiyue.fang 已提交
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
    if (newsize == 0)
    {
        rt_memheap_free(ptr);

        return RT_NULL;
    }
    /* align allocated size */
    newsize = RT_ALIGN(newsize, RT_ALIGN_SIZE);
    if (newsize < RT_MEMHEAP_MINIALLOC)
        newsize = RT_MEMHEAP_MINIALLOC;

    if (ptr == RT_NULL)
    {
        return rt_memheap_alloc(heap, newsize);
    }

    /* get memory block header and get the size of memory block */
    header_ptr = (struct rt_memheap_item *)
                 ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
    oldsize = MEMITEM_SIZE(header_ptr);
369
    /* re-allocate memory */
B
Bernard Xiong 已提交
370 371
    if (newsize > oldsize)
    {
372
        void *new_ptr;
373 374
        /* Fix the crash problem after opening Oz optimization on ac6  */
        volatile struct rt_memheap_item *next_ptr;
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425

        /* lock memheap */
        result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
        if (result != RT_EOK)
        {
            rt_set_errno(result);
            return RT_NULL;
        }

        next_ptr = header_ptr->next;

        /* header_ptr should not be the tail */
        RT_ASSERT(next_ptr > header_ptr);

        /* check whether the following free space is enough to expand */
        if (!RT_MEMHEAP_IS_USED(next_ptr))
        {
            rt_int32_t nextsize;

            nextsize = MEMITEM_SIZE(next_ptr);
            RT_ASSERT(next_ptr > 0);

            /* Here is the ASCII art of the situation that we can make use of
             * the next free node without alloc/memcpy, |*| is the control
             * block:
             *
             *      oldsize           free node
             * |*|-----------|*|----------------------|*|
             *         newsize          >= minialloc
             * |*|----------------|*|-----------------|*|
             */
            if (nextsize + oldsize > newsize + RT_MEMHEAP_MINIALLOC)
            {
                /* decrement the entire free size from the available bytes count. */
                heap->available_size = heap->available_size - (newsize - oldsize);
                if (heap->pool_size - heap->available_size > heap->max_used_size)
                    heap->max_used_size = heap->pool_size - heap->available_size;

                /* remove next_ptr from free list */
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
                             ("remove block: block[0x%08x], next_free 0x%08x, prev_free 0x%08x",
                              next_ptr,
                              next_ptr->next_free,
                              next_ptr->prev_free));

                next_ptr->next_free->prev_free = next_ptr->prev_free;
                next_ptr->prev_free->next_free = next_ptr->next_free;
                next_ptr->next->prev = next_ptr->prev;
                next_ptr->prev->next = next_ptr->next;

                /* build a new one on the right place */
426
                next_ptr = (struct rt_memheap_item *)((char *)ptr + newsize);
427 428 429 430 431 432 433 434

                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
                             ("new free block: block[0x%08x] nextm[0x%08x] prevm[0x%08x]",
                              next_ptr,
                              next_ptr->next,
                              next_ptr->prev));

                /* mark the new block as a memory block and freed. */
435
                next_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
436 437 438 439

                /* put the pool pointer into the new block. */
                next_ptr->pool_ptr = heap;

C
cliff-cmc 已提交
440 441
#ifdef RT_USING_MEMTRACE
                rt_memset(next_ptr->owner_thread_name, ' ', sizeof(next_ptr->owner_thread_name));
442
#endif /* RT_USING_MEMTRACE */
C
cliff-cmc 已提交
443

444 445
                next_ptr->prev          = header_ptr;
                next_ptr->next          = header_ptr->next;
446 447
                header_ptr->next->prev = (struct rt_memheap_item *)next_ptr;
                header_ptr->next       = (struct rt_memheap_item *)next_ptr;
448 449 450 451

                /* insert next_ptr to free list */
                next_ptr->next_free = heap->free_list->next_free;
                next_ptr->prev_free = heap->free_list;
452 453
                heap->free_list->next_free->prev_free = (struct rt_memheap_item *)next_ptr;
                heap->free_list->next_free            = (struct rt_memheap_item *)next_ptr;
454 455 456 457 458 459 460 461 462 463 464 465 466 467
                RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new ptr: next_free 0x%08x, prev_free 0x%08x",
                                                next_ptr->next_free,
                                                next_ptr->prev_free));

                /* release lock */
                rt_sem_release(&(heap->lock));

                return ptr;
            }
        }

        /* release lock */
        rt_sem_release(&(heap->lock));

B
Bernard Xiong 已提交
468
        /* re-allocate a memory block */
469
        new_ptr = (void *)rt_memheap_alloc(heap, newsize);
B
Bernard Xiong 已提交
470 471 472 473 474
        if (new_ptr != RT_NULL)
        {
            rt_memcpy(new_ptr, ptr, oldsize < newsize ? oldsize : newsize);
            rt_memheap_free(ptr);
        }
B
Bernard Xiong 已提交
475

B
Bernard Xiong 已提交
476 477 478
        return new_ptr;
    }

479 480 481 482
    /* don't split when there is less than one node space left */
    if (newsize + RT_MEMHEAP_SIZE + RT_MEMHEAP_MINIALLOC >= oldsize)
        return ptr;

Y
yiyue.fang 已提交
483 484 485 486 487 488 489 490 491 492 493 494 495 496
    /* lock memheap */
    result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
    if (result != RT_EOK)
    {
        rt_set_errno(result);

        return RT_NULL;
    }

    /* split the block. */
    new_ptr = (struct rt_memheap_item *)
              (((rt_uint8_t *)header_ptr) + newsize + RT_MEMHEAP_SIZE);

    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
497
                 ("split: block[0x%08x] nextm[0x%08x] prevm[0x%08x] to new[0x%08x]\n",
Y
yiyue.fang 已提交
498 499 500 501 502 503
                  header_ptr,
                  header_ptr->next,
                  header_ptr->prev,
                  new_ptr));

    /* mark the new block as a memory block and freed. */
504
    new_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
Y
yiyue.fang 已提交
505 506 507
    /* put the pool pointer into the new block. */
    new_ptr->pool_ptr = heap;

C
cliff-cmc 已提交
508 509
#ifdef RT_USING_MEMTRACE
    rt_memset(new_ptr->owner_thread_name, ' ', sizeof(new_ptr->owner_thread_name));
510
#endif /* RT_USING_MEMTRACE */
C
cliff-cmc 已提交
511

Y
yiyue.fang 已提交
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
    /* break down the block list */
    new_ptr->prev          = header_ptr;
    new_ptr->next          = header_ptr->next;
    header_ptr->next->prev = new_ptr;
    header_ptr->next       = new_ptr;

    /* determine if the block can be merged with the next neighbor. */
    if (!RT_MEMHEAP_IS_USED(new_ptr->next))
    {
        struct rt_memheap_item *free_ptr;

        /* merge block with next neighbor. */
        free_ptr = new_ptr->next;
        heap->available_size = heap->available_size - MEMITEM_SIZE(free_ptr);

        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
528
                     ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
Y
yiyue.fang 已提交
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
                      header_ptr, header_ptr->next_free, header_ptr->prev_free));

        free_ptr->next->prev = new_ptr;
        new_ptr->next   = free_ptr->next;

        /* remove free ptr from free list */
        free_ptr->next_free->prev_free = free_ptr->prev_free;
        free_ptr->prev_free->next_free = free_ptr->next_free;
    }

    /* insert the split block to free list */
    new_ptr->next_free = heap->free_list->next_free;
    new_ptr->prev_free = heap->free_list;
    heap->free_list->next_free->prev_free = new_ptr;
    heap->free_list->next_free            = new_ptr;
544
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("new free ptr: next_free 0x%08x, prev_free 0x%08x\n",
Y
yiyue.fang 已提交
545 546 547 548 549
                                    new_ptr->next_free,
                                    new_ptr->prev_free));

    /* increment the available byte count.  */
    heap->available_size = heap->available_size + MEMITEM_SIZE(new_ptr);
B
Bernard Xiong 已提交
550 551 552 553

    /* release lock */
    rt_sem_release(&(heap->lock));

Y
yiyue.fang 已提交
554 555
    /* return the old memory block */
    return ptr;
B
Bernard Xiong 已提交
556 557 558
}
RTM_EXPORT(rt_memheap_realloc);

559
void rt_memheap_free(void *ptr)
560
{
561 562 563 564 565
    rt_err_t result;
    struct rt_memheap *heap;
    struct rt_memheap_item *header_ptr, *new_ptr;
    rt_uint32_t insert_header;

566 567
    /* NULL check */
    if (ptr == RT_NULL) return;
568

569 570 571
    /* set initial status as OK */
    insert_header = 1;
    new_ptr       = RT_NULL;
Y
yiyue.fang 已提交
572 573
    header_ptr    = (struct rt_memheap_item *)
                    ((rt_uint8_t *)ptr - RT_MEMHEAP_SIZE);
574

575
    RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("free memory: memory[0x%08x], block[0x%08x]\n",
576
                                    ptr, header_ptr));
577

578
    /* check magic */
579 580
    if (header_ptr->magic != (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED))
    {
581 582
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("bad magic:0x%08x @ memheap\n",
                                        header_ptr->magic));
583 584
    }
    RT_ASSERT(header_ptr->magic == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED));
585 586
    /* check whether this block of memory has been over-written. */
    RT_ASSERT((header_ptr->next->magic & RT_MEMHEAP_MASK) == RT_MEMHEAP_MAGIC);
587 588 589

    /* get pool ptr */
    heap = header_ptr->pool_ptr;
590

591 592 593
    RT_ASSERT(heap);
    RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);

594
    /* lock memheap */
595
    result = rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
596 597 598
    if (result != RT_EOK)
    {
        rt_set_errno(result);
Y
yiyue.fang 已提交
599

600 601
        return ;
    }
602

603
    /* Mark the memory as available. */
604
    header_ptr->magic = (RT_MEMHEAP_MAGIC | RT_MEMHEAP_FREED);
605
    /* Adjust the available number of bytes. */
606
    heap->available_size += MEMITEM_SIZE(header_ptr);
607

608 609 610
    /* Determine if the block can be merged with the previous neighbor. */
    if (!RT_MEMHEAP_IS_USED(header_ptr->prev))
    {
611
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("merge: left node 0x%08x\n",
612
                                        header_ptr->prev));
613

614
        /* adjust the available number of bytes. */
615
        heap->available_size += RT_MEMHEAP_SIZE;
616

617 618 619
        /* yes, merge block with previous neighbor. */
        (header_ptr->prev)->next = header_ptr->next;
        (header_ptr->next)->prev = header_ptr->prev;
620

621 622 623 624 625
        /* move header pointer to previous. */
        header_ptr = header_ptr->prev;
        /* don't insert header to free list */
        insert_header = 0;
    }
626

627 628 629 630
    /* determine if the block can be merged with the next neighbor. */
    if (!RT_MEMHEAP_IS_USED(header_ptr->next))
    {
        /* adjust the available number of bytes. */
631
        heap->available_size += RT_MEMHEAP_SIZE;
632

633 634
        /* merge block with next neighbor. */
        new_ptr = header_ptr->next;
635

636
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
637
                     ("merge: right node 0x%08x, next_free 0x%08x, prev_free 0x%08x\n",
638
                      new_ptr, new_ptr->next_free, new_ptr->prev_free));
639

640 641
        new_ptr->next->prev = header_ptr;
        header_ptr->next    = new_ptr->next;
642

643 644 645 646
        /* remove new ptr from free list */
        new_ptr->next_free->prev_free = new_ptr->prev_free;
        new_ptr->prev_free->next_free = new_ptr->next_free;
    }
647

648 649 650 651 652 653 654
    if (insert_header)
    {
        /* no left merge, insert to free list */
        header_ptr->next_free = heap->free_list->next_free;
        header_ptr->prev_free = heap->free_list;
        heap->free_list->next_free->prev_free = header_ptr;
        heap->free_list->next_free            = header_ptr;
655

656
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP,
657
                     ("insert to free list: next_free 0x%08x, prev_free 0x%08x\n",
658
                      header_ptr->next_free, header_ptr->prev_free));
659
    }
660

C
cliff-cmc 已提交
661 662
#ifdef RT_USING_MEMTRACE
    rt_memset(header_ptr->owner_thread_name, ' ', sizeof(header_ptr->owner_thread_name));
663
#endif /* RT_USING_MEMTRACE */
C
cliff-cmc 已提交
664

665
    /* release lock */
666
    rt_sem_release(&(heap->lock));
667
}
668
RTM_EXPORT(rt_memheap_free);
669

670
#ifdef RT_USING_FINSH
G
guozhanxin 已提交
671
static void _memheap_dump_tag(struct rt_memheap_item *item)
672
{
G
guozhanxin 已提交
673 674
    rt_uint8_t name[2 * sizeof(void *)];
    rt_uint8_t *ptr;
675

G
guozhanxin 已提交
676 677 678 679
    ptr = (rt_uint8_t *) & (item->next_free);
    rt_memcpy(name, ptr, sizeof(void *));
    ptr = (rt_uint8_t *) & (item->prev_free);
    rt_memcpy(&name[sizeof(void *)], ptr, sizeof(void *));
680

G
guozhanxin 已提交
681
    rt_kprintf("%.*s", 2 * sizeof(void *), name);
682 683 684 685 686 687 688 689 690
}

int rt_memheap_dump(struct rt_memheap *heap)
{
    struct rt_memheap_item *item, *end;

    if (heap == RT_NULL) return 0;
    RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);

G
guozhanxin 已提交
691 692
    rt_kprintf("\n[%.*s] [0x%08x - 0x%08x]->\n", RT_NAME_MAX, heap->parent.name,
               (rt_ubase_t)heap->start_addr, (rt_ubase_t)heap->start_addr + heap->pool_size);
693 694 695 696 697 698
    rt_kprintf("------------------------------\n");

    /* lock memheap */
    rt_sem_take(&(heap->lock), RT_WAITING_FOREVER);
    item = heap->block_list;

G
guozhanxin 已提交
699
    end = (struct rt_memheap_item *)((rt_uint8_t *)heap->start_addr + heap->pool_size - RT_MEMHEAP_SIZE);
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724

    /* for each memory block */
    while ((rt_ubase_t)item < ((rt_ubase_t)end))
    {
        if (RT_MEMHEAP_IS_USED(item) && ((item->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC))
            rt_kprintf("0x%08x", item + 1);

        if (item->magic == (RT_MEMHEAP_MAGIC | RT_MEMHEAP_USED))
        {
            rt_kprintf("0x%08x: %-8d ",     item + 1, MEMITEM_SIZE(item));
            _memheap_dump_tag(item);
            rt_kprintf("\n");
        }
        else
        {
            rt_kprintf("0x%08x: %-8d <F>\n", item + 1, MEMITEM_SIZE(item));
        }

        item = item->next;
    }
    rt_sem_release(&(heap->lock));

    return 0;
}

725
int memheaptrace(void)
726 727 728 729 730 731 732 733 734
{
    int count = rt_object_get_length(RT_Object_Class_MemHeap);
    struct rt_memheap **heaps;

    if (count > 0)
    {
        int index;
        extern int list_memheap(void);

G
guozhanxin 已提交
735
        heaps = (struct rt_memheap **)rt_malloc(sizeof(struct rt_memheap *) * count);
736 737 738 739 740
        if (heaps == RT_NULL) return 0;

        list_memheap();

        rt_kprintf("memheap header size: %d\n", RT_MEMHEAP_SIZE);
G
guozhanxin 已提交
741
        count = rt_object_get_pointers(RT_Object_Class_MemHeap, (rt_object_t *)heaps, count);
742 743 744 745 746 747 748 749 750 751
        for (index = 0; index < count; index++)
        {
            rt_memheap_dump(heaps[index]);
        }

        rt_free(heaps);
    }

    return 0;
}
752
MSH_CMD_EXPORT(memheaptrace, dump memory trace information);
753
#endif /* RT_USING_FINSH */
754

755 756 757 758 759
#ifdef RT_USING_MEMHEAP_AS_HEAP
static struct rt_memheap _heap;

void rt_system_heap_init(void *begin_addr, void *end_addr)
{
760 761
    RT_ASSERT((rt_uint32_t)end_addr > (rt_uint32_t)begin_addr);

762 763 764 765 766
    /* initialize a default heap in the system */
    rt_memheap_init(&_heap,
                    "heap",
                    begin_addr,
                    (rt_uint32_t)end_addr - (rt_uint32_t)begin_addr);
767 768 769 770
}

void *rt_malloc(rt_size_t size)
{
771
    void *ptr;
B
Bernard Xiong 已提交
772

773 774 775 776 777 778 779 780 781 782
    /* try to allocate in system heap */
    ptr = rt_memheap_alloc(&_heap, size);
    if (ptr == RT_NULL)
    {
        struct rt_object *object;
        struct rt_list_node *node;
        struct rt_memheap *heap;
        struct rt_object_information *information;

        /* try to allocate on other memory heap */
783 784
        information = rt_object_get_information(RT_Object_Class_MemHeap);
        RT_ASSERT(information != RT_NULL);
785 786 787 788 789 790 791
        for (node  = information->object_list.next;
             node != &(information->object_list);
             node  = node->next)
        {
            object = rt_list_entry(node, struct rt_object, list);
            heap   = (struct rt_memheap *)object;

792 793 794
            RT_ASSERT(heap);
            RT_ASSERT(rt_object_get_type(&heap->parent) == RT_Object_Class_MemHeap);

795 796 797 798 799 800 801 802 803 804
            /* not allocate in the default system heap */
            if (heap == &_heap)
                continue;

            ptr = rt_memheap_alloc(heap, size);
            if (ptr != RT_NULL)
                break;
        }
    }

805 806 807 808

#ifdef RT_USING_MEMTRACE
    if (ptr == RT_NULL)
    {
809
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("malloc[%d] => NULL", size));
810 811 812 813 814 815 816 817 818
    }
    else
    {
        struct rt_memheap_item *item = MEMITEM(ptr);
        if (rt_thread_self())
            rt_memheap_setname(item, rt_thread_self()->name);
        else
            rt_memheap_setname(item, "<null>");

819
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("malloc => 0x%08x : %d", ptr, size));
820
    }
821
#endif /* RT_USING_MEMTRACE */
822

823
    return ptr;
824 825 826 827 828
}
RTM_EXPORT(rt_malloc);

void rt_free(void *rmem)
{
829
    rt_memheap_free(rmem);
830 831 832 833 834
}
RTM_EXPORT(rt_free);

void *rt_realloc(void *rmem, rt_size_t newsize)
{
Y
yiyue.fang 已提交
835
    void *new_ptr;
836 837
    struct rt_memheap_item *header_ptr;

Y
yiyue.fang 已提交
838 839
    if (rmem == RT_NULL)
        return rt_malloc(newsize);
840

841 842 843 844 845 846
    if (newsize == 0)
    {
        rt_free(rmem);
        return RT_NULL;
    }

847
    /* get old memory item */
Y
yiyue.fang 已提交
848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865
    header_ptr = (struct rt_memheap_item *)
                 ((rt_uint8_t *)rmem - RT_MEMHEAP_SIZE);

    new_ptr = rt_memheap_realloc(header_ptr->pool_ptr, rmem, newsize);
    if (new_ptr == RT_NULL && newsize != 0)
    {
        /* allocate memory block from other memheap */
        new_ptr = rt_malloc(newsize);
        if (new_ptr != RT_NULL && rmem != RT_NULL)
        {
            rt_size_t oldsize;

            /* get the size of old memory block */
            oldsize = MEMITEM_SIZE(header_ptr);
            if (newsize > oldsize)
                rt_memcpy(new_ptr, rmem, oldsize);
            else
                rt_memcpy(new_ptr, rmem, newsize);
866 867

            rt_free(rmem);
Y
yiyue.fang 已提交
868 869 870
        }
    }

871 872 873
#ifdef RT_USING_MEMTRACE
    if (new_ptr == RT_NULL)
    {
874
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("realloc[%d] => NULL", newsize));
875 876 877 878 879 880 881 882 883
    }
    else
    {
        struct rt_memheap_item *item = MEMITEM(new_ptr);
        if (rt_thread_self())
            rt_memheap_setname(item, rt_thread_self()->name);
        else
            rt_memheap_setname(item, "<null>");

884 885
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("realloc => 0x%08x : %d",
                                        new_ptr, newsize));
886
    }
887
#endif /* RT_USING_MEMTRACE */
888

Y
yiyue.fang 已提交
889
    return new_ptr;
890 891 892 893 894
}
RTM_EXPORT(rt_realloc);

void *rt_calloc(rt_size_t count, rt_size_t size)
{
895 896 897 898 899 900 901 902 903 904 905
    void *ptr;
    rt_size_t total_size;

    total_size = count * size;
    ptr = rt_malloc(total_size);
    if (ptr != RT_NULL)
    {
        /* clean memory */
        rt_memset(ptr, 0, total_size);
    }

906 907 908
#ifdef RT_USING_MEMTRACE
    if (ptr == RT_NULL)
    {
909 910
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("calloc[%d x %d] => NULL",
                                        count, size));
911 912 913
    }
    else
    {
914 915
        RT_DEBUG_LOG(RT_DEBUG_MEMHEAP, ("calloc => 0x%08x : %d",
                                        ptr, count * size));
916
    }
917
#endif /* RT_USING_MEMTRACE */
918

919
    return ptr;
920 921 922
}
RTM_EXPORT(rt_calloc);

U
unknown 已提交
923 924 925 926 927 928 929 930 931 932 933 934 935
void rt_memory_info(rt_uint32_t *total,
                    rt_uint32_t *used,
                    rt_uint32_t *max_used)
{
    if (total != RT_NULL)
        *total = _heap.pool_size;

    if (used  != RT_NULL)
        *used = _heap.pool_size - _heap.available_size;

    if (max_used != RT_NULL)
        *max_used = _heap.max_used_size;
}
936

937
#endif /* RT_USING_MEMHEAP_AS_HEAP */
938

C
cliff-cmc 已提交
939 940 941 942 943 944 945 946 947 948
#ifdef RT_USING_MEMTRACE

void dump_used_memheap(struct rt_memheap *mh)
{
    struct rt_memheap_item *header_ptr;
    rt_uint32_t block_size;


    rt_kprintf("\nmemory heap address:\n");
    rt_kprintf("heap_ptr: 0x%08x\n", mh->start_addr);
mysterywolf's avatar
mysterywolf 已提交
949
    rt_kprintf("free    : 0x%08x\n", mh->available_size);
C
cliff-cmc 已提交
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972
    rt_kprintf("max_used: 0x%08x\n", mh->max_used_size);
    rt_kprintf("size    : 0x%08x\n", mh->pool_size);

    rt_kprintf("\n--memory used information --\n");

    header_ptr = mh->block_list;
    while (header_ptr->next != mh->block_list)
    {
        if ((header_ptr->magic & RT_MEMHEAP_MASK) != RT_MEMHEAP_MAGIC)
        {
            rt_kprintf("[0x%08x - incorrect magic: 0x%08x\n", header_ptr, header_ptr->magic);
            break;
        }

        /* get current memory block size */
        block_size = MEMITEM_SIZE(header_ptr);
        if (block_size < 0)
            break;

        if (RT_MEMHEAP_IS_USED(header_ptr))
        {
            /* dump information */
            rt_kprintf("[0x%08x - %d - %c%c%c%c] used\n", header_ptr, block_size,
G
guozhanxin 已提交
973 974
                       header_ptr->owner_thread_name[0], header_ptr->owner_thread_name[1],
                       header_ptr->owner_thread_name[2], header_ptr->owner_thread_name[3]);
C
cliff-cmc 已提交
975 976 977 978 979
        }
        else
        {
            /* dump information */
            rt_kprintf("[0x%08x - %d - %c%c%c%c] free\n", header_ptr, block_size,
G
guozhanxin 已提交
980 981
                       header_ptr->owner_thread_name[0], header_ptr->owner_thread_name[1],
                       header_ptr->owner_thread_name[2], header_ptr->owner_thread_name[3]);
C
cliff-cmc 已提交
982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
        }

        /* move to next used memory block */
        header_ptr = header_ptr->next;
    }
}

void memtrace_heap()
{
    struct rt_object_information *info;
    struct rt_list_node *list;
    struct rt_memheap *mh;
    struct rt_list_node *node;

    info = rt_object_get_information(RT_Object_Class_MemHeap);
    list = &info->object_list;

    for (node = list->next; node != list; node = node->next)
    {
        mh = (struct rt_memheap *)rt_list_entry(node, struct rt_object, list);
        dump_used_memheap(mh);
    }
}

#ifdef RT_USING_FINSH
#include <finsh.h>
MSH_CMD_EXPORT(memtrace_heap, dump memory trace for heap);
1009
#endif /* RT_USING_FINSH */
C
cliff-cmc 已提交
1010

1011
#endif /* RT_USING_MEMTRACE */
C
cliff-cmc 已提交
1012

1013
#endif /* RT_USING_MEMHEAP */