diff --git a/include/nuttx/mm/mm.h b/include/nuttx/mm/mm.h index 73f4ab92ad..c9f8f888ed 100644 --- a/include/nuttx/mm/mm.h +++ b/include/nuttx/mm/mm.h @@ -224,6 +224,13 @@ struct mm_freenode_s FAR struct mm_freenode_s *blink; }; +#ifdef __KERNEL__ +struct mm_delaynode_s +{ + struct mm_delaynode_s *flink; +}; +#endif + /* What is the size of the freenode? */ #define MM_PTR_SIZE sizeof(FAR struct mm_freenode_s *) @@ -263,6 +270,12 @@ struct mm_heap_s */ struct mm_freenode_s mm_nodelist[MM_NNODES]; + +#ifdef __KERNEL__ + /* Free delay list, for some situation can't do free immdiately */ + + struct mm_delaynode_s mm_delaylist; +#endif }; /**************************************************************************** diff --git a/mm/mm_heap/mm_free.c b/mm/mm_heap/mm_free.c index 8f1afd3311..8b55b57e42 100644 --- a/mm/mm_heap/mm_free.c +++ b/mm/mm_heap/mm_free.c @@ -42,8 +42,31 @@ #include #include +#include +#include #include +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef __KERNEL__ +static void mm_add_delaylist(FAR struct mm_heap_s *heap, FAR void *mem) +{ + FAR struct mm_delaynode_s *new = mem; + irqstate_t flags; + + /* Delay the deallocation until a more appropriate time. */ + + flags = enter_critical_section(); + + new->flink = heap->mm_delaylist.flink; + heap->mm_delaylist.flink = new; + + leave_critical_section(flags); +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -72,11 +95,37 @@ void mm_free(FAR struct mm_heap_s *heap, FAR void *mem) return; } - /* We need to hold the MM semaphore while we muck with the - * nodelist. - */ +#ifdef __KERNEL__ + /* Check current environment */ + + if (up_interrupt_context()) + { + /* We are in ISR, add to mm_delaylist */ + + mm_add_delaylist(heap, mem); + return; + } + else if (mm_trysemaphore(heap) == 0) + { + /* Got the sem, do free immediately */ + } + else if (sched_idletask()) + { + /* We are in IDLE task & can't get sem, add to mm_delaylist */ + + mm_add_delaylist(heap, mem); + return; + } + else +#endif + { + /* We need to hold the MM semaphore while we muck with the + * nodelist. + */ + + mm_takesemaphore(heap); + } - mm_takesemaphore(heap); DEBUGASSERT(mm_heapmember(heap, mem)); /* Map the memory chunk into a free node */ diff --git a/mm/mm_heap/mm_initialize.c b/mm/mm_heap/mm_initialize.c index 7786a745db..4b07fde3cd 100644 --- a/mm/mm_heap/mm_initialize.c +++ b/mm/mm_heap/mm_initialize.c @@ -175,6 +175,12 @@ void mm_initialize(FAR struct mm_heap_s *heap, FAR void *heapstart, heap->mm_nregions = 0; #endif +#ifdef __KERNEL__ + /* Initialize mm_delaylist */ + + heap->mm_delaylist.flink = NULL; +#endif + /* Initialize the node array */ memset(heap->mm_nodelist, 0, sizeof(struct mm_freenode_s) * MM_NNODES); diff --git a/mm/mm_heap/mm_malloc.c b/mm/mm_heap/mm_malloc.c index b3355710a9..ed3fefd32d 100644 --- a/mm/mm_heap/mm_malloc.c +++ b/mm/mm_heap/mm_malloc.c @@ -44,6 +44,7 @@ #include #include +#include #include /**************************************************************************** @@ -54,6 +55,45 @@ # define NULL ((void *)0) #endif +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +#ifdef __KERNEL__ +static void mm_free_delaylist(FAR struct mm_heap_s *heap) +{ + FAR struct mm_delaynode_s *tmp; + irqstate_t flags; + + /* Move the delay list to local */ + + flags = enter_critical_section(); + + tmp = heap->mm_delaylist.flink; + heap->mm_delaylist.flink = NULL; + + leave_critical_section(flags); + + /* Test if the delayed is empty */ + + while (tmp) + { + FAR void *address; + + /* Get the first delayed deallocation */ + + address = tmp; + tmp = tmp->flink; + + /* The address should always be non-NULL since that was checked in the + * 'while' condition above. + */ + + mm_free(heap, address); + } +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -76,6 +116,12 @@ FAR void *mm_malloc(FAR struct mm_heap_s *heap, size_t size) void *ret = NULL; int ndx; +#ifdef __KERNEL__ + /* Firstly, free mm_delaylist */ + + mm_free_delaylist(heap); +#endif + /* Ignore zero-length allocations */ if (size < 1)