implementation of mg_slice_xxx

This commit is contained in:
Vincent Wei
2019-04-04 12:18:10 +08:00
parent e3ae994212
commit 8ac0d539d0
10 changed files with 1856 additions and 44 deletions
+2 -1
View File
@@ -76,7 +76,8 @@ AC_FUNC_ALLOCA
AC_FUNC_MEMCMP
AC_FUNC_MMAP
AC_FUNC_VPRINTF
AC_CHECK_FUNCS(time mktime localtime strdup strcasecmp strncasecmp strerror setlocale getpt)
AC_CHECK_FUNCS(time mktime localtime strdup strcasecmp strncasecmp strerror setlocale)
AC_CHECK_FUNCS(posix_memalign memalign valloc)
dnl ========================================================================
dnl User selectable options
+44 -12
View File
@@ -169,10 +169,10 @@ typedef signed int Sint32;
/* Figure out how to support 64-bit datatypes */
#if !defined(__STRICT_ANSI__)
# if defined(__GNUC__)
# define MGUI_HAS_64BIT_TYPE long long
# define MGUI_HAS_64BIT_TYPE long long
# endif
# if defined(__CC_ARM)
# define MGUI_HAS_64BIT_TYPE long long
# define MGUI_HAS_64BIT_TYPE long long
# endif
# if defined(_MSC_VER)
# define MGUI_HAS_64BIT_TYPE __int64
@@ -199,8 +199,8 @@ typedef signed MGUI_HAS_64BIT_TYPE Sint64;
#else
/* This is really just a hack to prevent the compiler from complaining */
typedef struct {
Uint32 hi;
Uint32 lo;
Uint32 hi;
Uint32 lo;
} Uint64, Sint64;
#endif
@@ -221,6 +221,38 @@ MGUI_COMPILE_TIME_ASSERT(sint64, sizeof(Sint64) == 8);
/** @} end of basic_types */
/* Here we provide MG_GNUC_EXTENSION as an alias for __extension__,
* where this is valid. This allows for warningless compilation of
* "long long" types even in the presence of '-ansi -pedantic'.
*/
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)
#define MG_GNUC_EXTENSION __extension__
#else
#define MG_GNUC_EXTENSION
#endif
/*
* The MG_LIKELY and MG_UNLIKELY macros let the programmer give hints to
* the compiler about the expected result of an expression. Some compilers
* can use this information for optimizations.
*/
#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
#define _MG_BOOLEAN_EXPR(expr) \
MG_GNUC_EXTENSION ({ \
int _g_boolean_var_; \
if (expr) \
_g_boolean_var_ = 1; \
else \
_g_boolean_var_ = 0; \
_g_boolean_var_; \
})
#define MG_LIKELY(expr) (__builtin_expect (_MG_BOOLEAN_EXPR(expr), 1))
#define MG_UNLIKELY(expr) (__builtin_expect (_MG_BOOLEAN_EXPR(expr), 0))
#else
#define MG_LIKELY(expr) (expr)
#define MG_UNLIKELY(expr) (expr)
#endif
/**
* \defgroup endian_info Endianness information
* @{
@@ -1778,12 +1810,12 @@ struct tm {
#include "os_type.h"
#include "os_file_api.h"
#define fopen tp_fopen
#define fclose tp_fclose
#define fwrite tp_fwrite
#define fread tp_fread
#define fseek tp_fseek
#define feof tp_feof
#define fopen tp_fopen
#define fclose tp_fclose
#define fwrite tp_fwrite
#define fread tp_fread
#define fseek tp_fseek
#define feof tp_feof
#undef assert
#define _HAVE_ASSERT 1
@@ -1907,8 +1939,8 @@ int init_minigui_printf (int (*output_char) (int ch),
#ifdef WIN32
# include <float.h>
# define isnan _isnan
# define finite _finite
# define isnan _isnan
# define finite _finite
#endif
#undef _I18N_MB_REQUIRED
+321
View File
@@ -3508,6 +3508,327 @@ MG_EXPORT char * strtrimall (char* src);
/** @} end of str_helpers */
/**
* \defgroup slices_allocator_fns Slice Memory Allocator
*
* An efficient way to allocate groups of equal-sized chunks of memory.
*
* Memory slices provide a space-efficient and multi-processing scalable
* way to allocate equal-sized pieces of memory, just like the
* MiniGUI's block data heap (\a block_heap_fns). Relative to the
* standard malloc function and block data heap, this allocator can
* avoid excessive memory-waste, scalability and performance problems.
*
* Note that this implementation is derived from LGPL'd glib.
*
* To achieve these goals, the slice allocator uses a sophisticated,
* layered design that has been inspired by Bonwick's slab allocator
* ([Bonwick94](http://citeseer.ist.psu.edu/bonwick94slab.html)
* Jeff Bonwick, The slab allocator: An object-caching kernel
* memory allocator. USENIX 1994, and
* [Bonwick01](http://citeseer.ist.psu.edu/bonwick01magazines.html)
* Bonwick and Jonathan Adams, Magazines and vmem: Extending the
* slab allocator to many cpu's and arbitrary resources. USENIX 2001)
*
* It uses posix_memalign() to optimize allocations of many equally-sized
* chunks, and has per-thread free lists (the so-called magazine layer)
* to quickly satisfy allocation requests of already known structure sizes.
* This is accompanied by extra caching logic to keep freed memory around
* for some time before returning it to the system. Memory that is unused
* due to alignment constraints is used for cache colorization (random
* distribution of chunk addresses) to improve CPU cache utilization. The
* caching layer of the slice allocator adapts itself to high lock
* contention to improve scalability.
*
* The slice allocator can allocate blocks as small as two pointers, and
* unlike malloc(), it does not reserve extra space per block. For large
* block sizes, mg_slice_new() and mg_slice_alloc() will automatically
* delegate to the system malloc() implementation. For newly written code
* it is recommended to use the new `mg_slice` API instead of malloc() and
* friends, as long as objects are not resized during their lifetime and
* the object size used at allocation time is still available when freeing.
*
* Here is an example for using the slice allocator:
*
* \code
* char *mem[10000];
* int i;
*
* // Allocate 10000 blocks.
* for (i = 0; i < 10000; i++)
* {
* mem[i] = mg_slice_alloc (50);
*
* // Fill in the memory with some junk.
* for (j = 0; j < 50; j++)
* mem[i][j] = i * j;
* }
*
* // Now free all of the blocks.
* for (i = 0; i < 10000; i++)
* mg_slice_free1 (50, mem[i]);
* \endcode
*
* And here is an example for using the slice allocator
* with data structures:
*
* \code
* MyStruct *array;
*
* // Allocate one block, using the mg_slice_new() macro.
* array = mg_slice_new (MyStruct);
*
* // We can now use array just like a normal pointer to a structure.
* array->data = NULL;
* array->len = 0;
* array->alloc = 0;
* array->zero_terminated = (zero_terminated ? 1 : 0);
* array->clear = (clear ? 1 : 0);
* array->elt_size = elt_size;
*
* // We can free the block, so it can be reused.
* mg_slice_free (MyStruct, array);
* \endcode
*
* @{
*/
/**
* mg_slice_alloc:
* @block_size: the number of bytes to allocate
*
* Allocates a block of memory from the slice allocator.
* The block address handed out can be expected to be aligned
* to at least 1 * sizeof (void*),
* though in general slices are 2 * sizeof (void*) bytes aligned,
* if a malloc() fallback implementation is used instead,
* the alignment may be reduced in a libc dependent fashion.
* Note that the underlying slice allocation mechanism can
* be changed with the [`G_SLICE=always-malloc`][G_SLICE]
* environment variable.
*
* Returns: a pointer to the allocated memory block, which will be %NULL if and
* only if @mem_size is 0
*
* Since: 3.4.0
*/
MG_EXPORT void *mg_slice_alloc(size_t block_size);
/**
* mg_slice_alloc0:
* @block_size: the number of bytes to allocate
*
* Allocates a block of memory via mg_slice_alloc() and initializes
* the returned memory to 0. Note that the underlying slice allocation
* mechanism can be changed with the [`G_SLICE=always-malloc`][G_SLICE]
* environment variable.
*
* Returns: a pointer to the allocated block, which will be %NULL if and only
* if @mem_size is 0
*
* Since: 3.4.0
*/
MG_EXPORT void *mg_slice_alloc0(size_t block_size);
/**
* mg_slice_copy:
* @block_size: the number of bytes to allocate
* @mem_block: the memory to copy
*
* Allocates a block of memory from the slice allocator
* and copies @block_size bytes into it from @mem_block.
*
* @mem_block must be non-%NULL if @block_size is non-zero.
*
* Returns: a pointer to the allocated memory block, which will be %NULL if and
* only if @mem_size is 0
*
* Since: 3.4.0
*/
MG_EXPORT void *mg_slice_copy(size_t block_size, const void *mem_block);
/**
* mg_slice_free1:
* @block_size: the size of the block
* @mem_block: a pointer to the block to free
*
* Frees a block of memory.
*
* The memory must have been allocated via mg_slice_alloc() or
* mg_slice_alloc0() and the @block_size has to match the size
* specified upon allocation. Note that the exact release behaviour
* can be changed with the [`G_DEBUG=gc-friendly`][G_DEBUG] environment
* variable, also see [`G_SLICE`][G_SLICE] for related debugging options.
*
* If @mem_block is %NULL, this function does nothing.
*
* Since: 3.4.0
*/
MG_EXPORT void mg_slice_free1(size_t block_size, void *mem_block);
/**
* mg_slice_free_chain_with_offset:
* @block_size: the size of the blocks
* @mem_chain: a pointer to the first block of the chain
* @next_offset: the offset of the @next field in the blocks
*
* Frees a linked list of memory blocks of structure type @type.
*
* The memory blocks must be equal-sized, allocated via
* mg_slice_alloc() or mg_slice_alloc0() and linked together by a
* @next pointer (similar to #GSList). The offset of the @next
* field in each block is passed as third argument.
* Note that the exact release behaviour can be changed with the
* [`G_DEBUG=gc-friendly`][G_DEBUG] environment variable, also see
* [`G_SLICE`][G_SLICE] for related debugging options.
*
* If @mem_chain is %NULL, this function does nothing.
*
* Since: 3.4.0
*/
MG_EXPORT void mg_slice_free_chain_with_offset(size_t block_size,
void *mem_chain, size_t next_offset);
/**
* mg_slice_new:
* @type: the type to allocate, typically a structure name
*
* A convenience macro to allocate a block of memory from the
* slice allocator.
*
* It calls mg_slice_alloc() with `sizeof (@type)` and casts the
* returned pointer to a pointer of the given type, avoiding a type
* cast in the source code. Note that the underlying slice allocation
* mechanism can be changed with the [`G_SLICE=always-malloc`][G_SLICE]
* environment variable.
*
* This can never return %NULL as the minimum allocation size from
* `sizeof (@type)` is 1 byte.
*
* Returns: (not nullable): a pointer to the allocated block, cast to a pointer
* to @type
*
* Since: 3.4.0
*/
#define mg_slice_new(type) ((type*)mg_slice_alloc(sizeof (type)))
/**
* mg_slice_new0:
* @type: the type to allocate, typically a structure name
*
* A convenience macro to allocate a block of memory from the
* slice allocator and set the memory to 0.
*
* It calls mg_slice_alloc0() with `sizeof (@type)`
* and casts the returned pointer to a pointer of the given type,
* avoiding a type cast in the source code.
* Note that the underlying slice allocation mechanism can
* be changed with the [`G_SLICE=always-malloc`][G_SLICE]
* environment variable.
*
* This can never return %NULL as the minimum allocation size from
* `sizeof (@type)` is 1 byte.
*
* Returns: (not nullable): a pointer to the allocated block, cast to a pointer
* to @type
*
* Since: 3.4.0
*/
#define mg_slice_new0(type) ((type*)mg_slice_alloc0(sizeof (type)))
/* MemoryBlockType *
* mg_slice_dup (MemoryBlockType,
* MemoryBlockType *mem_block);
* mg_slice_free (MemoryBlockType,
* MemoryBlockType *mem_block);
* mg_slice_free_chain (MemoryBlockType,
* MemoryBlockType *first_chain_block,
* memory_block_next_field);
* pseudo prototypes for the macro definitions following below.
*/
/**
* mg_slice_dup:
* @type: the type to duplicate, typically a structure name
* @mem: (not nullable): the memory to copy into the allocated block
*
* A convenience macro to duplicate a block of memory using
* the slice allocator.
*
* It calls mg_slice_copy() with `sizeof (@type)`
* and casts the returned pointer to a pointer of the given type,
* avoiding a type cast in the source code.
* Note that the underlying slice allocation mechanism can
* be changed with the [`G_SLICE=always-malloc`][G_SLICE]
* environment variable.
*
* This can never return %NULL.
*
* Returns: (not nullable): a pointer to the allocated block, cast to a pointer
* to @type
*
* Since: 3.4.0
*/
#define mg_slice_dup(type, mem) \
(1 ? (type*) mg_slice_copy (sizeof (type), (mem)) \
: ((void) ((type*) 0 == (mem)), (type*) 0))
/**
* mg_slice_free:
* @type: the type of the block to free, typically a structure name
* @mem: a pointer to the block to free
*
* A convenience macro to free a block of memory that has
* been allocated from the slice allocator.
*
* It calls mg_slice_free1() using `sizeof (type)`
* as the block size.
* Note that the exact release behaviour can be changed with the
* [`G_DEBUG=gc-friendly`][G_DEBUG] environment variable, also see
* [`G_SLICE`][G_SLICE] for related debugging options.
*
* If @mem is %NULL, this macro does nothing.
*
* Since: 3.4.0
*/
#define mg_slice_free(type, mem) \
do { \
if (1) mg_slice_free1 (sizeof (type), (mem)); \
else (void) ((type*) 0 == (mem)); \
} while(0);
/**
* mg_slice_free_chain:
* @type: the type of the @mem_chain blocks
* @mem_chain: a pointer to the first block of the chain
* @next: the field name of the next pointer in @type
*
* Frees a linked list of memory blocks of structure type @type.
* The memory blocks must be equal-sized, allocated via
* mg_slice_alloc() or mg_slice_alloc0() and linked together by
* a @next pointer (similar to #GSList). The name of the
* @next field in @type is passed as third argument.
* Note that the exact release behaviour can be changed with the
* [`G_DEBUG=gc-friendly`][G_DEBUG] environment variable, also see
* [`G_SLICE`][G_SLICE] for related debugging options.
*
* If @mem_chain is %NULL, this function does nothing.
*
* Since: 3.4.0
*/
#define mg_slice_free_chain(type, mem_chain, next) \
do { \
if (1) mg_slice_free_chain_with_offset (sizeof (type), \
(mem_chain), G_STRUCT_OFFSET (type, next)); \
else (void) ((type*) 0 == (mem_chain)); \
} while(0);
#ifdef _MGDEVEL_MODE
MG_EXPORT void mg_slice_debug_tree_statistics(void);
#endif
/** @} end of slices_allocator_fns */
/** @} end of global_fns */
/** @} end of fns */
+3
View File
@@ -74,6 +74,9 @@ void __mg_os_time_delay (int ms);
extern GHANDLE hMgEtc;
BOOL mg_InitSliceAllocator(void);
void mg_TerminateSliceAllocator(void);
BOOL mg_InitMgEtc (void);
void mg_TerminateMgEtc (void);
+23 -23
View File
@@ -1,39 +1,39 @@
/*
* This file is part of MiniGUI, a mature cross-platform windowing
* This file is part of MiniGUI, a mature cross-platform windowing
* and Graphics User Interface (GUI) support system for embedded systems
* and smart IoT devices.
*
*
* Copyright (C) 2002~2018, Beijing FMSoft Technologies Co., Ltd.
* Copyright (C) 1998~2002, WEI Yongming
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*
* Or,
*
*
* As this program is a library, any link to this program must follow
* GNU General Public License version 3 (GPLv3). If you cannot accept
* GPLv3, you need to be licensed from FMSoft.
*
*
* If you have got a commercial license of this program, please use it
* under the terms and conditions of the commercial license.
*
*
* For more information about the commercial license, please refer to
* <http://www.minigui.com/en/about/licensing-policy/>.
*/
/*
/*
** fixstr.c: the Fixed String module for MiniGUI.
**
**
** Current maintainer: Wei Yongming.
*/
@@ -64,7 +64,7 @@ BOOL mg_InitFixStr (void)
{
int i, j, offset;
BYTE* bitmap;
// allocate memory.
if (!(FixStrHeap.heap [0] = malloc (MAX_LEN_FIXSTR * 8 * NR_HEAP))) return FALSE;
@@ -80,12 +80,12 @@ BOOL mg_InitFixStr (void)
bitmap[j] |= 0xFF;
bitmap += 1<<i;
FixStrHeap.offset[i] = offset;
offset += 1<<i;
}
#ifdef _MGRM_THREADS
pthread_mutex_init (&FixStrHeap.lock, NULL);
#endif
@@ -111,13 +111,13 @@ char* GUIAPI FixStrAlloc (int len)
if (len < 0)
return NULL;
if (len == 0)
return zero_string;
if (len >= MAX_LEN_FIXSTR)
return (char*)malloc (len + 1);
// determine which heap will use.
i = 0;
while (ulen) {
@@ -134,7 +134,7 @@ char* GUIAPI FixStrAlloc (int len)
// if 2K > len >= 1K, then i = 11;
if (i == 1) i = 2;
bufflen = 1 << i;
i = NR_HEAP + 1 - i;
// i is the heap index;
// if i == 7; then bufflen = 4
@@ -149,7 +149,7 @@ char* GUIAPI FixStrAlloc (int len)
heap = FixStrHeap.heap[i];
bitmap = FixStrHeap.bitmap + FixStrHeap.offset[i];
btlen = 1 << i;
for (i = 0; i < btlen; i++) {
for(j = 0; j < 8; j++) {
if (*bitmap & (0x80 >> j)) {
@@ -165,7 +165,7 @@ char* GUIAPI FixStrAlloc (int len)
heap += bufflen;
}
bitmap++;
}
@@ -182,10 +182,10 @@ void GUIAPI FreeFixStr (char* str)
int i;
int bufflen;
int stroff;
if (str [0] == '\0')
return;
if (str >= FixStrHeap.heap [NR_HEAP] || str < FixStrHeap.heap [0]) {
free (str);
return;
+17 -2
View File
@@ -104,6 +104,12 @@ int InitGUI (int argc, const char* agr[])
tcgetattr (0, &savedtermio);
#endif
step++;
if (!mg_InitSliceAllocator ()) {
fprintf (stderr, "KERNEL>InitGUI: failed to initialize slice allocator!\n");
return step;
}
if (!mg_InitFixStr ()) {
err_message (step, "Can not initialize Fixed String heap!\n");
return step;
@@ -158,6 +164,7 @@ void TerminateGUI (int rcByGUI)
{
mg_TerminateMisc ();
mg_TerminateFixStr ();
mg_TerminateSliceAllocator();
}
#warning ExitGUISafely?
@@ -321,6 +328,12 @@ int InitGUI (int argc, const char* agr[])
__mg_def_proc[1] = PreDefDialogProc;
__mg_def_proc[2] = PreDefControlProc;
step++;
if (!mg_InitSliceAllocator ()) {
fprintf (stderr, "KERNEL>InitGUI: failed to initialize slice allocator!\n");
return step;
}
if (!mg_InitFixStr ()) {
err_message (step, "Can not initialize Fixed String heap!\n");
return step;
@@ -510,8 +523,6 @@ void TerminateGUI (int rcByGUI)
#ifdef _MGHAVE_CURSOR
mg_TerminateCursor ();
#endif
mg_TerminateMisc ();
mg_TerminateFixStr ();
#ifdef _MGRM_PROCESSES
if (mgIsServer)
@@ -535,6 +546,10 @@ void TerminateGUI (int rcByGUI)
client_ClientCleanup ();
}
#endif
mg_TerminateMisc ();
mg_TerminateFixStr ();
mg_TerminateSliceAllocator();
}
#endif /* ifdef _MG_MINIMALGDI */
+9 -1
View File
@@ -376,12 +376,18 @@ int GUIAPI InitGUI (int args, const char *agr[])
__mg_def_proc[1] = PreDefDialogProc;
__mg_def_proc[2] = PreDefControlProc;
step++;
if (!mg_InitSliceAllocator ()) {
fprintf (stderr, "KERNEL>InitGUI: failed to initialize slice allocator!\n");
return step;
}
step++;
if (!mg_InitFixStr ()) {
fprintf (stderr, "KERNEL>InitGUI: Init Fixed String module failure!\n");
return step;
}
step++;
/* Init miscelleous*/
if (!mg_InitMisc ()) {
@@ -586,6 +592,8 @@ void GUIAPI TerminateGUI (int not_used)
mg_miFreeArcCache ();
#endif
mg_TerminateSliceAllocator();
/*
* Restore original termio
*tcsetattr (0, TCSAFLUSH, &savedtermio);
+4 -4
View File
@@ -2,7 +2,7 @@ AM_CPPFLAGS = -I$(abs_top_srcdir)/include -I$(abs_top_srcdir)/src/include -I$(ab
noinst_LTLIBRARIES = liblibc.la
SRC_FILES=malloc.c \
SRC_FILES=malloc.c mgslice.c \
defdev.c stdioinlines.c \
fnprintf.c fprintf.c printf.c vfnprintf.c \
snprintf.c sprintf.c vsnprintf.c vfscanf.c \
@@ -12,12 +12,12 @@ SRC_FILES=malloc.c \
threadx_pprivate.c threadx_pthread.c threadx_mutex.c threadx_sem.c \
nucleus_pthread.c nucleus_mutex.c nucleus_sem.c \
vxworks_pthread.c vxworks_mutex.c vxworks_sem.c \
ose_sem.c \
ose_sem.c \
psos_pprivate.c psos_pthread.c psos_mutex.c psos_sem.c
HDR_FILES=ucos2_pprivate.h sysvipc_private.h ieeefp.h \
threadx_pprivate.h nucleus_pprivate.h vxworks_pprivate.h \
psos_pprivate.h
threadx_pprivate.h nucleus_pprivate.h vxworks_pprivate.h \
psos_pprivate.h
EXTRA_DIST=makefile.ng makefile.msvc vxworks_sem.c
+1432
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -235,7 +235,7 @@ BOOL mg_InitMgEtc (void)
"or bad files!\n");
return FALSE;
}
if (hMgEtc)
return TRUE;