From 45ce321f513d005e649098e7f26ebc221f222da5 Mon Sep 17 00:00:00 2001 From: patacongo Date: Fri, 8 Mar 2013 18:29:56 +0000 Subject: [PATCH] Move all memory manager globals to a structure. Pass structure pointer as a handler because MM APIs git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5719 42af7a65-404d-4744-a932-0658087f49c3 --- ChangeLog | 4 + TODO | 67 ++++++- arch/arm/src/lm/chip/lm4f_syscontrol.h | 38 ++-- include/nuttx/kmalloc.h | 10 +- include/nuttx/mm.h | 14 +- mm/Makefile.test | 37 ++-- mm/mm_addfreechunk.c | 6 +- mm/mm_environment.h | 14 +- mm/mm_free.c | 38 ++-- mm/mm_initialize.c | 233 +++++++++++++++---------- mm/mm_internal.h | 102 +++++++---- mm/mm_mallinfo.c | 87 +++++---- mm/mm_malloc.c | 41 +++-- mm/mm_memalign.c | 43 ++++- mm/mm_realloc.c | 60 +++++-- mm/mm_sem.c | 64 +++---- mm/mm_shrinkchunk.c | 9 +- mm/mm_test.c | 23 +-- 18 files changed, 576 insertions(+), 314 deletions(-) diff --git a/ChangeLog b/ChangeLog index 753e4c88c4..62d0fe2871 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4281,3 +4281,7 @@ * net/net_poll.c: Handle the missing case. Now tests for not connected AND not listening. I think that now covers all of the cases including the missing case noted above. (2013-03-07) + * mm/: Move all memory manager globals into a structure. A reference + to this structure is now passed internally between mm APIs. This + change will (eventually) support multiple heaps and heap allocators. + diff --git a/TODO b/TODO index 96a4f8c7e5..5524fe256e 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,4 @@ -NuttX TODO List (Last updated March 6, 2013) +NuttX TODO List (Last updated March 8, 2013) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This file summarizes known NuttX bugs, limitations, inconsistencies with @@ -7,8 +7,8 @@ standards, things that could be improved, and ideas for enhancements. nuttx/ (10) Task/Scheduler (sched/) - (1) Memory Managment (mm/) - (3) Signals (sched/, arch/) + (2) Memory Managment (mm/) + (4) Signals (sched/, arch/) (2) pthreads (sched/) (2) C++ Support (6) Binary loaders (binfmt/) @@ -99,7 +99,7 @@ o Task/Scheduler (sched/) Status: Open. Priority: Medium Low. - Title: ON-DEMAND PAGE INCOMPLETE + Title: ON-DEMAND PAGING INCOMPLETE Description: On-demand paging has recently been incorporated into the RTOS. The design of this feature is described here: http://www.nuttx.org/NuttXDemandPaging.html. @@ -253,6 +253,53 @@ o Memory Managment (mm/) Priority: Medium/Low, a good feature to prevent memory leaks but would have negative impact on memory usage and code size. + Title: MEMORY MANAGEMENT IN THE KERNEL BUILD + Description: If the option CONFIG_NUTTX_KERNEL is selected, then NuttX will + built as two separate blobs: (1) a monolithic, NuttX kernel, + and (2) a user-space application blob. Communication between + the two is via traps in order to get from user-mode to kernel- + mode. + + At present, the final link of the kernel build fails because + of undefined memory allocation logic: kmm_initialize, kmm_addregion, + kmalloc, etc. In the flat build, these map to mm_initialize, + mm_addregion, malloc, etc. but they are undefined in the kernel + build. + + It has not been fully decided how to handle kernel- and user- + memory allocations. Here are some ideas: + + 1) Have only a single user-space heap and heap allocator that + is shared by both kernel- and user-modes. PROs: Simpler, + CONs: Awkward architecture and no security for kernel-mode + allocations. + + 2) Have two separate heap partitions and two copies of the + memory allocators. PROs: Not two difficult, CONs: Partitioning + the heap will not make the best use of heap memory. + + A complication is that the kernel needs to allocate both + protected, kernel private as well as user accessible memory + (such as for stacks). Perhaps this approach would require + three heap partitions. + + 3) Have a classes of two allocators: (1) one that allocates large + regions/pages of memory that can be protected or not, and + (2) the current memory allocator extended to support sbrk(). + The would still be kernel- and user-mode instances of the + memory allocators. Each would sbrk() as necessary to extend + their heap; the pages allocated for the kerne-mode allocator + would be protected but the pages allocated for the user-mode + allocator would not. PROs: Meets all of the needs. CONs: + would limit the size of allocations due to the physical + pages. Complex. There would likely be some small memory + inefficiencies due to quantization to pages. This really + feels like overkill for this class of processor. + + See other kernel build issues under "Build system" + Status: Open + Priority: Low, unless you need a working kernel build now. + o Signals (sched/, arch/) ^^^^^^^^^^^^^^^^^^^^^^^ @@ -281,6 +328,14 @@ o Signals (sched/, arch/) Status: Open Priority: Low. Even if there are only 31 usable signals, that is still a lot. + Title: USER-MODE SIGNALS + Description: In a kernel build (CONFIG_NUTTX_KERNEL). Signal handlers should + execute in user mode. This is to prevent a security hole where + user code can get control of the system in kernel mode if the signal + executes in kernel mode. + Status: Open + Priority: Low + o pthreads (sched/) ^^^^^^^^^^^^^^^^^ @@ -1054,6 +1109,8 @@ o Build system A similar issue exists in NSH that uses some internal OS interfaces that would not be available in a kernel build (such as foreach_task, foreach_mountpoint, etc.). + + See also "Memory Management" for another kernel build issue. Status: Open Priority: Low -- the kernel build configuration is not fully fielded yet. @@ -1772,7 +1829,7 @@ o z80/z8/ez80/z180 (arch/z80) Title: ZDS-II COMPILER PROBLEMS Description: The ZDS-II compiler (version 4.10.1) fails with an internal error - while compiler mm/mm_initialize. This has been reported as + while compiling mm/mm_initialize.c. This has been reported as incident 81509. I have found the following workaround that I use to build for the diff --git a/arch/arm/src/lm/chip/lm4f_syscontrol.h b/arch/arm/src/lm/chip/lm4f_syscontrol.h index 9696962c9a..e0701c11e6 100644 --- a/arch/arm/src/lm/chip/lm4f_syscontrol.h +++ b/arch/arm/src/lm/chip/lm4f_syscontrol.h @@ -416,8 +416,8 @@ #define SYSCON_RCC_OSCSRC_SHIFT 4 /* Bits 5-4: Oscillator Source */ #define SYSCON_RCC_OSCSRC_MASK (0x03 << SYSCON_RCC_OSCSRC_SHIFT) # define SYSCON_RCC_OSCSRC_MOSC (0 << SYSCON_RCC_OSCSRC_SHIFT) /* Main oscillator */ -# define SYSCON_RCC_OSCSRC_IOSC (1 << SYSCON_RCC_OSCSRC_SHIFT) /* Precision internal oscillator (reset) */ -# define SYSCON_RCC_OSCSRC_IOSC4 (2 << SYSCON_RCC_OSCSRC_SHIFT) /* Precision internal oscillator / 4 */ +# define SYSCON_RCC_OSCSRC_PIOSC (1 << SYSCON_RCC_OSCSRC_SHIFT) /* Precision internal oscillator (reset) */ +# define SYSCON_RCC_OSCSRC_PIOSC4 (2 << SYSCON_RCC_OSCSRC_SHIFT) /* Precision internal oscillator / 4 */ # define SYSCON_RCC_OSCSRC_LFIOSC (3 << SYSCON_RCC_OSCSRC_SHIFT) /* Low-frequency internal oscillator */ #define SYSCON_RCC_XTAL_SHIFT 6 /* Bits 10-6: Crystal Value */ #define SYSCON_RCC_XTAL_MASK (31 << SYSCON_RCC_XTAL_SHIFT) @@ -425,23 +425,23 @@ # define SYSCON_RCC_XTAL4096KHZ (7 << SYSCON_RCC_XTAL_SHIFT) /* 4.096 MHz (NO PLL) */ # define SYSCON_RCC_XTAL4915p2KHZ (8 << SYSCON_RCC_XTAL_SHIFT) /* 4.9152 MHz (NO PLL) */ # define SYSCON_RCC_XTAL5000KHZ (9 << SYSCON_RCC_XTAL_SHIFT) /* 5 MHz (USB) */ -# define SYSCON_RCC_XTAL5120KHZ (10 << SYSCON_RCC_XTAL_SHIFT) /* 5.12 MHz */ -# define SYSCON_RCC_XTAL6000KHZ (11 << SYSCON_RCC_XTAL_SHIFT) /* 6 MHz (USB) */ -# define SYSCON_RCC_XTAL6144KHZ (12 << SYSCON_RCC_XTAL_SHIFT) /* 6.144 MHz */ -# define SYSCON_RCC_XTAL7372p8KHZ (13 << SYSCON_RCC_XTAL_SHIFT) /* 7.3728 MHz */ -# define SYSCON_RCC_XTAL8000KHZ (14 << SYSCON_RCC_XTAL_SHIFT) /* 8 MHz (USB) */ -# define SYSCON_RCC_XTAL8192KHZ (15 << SYSCON_RCC_XTAL_SHIFT) /* 8.192 MHz */ -# define SYSCON_RCC_XTAL10000KHZ (16 << SYSCON_RCC_XTAL_SHIFT) /* 10.0 MHz (USB) */ -# define SYSCON_RCC_XTAL12000KHZ (17 << SYSCON_RCC_XTAL_SHIFT) /* 12.0 MHz (USB) */ -# define SYSCON_RCC_XTAL12288KHZ (18 << SYSCON_RCC_XTAL_SHIFT) /* 12.288 MHz */ -# define SYSCON_RCC_XTAL13560KHZ (19 << SYSCON_RCC_XTAL_SHIFT) /* 13.56 MHz */ -# define SYSCON_RCC_XTAL14318p18KHZ (20 << SYSCON_RCC_XTAL_SHIFT) /* 14.31818 MHz */ -# define SYSCON_RCC_XTAL16000KHZ (21 << SYSCON_RCC_XTAL_SHIFT) /* 16.0 MHz (USB) */ -# define SYSCON_RCC_XTAL16384KHZ (22 << SYSCON_RCC_XTAL_SHIFT) /* 16.384 MHz */ -# define SYSCON_RCC_XTAL18000KHZ (23 << SYSCON_RCC_XTAL_SHIFT) /* 18.0 MHz (USB) */ -# define SYSCON_RCC_XTAL20000KHZ (24 << SYSCON_RCC_XTAL_SHIFT) /* 20.0 MHz (USB) */ -# define SYSCON_RCC_XTAL24000KHZ (25 << SYSCON_RCC_XTAL_SHIFT) /* 24.0 MHz (USB) */ -# define SYSCON_RCC_XTAL25000KHZ (26 << SYSCON_RCC_XTAL_SHIFT) /* 25.0 MHz (USB) */ +# define SYSCON_RCC_XTAL5120KHZ (10 << SYSCON_RCC_XTAL_SHIFT) /* 5.12 MHz */ +# define SYSCON_RCC_XTAL6000KHZ (11 << SYSCON_RCC_XTAL_SHIFT) /* 6 MHz (USB) */ +# define SYSCON_RCC_XTAL6144KHZ (12 << SYSCON_RCC_XTAL_SHIFT) /* 6.144 MHz */ +# define SYSCON_RCC_XTAL7372p8KHZ (13 << SYSCON_RCC_XTAL_SHIFT) /* 7.3728 MHz */ +# define SYSCON_RCC_XTAL8000KHZ (14 << SYSCON_RCC_XTAL_SHIFT) /* 8 MHz (USB) */ +# define SYSCON_RCC_XTAL8192KHZ (15 << SYSCON_RCC_XTAL_SHIFT) /* 8.192 MHz */ +# define SYSCON_RCC_XTAL10000KHZ (16 << SYSCON_RCC_XTAL_SHIFT) /* 10.0 MHz (USB) */ +# define SYSCON_RCC_XTAL12000KHZ (17 << SYSCON_RCC_XTAL_SHIFT) /* 12.0 MHz (USB) */ +# define SYSCON_RCC_XTAL12288KHZ (18 << SYSCON_RCC_XTAL_SHIFT) /* 12.288 MHz */ +# define SYSCON_RCC_XTAL13560KHZ (19 << SYSCON_RCC_XTAL_SHIFT) /* 13.56 MHz */ +# define SYSCON_RCC_XTAL14318p18KHZ (20 << SYSCON_RCC_XTAL_SHIFT) /* 14.31818 MHz */ +# define SYSCON_RCC_XTAL16000KHZ (21 << SYSCON_RCC_XTAL_SHIFT) /* 16.0 MHz (USB) */ +# define SYSCON_RCC_XTAL16384KHZ (22 << SYSCON_RCC_XTAL_SHIFT) /* 16.384 MHz */ +# define SYSCON_RCC_XTAL18000KHZ (23 << SYSCON_RCC_XTAL_SHIFT) /* 18.0 MHz (USB) */ +# define SYSCON_RCC_XTAL20000KHZ (24 << SYSCON_RCC_XTAL_SHIFT) /* 20.0 MHz (USB) */ +# define SYSCON_RCC_XTAL24000KHZ (25 << SYSCON_RCC_XTAL_SHIFT) /* 24.0 MHz (USB) */ +# define SYSCON_RCC_XTAL25000KHZ (26 << SYSCON_RCC_XTAL_SHIFT) /* 25.0 MHz (USB) */ #define SYSCON_RCC_BYPASS (1 << 11) /* Bit 11: PLL Bypass */ #define SYSCON_RCC_PWRDN (1 << 13) /* Bit 13: PLL Power Down */ #define SYSCON_RCC_USESYSDIV (1 << 22) /* Bit 22: Enable System Clock Divider */ diff --git a/include/nuttx/kmalloc.h b/include/nuttx/kmalloc.h index de02463706..d6a1bd0b4c 100644 --- a/include/nuttx/kmalloc.h +++ b/include/nuttx/kmalloc.h @@ -60,7 +60,8 @@ #undef KMALLOC_EXTERN #if defined(__cplusplus) # define KMALLOC_EXTERN extern "C" -extern "C" { +extern "C" +{ #else # define KMALLOC_EXTERN extern #endif @@ -76,10 +77,13 @@ extern "C" { #ifndef CONFIG_NUTTX_KERNEL +struct mm_heap_s; +extern struct mm_heap_s g_mmheap; + # define kmm_initialize(h,s) mm_initialize(h,s) # define kmm_addregion(h,s) mm_addregion(h,s) -# define kmm_trysemaphore() mm_trysemaphore() -# define kmm_givesemaphore() mm_givesemaphore() +# define kmm_trysemaphore() mm_trysemaphore(&g_mmheap) +# define kmm_givesemaphore() mm_givesemaphore(&g_mmheap) # define kmalloc(s) malloc(s) # define kzalloc(s) zalloc(s) diff --git a/include/nuttx/mm.h b/include/nuttx/mm.h index cabab2619d..feb45a931a 100644 --- a/include/nuttx/mm.h +++ b/include/nuttx/mm.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/nuttx/mm.h * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -61,20 +61,22 @@ #ifdef __cplusplus #define EXTERN extern "C" -extern "C" { +extern "C" +{ #else #define EXTERN extern #endif /* Functions contained in mm_initialize.c ***********************************/ -EXTERN void mm_initialize(FAR void *heap_start, size_t heap_size); -EXTERN void mm_addregion(FAR void *heapstart, size_t heapsize); +void mm_initialize(FAR void *heap_start, size_t heap_size); +void mm_addregion(FAR void *heapstart, size_t heapsize); /* Functions contained in mm_sem.c ******************************************/ -EXTERN int mm_trysemaphore(void); -EXTERN void mm_givesemaphore(void); +struct mm_heap_s; +int mm_trysemaphore(FAR struct mm_heap_s *heap); +void mm_givesemaphore(FAR struct mm_heap_s *heap); #undef EXTERN #ifdef __cplusplus diff --git a/mm/Makefile.test b/mm/Makefile.test index 2ae9dcb883..8a9e0d8868 100644 --- a/mm/Makefile.test +++ b/mm/Makefile.test @@ -35,34 +35,33 @@ -include $(TOPDIR)/Make.defs -SRCS = mm_test.c mm_initialize.c mm_sem.c mm_addfreechunk.c mm_size2ndx.c mm_shrinkchunk.c \ - mm_malloc.c mm_zalloc.c mm_calloc.c mm_realloc.c \ - mm_memalign.c mm_free.c mm_mallinfo.c -OBJS = $(SRCS:.c=.o1) +SRCS = mm_test.c mm_initialize.c mm_sem.c mm_addfreechunk.c mm_size2ndx.c +SRCS += mm_shrinkchunk.c mm_malloc.c mm_zalloc.c mm_calloc.c mm_realloc.c +SRCS += mm_memalign.c mm_free.c mm_mallinfo.c +OBJS = $(SRCS:.c=.o1) -LIBS = -lpthread -lc +LIBS = -lpthread -lc -CC = gcc -LD = gcc +CC = gcc +LD = gcc -DEFINES = -DMM_TEST=1 -WARNIGNS = -Wall -Wstrict-prototypes -Wshadow -CFLAGS = -g $(DEFINES) -LDFLAGS = +DEFINES = -DMM_TEST=1 +WARNIGNS = -Wall -Wstrict-prototypes -Wshadow +CFLAGS = -g $(DEFINES) +LDFLAGS = -BIN = ..$(DELIM)mm_test +BIN = mm_test -all: $(BIN) +all: $(BIN) $(OBJS): %.o1: %.c @echo "Compiling $<" - $(Q) $(CC) -c $(CFLAGS) $< -o $@ + @$(CC) -c $(CFLAGS) $< -o $@ -$(BIN): $(OBJS) +$(BIN): $(OBJS) @echo "Linking {$(OBJS)} to produce $@" - $(Q) $(LD) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ + @$(LD) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ clean: - $(call DELFILE, $(BIN)) - $(call DELFILE, *.o1) - $(call CLEAN) + rm -f $(BIN) + rm -f *.o1 diff --git a/mm/mm_addfreechunk.c b/mm/mm_addfreechunk.c index fdda3ed8d9..61c11baaf0 100644 --- a/mm/mm_addfreechunk.c +++ b/mm/mm_addfreechunk.c @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_addfreechunk.c * - * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -61,7 +61,7 @@ * ****************************************************************************/ -void mm_addfreechunk(FAR struct mm_freenode_s *node) +void mm_addfreechunk(FAR struct mm_heap_s *heap, FAR struct mm_freenode_s *node) { FAR struct mm_freenode_s *next; FAR struct mm_freenode_s *prev; @@ -72,7 +72,7 @@ void mm_addfreechunk(FAR struct mm_freenode_s *node) /* Now put the new node int the next */ - for (prev = &g_nodelist[ndx], next = g_nodelist[ndx].flink; + for (prev = &heap->mm_nodelist[ndx], next = heap->mm_nodelist[ndx].flink; next && next->size && next->size < node->size; prev = next, next = next->flink); diff --git a/mm/mm_environment.h b/mm/mm_environment.h index d28fbf1d77..0f9967bcb7 100644 --- a/mm/mm_environment.h +++ b/mm/mm_environment.h @@ -40,7 +40,7 @@ * Included Files ****************************************************************************/ -/* The platform configuratioin file will not be included when the memory +/* The platform configuration file will not be included when the memory * manager is built for the host-based test harness. */ @@ -50,13 +50,17 @@ # include # include # include -# include +# include # include # include # include +# include #else # include + +# include # include +# include # include #endif @@ -79,7 +83,7 @@ # define CONFIG_CAN_PASS_STRUCTS 1 /* Normally in config.h */ # undef CONFIG_SMALL_MEMORY /* Normally in config.h */ -extern void mm_addregion(FAR void *heapstart, size_t heapsize); +void mm_addregion(FAR void *heapstart, size_t heapsize); /* Use the real system errno */ @@ -103,6 +107,10 @@ extern void mm_addregion(FAR void *heapstart, size_t heapsize); # undef DEBUGASSERT # define DEBUGASSERT(e) assert(e) +/* Misc. NuttX-isms */ + +#define OK 0 + /* Debug macros are always on */ # define CONFIG_DEBUG 1 diff --git a/mm/mm_free.c b/mm/mm_free.c index b34b8a4593..7f7d92b161 100644 --- a/mm/mm_free.c +++ b/mm/mm_free.c @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_free.c * - * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -51,19 +51,15 @@ ****************************************************************************/ /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: free + * Name: _mm_free * * Description: - * Returns a chunk of memory into the list of free nodes, merging with + * Returns a chunk of memory to the list of free nodes, merging with * adjacent free chunks if possible. * ****************************************************************************/ -void free(FAR void *mem) +static inline void _mm_free(FAR struct mm_heap_s *heap, FAR void *mem) { FAR struct mm_freenode_s *node; FAR struct mm_freenode_s *prev; @@ -82,7 +78,7 @@ void free(FAR void *mem) * nodelist. */ - mm_takesemaphore(); + mm_takesemaphore(heap); /* Map the memory chunk into a free node */ @@ -148,6 +144,26 @@ void free(FAR void *mem) /* Add the merged node to the nodelist */ - mm_addfreechunk(node); - mm_givesemaphore(); + mm_addfreechunk(heap, node); + mm_givesemaphore(heap); } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: free + * + * Description: + * Returns a chunk of memory to the list of free nodes, merging with + * adjacent free chunks if possible. + * + ****************************************************************************/ + +#if !defined(CONFIG_NUTTX_KERNEL) || !defined(__KERNEL__) +void free(FAR void *mem) +{ + _mm_free(&g_mmheap, mem); +} +#endif diff --git a/mm/mm_initialize.c b/mm/mm_initialize.c index a7f64cfafd..d536774ee7 100644 --- a/mm/mm_initialize.c +++ b/mm/mm_initialize.c @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_initialize.c * - * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2011, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -48,98 +48,25 @@ * Public Variables ****************************************************************************/ -/* This is the size of the heap provided to mm */ +#if !defined(CONFIG_NUTTX_KERNEL) || !defined(__KERNEL__) +/* This is the user heap */ -size_t g_heapsize; +struct mm_heap_s g_mmheap; -/* This is the first and last nodes of the heap */ - -FAR struct mm_allocnode_s *g_heapstart[CONFIG_MM_REGIONS]; -FAR struct mm_allocnode_s *g_heapend[CONFIG_MM_REGIONS]; - -#if CONFIG_MM_REGIONS > 1 -int g_nregions; #endif -/* All free nodes are maintained in a doubly linked list. This array - * provides some hooks into the list at various points to speed searches for - * free nodes. - */ - -FAR struct mm_freenode_s g_nodelist[MM_NNODES]; - /**************************************************************************** - * Public Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: mm_initialize + * Name: _mm_addregion * * Description: - * This is an internal OS function called only at power-up boot time. - * - * Parameters: - * heapstart - Start of the initial heap region - * heapsize - Size of the initial heap region - * - * Return Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -void mm_initialize(FAR void *heapstart, size_t heapsize) -{ - int i; - - mlldbg("Heap: start=%p size=%u\n", heapstart, heapsize); - - /* The following two lines have cause problems for some older ZiLog - * compilers in the past (but not the more recent). Life is easier if we - * just the suppress them altogther for those tools. - */ - -#ifndef __ZILOG__ - CHECK_ALLOCNODE_SIZE; - CHECK_FREENODE_SIZE; -#endif - - /* Set up global variables */ - - g_heapsize = 0; - -#if CONFIG_MM_REGIONS > 1 - g_nregions = 0; -#endif - - /* Initialize the node array */ - - memset(g_nodelist, 0, sizeof(struct mm_freenode_s) * MM_NNODES); - for (i = 1; i < MM_NNODES; i++) - { - g_nodelist[i-1].flink = &g_nodelist[i]; - g_nodelist[i].blink = &g_nodelist[i-1]; - } - - /* Initialize the malloc semaphore to one (to support one-at- - * a-time access to private data sets). - */ - - mm_seminitialize(); - - /* Add the initial region of memory to the heap */ - - mm_addregion(heapstart, heapsize); -} - -/**************************************************************************** - * Name: mm_addregion - * - * Description: - * This function gives a region of contiguous memory to the memory manager + * This function adds a region of contiguous memory to the selected heap. * * Parameters: + * heap - The selected heap * heapstart - Start of the heap region * heapsize - Size of the heap region * @@ -150,13 +77,14 @@ void mm_initialize(FAR void *heapstart, size_t heapsize) * ****************************************************************************/ -void mm_addregion(FAR void *heapstart, size_t heapsize) +static inline void _mm_addregion(FAR struct mm_heap_s *heap, + FAR void *heapstart, size_t heapsize) { FAR struct mm_freenode_s *node; uintptr_t heapbase; uintptr_t heapend; #if CONFIG_MM_REGIONS > 1 - int IDX = g_nregions; + int IDX = heap->mm_nregions; #else # define IDX 0 #endif @@ -182,7 +110,7 @@ void mm_addregion(FAR void *heapstart, size_t heapsize) /* Add the size of this region to the total size of the heap */ - g_heapsize += heapsize; + heap->mm_heapsize += heapsize; /* Create two "allocated" guard nodes at the beginning and end of * the heap. These only serve to keep us from allocating outside @@ -192,25 +120,146 @@ void mm_addregion(FAR void *heapstart, size_t heapsize) * all available memory. */ - g_heapstart[IDX] = (FAR struct mm_allocnode_s *)heapbase; - g_heapstart[IDX]->size = SIZEOF_MM_ALLOCNODE; - g_heapstart[IDX]->preceding = MM_ALLOC_BIT; + heap->mm_heapstart[IDX] = (FAR struct mm_allocnode_s *)heapbase; + heap->mm_heapstart[IDX]->size = SIZEOF_MM_ALLOCNODE; + heap->mm_heapstart[IDX]->preceding = MM_ALLOC_BIT; node = (FAR struct mm_freenode_s *)(heapbase + SIZEOF_MM_ALLOCNODE); node->size = heapsize - 2*SIZEOF_MM_ALLOCNODE; node->preceding = SIZEOF_MM_ALLOCNODE; - g_heapend[IDX] = (FAR struct mm_allocnode_s *)(heapend - SIZEOF_MM_ALLOCNODE); - g_heapend[IDX]->size = SIZEOF_MM_ALLOCNODE; - g_heapend[IDX]->preceding = node->size | MM_ALLOC_BIT; + heap->mm_heapend[IDX] = (FAR struct mm_allocnode_s *)(heapend - SIZEOF_MM_ALLOCNODE); + heap->mm_heapend[IDX]->size = SIZEOF_MM_ALLOCNODE; + heap->mm_heapend[IDX]->preceding = node->size | MM_ALLOC_BIT; #undef IDX #if CONFIG_MM_REGIONS > 1 - g_nregions++; + heap->mm_nregions++; #endif /* Add the single, large free node to the nodelist */ - mm_addfreechunk(node); + mm_addfreechunk(heap, node); } + +/**************************************************************************** + * Name: _mm_initialize + * + * Description: + * Initialize the selected heap data structures, providing the initial + * heap region. + * + * Parameters: + * heap - The selected heap + * heapstart - Start of the initial heap region + * heapsize - Size of the initial heap region + * + * Return Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +static inline void _mm_initialize(FAR struct mm_heap_s *heap, + FAR void *heapstart, size_t heapsize) +{ + int i; + + mlldbg("Heap: start=%p size=%u\n", heapstart, heapsize); + + /* The following two lines have cause problems for some older ZiLog + * compilers in the past (but not the more recent). Life is easier if we + * just the suppress them altogther for those tools. + */ + +#ifndef __ZILOG__ + CHECK_ALLOCNODE_SIZE; + CHECK_FREENODE_SIZE; +#endif + + /* Set up global variables */ + + heap->mm_heapsize = 0; + +#if CONFIG_MM_REGIONS > 1 + heap->mm_nregions = 0; +#endif + + /* Initialize the node array */ + + memset(heap->mm_nodelist, 0, sizeof(struct mm_freenode_s) * MM_NNODES); + for (i = 1; i < MM_NNODES; i++) + { + heap->mm_nodelist[i-1].flink = &heap->mm_nodelist[i]; + heap->mm_nodelist[i].blink = &heap->mm_nodelist[i-1]; + } + + /* Initialize the malloc semaphore to one (to support one-at- + * a-time access to private data sets). + */ + + mm_seminitialize(heap); + + /* Add the initial region of memory to the heap */ + + _mm_addregion(heap, heapstart, heapsize); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: mm_initialize + * + * Description: + * This this function is called during initialization to initialize the + * user heap. + * + * Parameters: + * heapstart - Start of the initial heap region + * heapsize - Size of the initial heap region + * + * Return Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#if !defined(CONFIG_NUTTX_KERNEL) || !defined(__KERNEL__) + +void mm_initialize(FAR void *heapstart, size_t heapsize) +{ + _mm_initialize(&g_mmheap, heapstart, heapsize); +} + +#endif + +/**************************************************************************** + * Name: mm_addregion + * + * Description: + * This function adds a region of contiguous memory to the user heap. + * + * Parameters: + * heapstart - Start of the heap region + * heapsize - Size of the heap region + * + * Return Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#if !defined(CONFIG_NUTTX_KERNEL) || !defined(__KERNEL__) + +void mm_addregion(FAR void *heapstart, size_t heapsize) +{ + _mm_addregion(&g_mmheap, heapstart, heapsize); +} + +#endif diff --git a/mm/mm_internal.h b/mm/mm_internal.h index 21cf253d7a..9f1616978b 100644 --- a/mm/mm_internal.h +++ b/mm/mm_internal.h @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_internal.h * - * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2011, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -113,7 +113,7 @@ * Public Types ****************************************************************************/ -/* Determine the size of the chunk size/offset type */ +/* Determines the size of the chunk size/offset type */ #ifdef CONFIG_MM_SMALL typedef uint16_t mmsize_t; @@ -170,6 +170,39 @@ struct mm_freenode_s #define CHECK_FREENODE_SIZE \ DEBUGASSERT(sizeof(struct mm_freenode_s) == SIZEOF_MM_FREENODE) +/* This describes one heap (possibly with multiple regions) */ + +struct mm_heap_s +{ + /* Mutually exclusive access to this data set is enforced with + * the following un-named semaphore. + */ + + sem_t mm_semaphore; + pid_t mm_holder; + int mm_counts_held; + + /* This is the size of the heap provided to mm */ + + size_t mm_heapsize; + + /* This is the first and last nodes of the heap */ + + FAR struct mm_allocnode_s *mm_heapstart[CONFIG_MM_REGIONS]; + FAR struct mm_allocnode_s *mm_heapend[CONFIG_MM_REGIONS]; + +#if CONFIG_MM_REGIONS > 1 + int mm_nregions; +#endif + + /* All free nodes are maintained in a doubly linked list. This + * array provides some hooks into the list at various points to + * speed searches for free nodes. + */ + + struct mm_freenode_s mm_nodelist[MM_NNODES]; +}; + /* Normally defined in stdlib.h */ #ifdef MM_TEST @@ -187,57 +220,58 @@ struct mallinfo #endif /**************************************************************************** - * Global Variables + * Public Variables ****************************************************************************/ -/* This is the size of the heap provided to mm */ - -extern size_t g_heapsize; - -/* This is the first and last nodes of the heap */ - -extern FAR struct mm_allocnode_s *g_heapstart[CONFIG_MM_REGIONS]; -extern FAR struct mm_allocnode_s *g_heapend[CONFIG_MM_REGIONS]; - -#if CONFIG_MM_REGIONS > 1 -extern int g_nregions; +#undef EXTERN +#if defined(__cplusplus) +#define EXTERN extern "C" +extern "C" +{ #else -# define g_nregions 1 +#define EXTERN extern #endif -/* All free nodes are maintained in a doubly linked list. This - * array provides some hooks into the list at various points to - * speed searches for free nodes. - */ +#if !defined(CONFIG_NUTTX_KERNEL) || !defined(__KERNEL__) +/* This is the user heap */ -extern FAR struct mm_freenode_s g_nodelist[MM_NNODES]; +EXTERN struct mm_heap_s g_mmheap; + +#endif /**************************************************************************** * Public Function Prototypes ****************************************************************************/ #ifdef MM_TEST -FAR void *mm_malloc(size_t); -void mm_free(void*); -FAR void *mm_realloc(void*, size_t); -FAR void *mm_memalign(size_t, size_t); -FAR void *mm_zalloc(size_t); -FAR void *mm_calloc(size_t, size_t); +FAR void *mm_malloc(size_t); +void mm_free(void*); +FAR void *mm_realloc(void*, size_t); +FAR void *mm_memalign(size_t, size_t); +FAR void *mm_zalloc(size_t); +FAR void *mm_calloc(size_t, size_t); #ifdef CONFIG_CAN_PASS_STRUCTS struct mallinfo mallinfo(void); #else -int mallinfo(struct mallinfo *info); +int mallinfo(struct mallinfo *info); #endif #endif -void mm_shrinkchunk(FAR struct mm_allocnode_s *node, size_t size); -void mm_addfreechunk(FAR struct mm_freenode_s *node); -int mm_size2ndx(size_t size); -void mm_seminitialize(void); -void mm_takesemaphore(void); -void mm_givesemaphore(void); +void mm_shrinkchunk(FAR struct mm_heap_s *heap, + FAR struct mm_allocnode_s *node, size_t size); +void mm_addfreechunk(FAR struct mm_heap_s *heap, + FAR struct mm_freenode_s *node); +int mm_size2ndx(size_t size); +void mm_seminitialize(FAR struct mm_heap_s *heap); +void mm_takesemaphore(FAR struct mm_heap_s *heap); +void mm_givesemaphore(FAR struct mm_heap_s *heap); #ifdef MM_TEST -int mm_getsemaphore(void); +int mm_getsemaphore(FAR struct mm_heap_s *heap); +#endif + +#undef EXTERN +#if defined(__cplusplus) +} #endif #endif /* __MM_MM_INTERNAL_H */ diff --git a/mm/mm_mallinfo.c b/mm/mm_mallinfo.c index 30c1028fd4..37432a1575 100644 --- a/mm/mm_mallinfo.c +++ b/mm/mm_mallinfo.c @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_mallinfo.c * - * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -55,22 +55,15 @@ ****************************************************************************/ /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: mallinfo + * Name: _mm_mallinfo * * Description: - * mallinfo returns a copy of updated current mallinfo. + * mallinfo returns a copy of updated current heap information. * ****************************************************************************/ -#ifdef CONFIG_CAN_PASS_STRUCTS -struct mallinfo mallinfo(void) -#else -int mallinfo(struct mallinfo *info) -#endif +static inline int _mm_mallinfo(FAR struct mm_heap_s *heap, + FAR struct mallinfo *info) { struct mm_allocnode_s *node; size_t mxordblk = 0; @@ -83,29 +76,22 @@ int mallinfo(struct mallinfo *info) # define region 0 #endif -#ifdef CONFIG_CAN_PASS_STRUCTS - static struct mallinfo info; -#else - if (!info) - { - return ERROR; - } -#endif + DEBUGASSERT(info); /* Visit each region */ #if CONFIG_MM_REGIONS > 1 - for (region = 0; region < g_nregions; region++) + for (region = 0; region < heap->mm_nregions; region++) #endif { /* Visit each node in the region * Retake the semaphore for each region to reduce latencies */ - mm_takesemaphore(); + mm_takesemaphore(heap); - for (node = g_heapstart[region]; - node < g_heapend[region]; + for (node = heap->mm_heapstart[region]; + node < heap->mm_heapend[region]; node = (struct mm_allocnode_s *)((char*)node + node->size)) { mvdbg("region=%d node=%p size=%p preceding=%p\n", region, node, node->size, node->preceding); @@ -124,29 +110,54 @@ int mallinfo(struct mallinfo *info) } } - mm_givesemaphore(); + mm_givesemaphore(heap); - mvdbg("region=%d node=%p g_heapend=%p\n", region, node, g_heapend[region]); - DEBUGASSERT(node == g_heapend[region]); + mvdbg("region=%d node=%p heapend=%p\n", region, node, heap->mm_heapend[region]); + DEBUGASSERT(node == heap->mm_heapend[region]); uordblks += SIZEOF_MM_ALLOCNODE; /* account for the tail node */ } #undef region - DEBUGASSERT(uordblks + fordblks == g_heapsize); + DEBUGASSERT(uordblks + fordblks == heap->mm_heapsize); -#ifdef CONFIG_CAN_PASS_STRUCTS - info.arena = g_heapsize; - info.ordblks = ordblks; - info.mxordblk = mxordblk; - info.uordblks = uordblks; - info.fordblks = fordblks; - return info; -#else - info->arena = g_heapsize; + info->arena = heap->mm_heapsize; info->ordblks = ordblks; info->mxordblk = mxordblk; info->uordblks = uordblks; info->fordblks = fordblks; return OK; -#endif } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: kmallinfo and mallinfo + * + * Description: + * mallinfo returns a copy of updated current heap information for either + * the user heap (mallinfo) or the kernel heap (kmallinfo). + * + ****************************************************************************/ + +#if !defined(CONFIG_NUTTX_KERNEL) || !defined(__KERNEL__) +# ifdef CONFIG_CAN_PASS_STRUCTS + +struct mallinfo mallinfo(void) +{ + struct mallinfo info; + + _mm_mallinfo(&g_mmheap, &info); + return info; +} + +# else + +int mallinfo(struct mallinfo *info) +{ + return _mm_mallinfo(&g_mmheap, info); +} + +#endif +#endif /* !CONFIG_NUTTX_KERNEL || !__KERNEL__ */ diff --git a/mm/mm_malloc.c b/mm/mm_malloc.c index 4f138957f9..331f8eefdc 100644 --- a/mm/mm_malloc.c +++ b/mm/mm_malloc.c @@ -71,11 +71,7 @@ ****************************************************************************/ /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: malloc + * Name: _mm_malloc * * Description: * Find the smallest chunk that satisfies the request. Take the memory from @@ -85,7 +81,7 @@ * ****************************************************************************/ -FAR void *malloc(size_t size) +static inline FAR void *_mm_malloc(FAR struct mm_heap_s *heap, size_t size) { FAR struct mm_freenode_s *node; void *ret = NULL; @@ -106,7 +102,7 @@ FAR void *malloc(size_t size) /* We need to hold the MM semaphore while we muck with the nodelist. */ - mm_takesemaphore(); + mm_takesemaphore(heap); /* Get the location in the node list to start the search. Special case * really big allocations @@ -125,10 +121,10 @@ FAR void *malloc(size_t size) /* Search for a large enough chunk in the list of nodes. This list is * ordered by size, but will have occasional zero sized nodes as we visit - * other g_nodelist[] entries. + * other mm_nodelist[] entries. */ - for (node = g_nodelist[ndx].flink; + for (node = heap->mm_nodelist[ndx].flink; node && node->size < size; node = node->flink); @@ -186,7 +182,7 @@ FAR void *malloc(size_t size) /* Add the remainder back into the nodelist */ - mm_addfreechunk(remainder); + mm_addfreechunk(heap, remainder); } /* Handle the case of an exact size match */ @@ -195,7 +191,7 @@ FAR void *malloc(size_t size) ret = (void*)((char*)node + SIZEOF_MM_ALLOCNODE); } - mm_givesemaphore(); + mm_givesemaphore(heap); /* If CONFIG_DEBUG_MM is defined, then output the result of the allocation * to the SYSLOG. @@ -214,3 +210,26 @@ FAR void *malloc(size_t size) return ret; } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: malloc + * + * Description: + * Find the smallest chunk that satisfies the request. Take the memory from + * that chunk, save the remaining, smaller chunk (if any). + * + * 8-byte alignment of the allocated data is assured. + * + ****************************************************************************/ + +#if !defined(CONFIG_NUTTX_KERNEL) || !defined(__KERNEL__) +FAR void *malloc(size_t size) +{ + return _mm_malloc(&g_mmheap, size); +} +#endif + diff --git a/mm/mm_memalign.c b/mm/mm_memalign.c index 87547c96bf..d069645346 100644 --- a/mm/mm_memalign.c +++ b/mm/mm_memalign.c @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_memalign.c * - * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2011, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -47,11 +47,11 @@ ****************************************************************************/ /**************************************************************************** - * Global Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: memalign + * Name: _mm_memalign * * Description: * memalign requests more than enough space from malloc, finds a region @@ -63,7 +63,8 @@ * ****************************************************************************/ -FAR void *memalign(size_t alignment, size_t size) +static inline FAR void *_mm_memalign(FAR struct mm_heap_s *heap, + size_t alignment, size_t size) { FAR struct mm_allocnode_s *node; size_t rawchunk; @@ -107,7 +108,7 @@ FAR void *memalign(size_t alignment, size_t size) * nodelist. */ - mm_takesemaphore(); + mm_takesemaphore(heap); /* Get the node associated with the allocation and the next node after * the allocation. @@ -182,7 +183,7 @@ FAR void *memalign(size_t alignment, size_t size) /* Add the original, newly freed node to the free nodelist */ - mm_addfreechunk((FAR struct mm_freenode_s *)node); + mm_addfreechunk(heap, (FAR struct mm_freenode_s *)node); /* Replace the original node with the newlay realloaced, * aligned node @@ -200,9 +201,35 @@ FAR void *memalign(size_t alignment, size_t size) * malloc-compatible sizes that we have. */ - mm_shrinkchunk(node, size + SIZEOF_MM_ALLOCNODE); + mm_shrinkchunk(heap, node, size + SIZEOF_MM_ALLOCNODE); } - mm_givesemaphore(); + mm_givesemaphore(heap); return (FAR void*)alignedchunk; } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: _mm_memalign + * + * Description: + * memalign requests more than enough space from malloc, finds a region + * within that chunk that meets the alignment request and then frees any + * leading or trailing space. + * + * The alignment argument must be a power of two (not checked). 8-byte + * alignment is guaranteed by normal malloc calls. + * + ****************************************************************************/ + +#if !defined(CONFIG_NUTTX_KERNEL) || !defined(__KERNEL__) + +FAR void *memalign(size_t alignment, size_t size) +{ + return _mm_memalign(&g_mmheap, alignment, size); +} + +#endif diff --git a/mm/mm_realloc.c b/mm/mm_realloc.c index b449389958..5364a97a87 100644 --- a/mm/mm_realloc.c +++ b/mm/mm_realloc.c @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_realloc.c * - * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -47,11 +47,11 @@ ****************************************************************************/ /**************************************************************************** - * Global Functions + * Private Functions ****************************************************************************/ /**************************************************************************** - * Name: realloc + * Name: _mm_realloc * * Description: * If the reallocation is for less space, then: @@ -73,7 +73,8 @@ * ****************************************************************************/ -FAR void *realloc(FAR void *oldmem, size_t size) +static inline FAR void *_mm_realloc(FAR struct mm_heap_s *heap, + FAR void *oldmem, size_t size) { FAR struct mm_allocnode_s *oldnode; FAR struct mm_freenode_s *prev; @@ -110,7 +111,7 @@ FAR void *realloc(FAR void *oldmem, size_t size) /* We need to hold the MM semaphore while we muck with the nodelist. */ - mm_takesemaphore(); + mm_takesemaphore(heap); /* Check if this is a request to reduce the size of the allocation. */ @@ -123,12 +124,12 @@ FAR void *realloc(FAR void *oldmem, size_t size) if (size < oldsize) { - mm_shrinkchunk(oldnode, size); + mm_shrinkchunk(heap, oldnode, size); } /* Then return the original address */ - mm_givesemaphore(); + mm_givesemaphore(heap); return oldmem; } @@ -248,7 +249,7 @@ FAR void *realloc(FAR void *oldmem, size_t size) /* Return the previous free node to the nodelist (with the new size) */ - mm_addfreechunk(prev); + mm_addfreechunk(heap, prev); /* Now we want to return newnode */ @@ -317,7 +318,7 @@ FAR void *realloc(FAR void *oldmem, size_t size) /* Add the new free node to the nodelist (with the new size) */ - mm_addfreechunk(newnode); + mm_addfreechunk(heap, newnode); } else { @@ -327,7 +328,7 @@ FAR void *realloc(FAR void *oldmem, size_t size) } } - mm_givesemaphore(); + mm_givesemaphore(heap); return newmem; } @@ -339,7 +340,7 @@ FAR void *realloc(FAR void *oldmem, size_t size) * leave the original memory in place. */ - mm_givesemaphore(); + mm_givesemaphore(heap); newmem = (FAR void*)malloc(size); if (newmem) { @@ -350,3 +351,40 @@ FAR void *realloc(FAR void *oldmem, size_t size) return newmem; } } + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: realloc + * + * Description: + * If the reallocation is for less space, then: + * + * (1) the current allocation is reduced in size + * (2) the remainder at the end of the allocation is returned to the + * free list. + * + * If the request is for more space and the current allocation can be + * extended, it will be extended by: + * + * (1) Taking the additional space from the following free chunk, or + * (2) Taking the additional space from the preceding free chunk. + * (3) Or both + * + * If the request is for more space but the current chunk cannot be + * extended, then malloc a new buffer, copy the data into the new buffer, + * and free the old buffer. + * + ****************************************************************************/ + +#if !defined(CONFIG_NUTTX_KERNEL) || !defined(__KERNEL__) + +FAR void *realloc(FAR void *oldmem, size_t size) +{ + return _mm_realloc(&g_mmheap, oldmem, size); +} + +#endif + diff --git a/mm/mm_sem.c b/mm/mm_sem.c index 19fff780b9..61e4fc2f01 100644 --- a/mm/mm_sem.c +++ b/mm/mm_sem.c @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_sem.c * - * Copyright (C) 2007-2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -40,7 +40,6 @@ #include "mm_environment.h" #include -#include #include #include @@ -72,13 +71,6 @@ * Private Data ****************************************************************************/ -/* Mutually exclusive access to this data set is enforced with - * the following (un-named) semaphore. */ - -static sem_t g_mm_semaphore; -static pid_t g_holder; -static int g_counts_held; - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -91,16 +83,16 @@ static int g_counts_held; * ****************************************************************************/ -void mm_seminitialize(void) +void mm_seminitialize(FAR struct mm_heap_s *heap) { /* Initialize the MM semaphore to one (to support one-at-a-time access to * private data sets. */ - (void)sem_init(&g_mm_semaphore, 0, 1); + (void)sem_init(&heap->mm_semaphore, 0, 1); - g_holder = -1; - g_counts_held = 0; + heap->mm_holder = -1; + heap->mm_counts_held = 0; } /**************************************************************************** @@ -115,32 +107,32 @@ void mm_seminitialize(void) ****************************************************************************/ #ifndef MM_TEST -int mm_trysemaphore(void) +int mm_trysemaphore(FAR struct mm_heap_s *heap) { pid_t my_pid = getpid(); /* Do I already have the semaphore? */ - if (g_holder == my_pid) + if (heap->mm_holder == my_pid) { /* Yes, just increment the number of references that I have */ - g_counts_held++; + heap->mm_counts_held++; return OK; } else { /* Try to take the semaphore (perhaps waiting) */ - if (sem_trywait(&g_mm_semaphore) != 0) + if (sem_trywait(&heap->mm_semaphore) != 0) { return ERROR; } /* We have it. Claim the stak and return */ - g_holder = my_pid; - g_counts_held = 1; + heap->mm_holder = my_pid; + heap->mm_counts_held = 1; return OK; } } @@ -155,24 +147,24 @@ int mm_trysemaphore(void) * ****************************************************************************/ -void mm_takesemaphore(void) +void mm_takesemaphore(FAR struct mm_heap_s *heap) { pid_t my_pid = getpid(); /* Do I already have the semaphore? */ - if (g_holder == my_pid) + if (heap->mm_holder == my_pid) { /* Yes, just increment the number of references that I have */ - g_counts_held++; + heap->mm_counts_held++; } else { /* Take the semaphore (perhaps waiting) */ msemdbg("PID=%d taking\n", my_pid); - while (sem_wait(&g_mm_semaphore) != 0) + while (sem_wait(&heap->mm_semaphore) != 0) { /* The only case that an error should occur here is if * the wait was awakened by a signal. @@ -183,11 +175,11 @@ void mm_takesemaphore(void) /* We have it. Claim the stake and return */ - g_holder = my_pid; - g_counts_held = 1; + heap->mm_holder = my_pid; + heap->mm_counts_held = 1; } - msemdbg("Holder=%d count=%d\n", g_holder, g_counts_held); + msemdbg("Holder=%d count=%d\n", heap->mm_holder, heap->mm_counts_held); } /**************************************************************************** @@ -198,7 +190,7 @@ void mm_takesemaphore(void) * ****************************************************************************/ -void mm_givesemaphore(void) +void mm_givesemaphore(FAR struct mm_heap_s *heap) { #ifdef CONFIG_DEBUG pid_t my_pid = getpid(); @@ -206,25 +198,25 @@ void mm_givesemaphore(void) /* I better be holding at least one reference to the semaphore */ - DEBUGASSERT(g_holder == my_pid); + DEBUGASSERT(heap->mm_holder == my_pid); /* Do I hold multiple references to the semphore */ - if (g_counts_held > 1) + if (heap->mm_counts_held > 1) { /* Yes, just release one count and return */ - g_counts_held--; - msemdbg("Holder=%d count=%d\n", g_holder, g_counts_held); + heap->mm_counts_held--; + msemdbg("Holder=%d count=%d\n", heap->mm_holder, heap->mm_counts_held); } else { /* Nope, this is the last reference I have */ msemdbg("PID=%d giving\n", my_pid); - g_holder = -1; - g_counts_held = 0; - ASSERT(sem_post(&g_mm_semaphore) == 0); + heap->mm_holder = -1; + heap->mm_counts_held = 0; + ASSERT(sem_post(&heap->mm_semaphore) == 0); } } @@ -237,10 +229,10 @@ void mm_givesemaphore(void) ****************************************************************************/ #ifdef MM_TEST -int mm_getsemaphore(void) +int mm_getsemaphore(FAR struct mm_heap_s *heap) { int sval; - sem_getvalue(&g_mm_semaphore, &sval); + sem_getvalue(&heap->mm_semaphore, &sval); return sval; } #endif diff --git a/mm/mm_shrinkchunk.c b/mm/mm_shrinkchunk.c index e538e43edb..c20aaf0fb0 100644 --- a/mm/mm_shrinkchunk.c +++ b/mm/mm_shrinkchunk.c @@ -1,7 +1,7 @@ /**************************************************************************** * mm/mm_shrinkchunk.c * - * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 1013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -63,7 +63,8 @@ * ****************************************************************************/ -void mm_shrinkchunk(FAR struct mm_allocnode_s *node, size_t size) +void mm_shrinkchunk(FAR struct mm_heap_s *heap, + FAR struct mm_allocnode_s *node, size_t size) { FAR struct mm_freenode_s *next; @@ -108,7 +109,7 @@ void mm_shrinkchunk(FAR struct mm_allocnode_s *node, size_t size) /* Add the new node to the freenodelist */ - mm_addfreechunk(newnode); + mm_addfreechunk(heap, newnode); } /* The next chunk is allocated. Try to free the end portion at the end @@ -134,6 +135,6 @@ void mm_shrinkchunk(FAR struct mm_allocnode_s *node, size_t size) /* Add the new node to the freenodelist */ - mm_addfreechunk(newnode); + mm_addfreechunk(heap, newnode); } } diff --git a/mm/mm_test.c b/mm/mm_test.c index b25a240958..483fd165c3 100644 --- a/mm/mm_test.c +++ b/mm/mm_test.c @@ -1,7 +1,7 @@ /************************************************************************ * mm/mm_test.c * - * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2009, 2011, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -40,6 +40,7 @@ #include #include #include +#include /************************************************************************ * Pre-processor Definitions @@ -133,7 +134,7 @@ static int mm_findinfreelist(struct mm_freenode_s *node) { struct mm_freenode_s *list; - for(list = &g_nodelist[0]; + for(list = &g_mmheap.mm_nodelist[0]; list; list = list->flink) { @@ -165,13 +166,13 @@ static void mm_showchunkinfo(void) /* Visit each region */ #if CONFIG_MM_REGIONS > 1 - for (region = 0; region < g_nregions; region++) + for (region = 0; region < g_mmheap.mm_nregions; region++) #endif { /* Visit each node in each region */ - for (node = g_heapstart[region]; - node < g_heapend[region]; + for (node = g_mmheap.mm_heapstart[region]; + node < g_mmheap.mm_heapend[region]; node = (struct mm_allocnode_s *)((char*)node + node->size)) { printf(" %p 0x%08x 0x%08x %s", @@ -206,7 +207,7 @@ static void mm_showfreelist(void) int i = 0; printf(" FREE NODE LIST:\n"); - for(prev = NULL, node = &g_nodelist[0]; + for(prev = NULL, node = &g_mmheap.mm_nodelist[0]; node; prev = node, node = node->flink) { @@ -258,7 +259,7 @@ static void mm_showmallinfo(void) printf(" Total non-inuse space = %ld\n", alloc_info.fordblks); - sval = mm_getsemaphore(); + sval = mm_getsemaphore(&g_mmheap); if (sval != 1) { fprintf(stderr, "After mallinfo, semaphore count=%d, should be 1\n", sval); @@ -322,7 +323,7 @@ static void do_mallocs(void **mem, const int *size, const int *rand, memset(mem[j], 0xAA, size[j]); } - sval = mm_getsemaphore(); + sval = mm_getsemaphore(&g_mmheap); if (sval != 1) { fprintf(stderr, " After malloc semaphore count=%d, should be 1\n", sval); @@ -371,7 +372,7 @@ static void do_reallocs(void **mem, const int *oldsize, memset(mem[j], 0x55, newsize[j]); } - sval = mm_getsemaphore(); + sval = mm_getsemaphore(&g_mmheap); if (sval != 1) { fprintf(stderr, " After realloc semaphore count=%d, should be 1\n", sval); @@ -419,7 +420,7 @@ static void do_memaligns(void **mem, const int *size, const int *align, memset(mem[j], 0x33, size[j]); } - sval = mm_getsemaphore(); + sval = mm_getsemaphore(&g_mmheap); if (sval != 1) { fprintf(stderr, " After memalign semaphore count=%d, should be 1\n", sval); @@ -448,7 +449,7 @@ static void do_frees(void **mem, const int *size, const int *rand, int n) mm_free(mem[j]); mem[j] = NULL; - sval = mm_getsemaphore(); + sval = mm_getsemaphore(&g_mmheap); if (sval != 1) { fprintf(stderr, " After free semaphore count=%d, should be 1\n", sval);