mirror of
https://github.com/adtools/clib2.git
synced 2025-12-08 14:59:05 +00:00
Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1b2c798467 | |||
| 053a61fc4b | |||
| 4c54ee3f2d | |||
| f491e38b38 | |||
| 734ce4c1a9 | |||
| ce345df9da | |||
| 5e0fa78d61 | |||
| bc3e19abe5 | |||
| 29e02775fb | |||
| 5cb27db203 | |||
| 4fc1b13945 | |||
| 8beaabac4f | |||
| 271572ed56 | |||
| e0feef8932 | |||
| 07259ed7eb | |||
| 3203fcf96a | |||
| bfba44bf83 | |||
| 35434bdedc | |||
| 17ba18c731 | |||
| 78a8c7655e | |||
| 184a127860 | |||
| 5617c0eacf | |||
| ac710b333e | |||
| d2acae7cd7 | |||
| f8cf752e6a | |||
| 0c5b88d2d3 | |||
| 1ea8953bd3 | |||
| ff908f8a02 | |||
| 525e193113 | |||
| 2df2393b81 | |||
| ecd40943e2 | |||
| 7e201fea06 | |||
| 799ee705e8 | |||
| 3425e33cf9 | |||
| ef66e530b7 |
14
.codeclimate.yml
Normal file
14
.codeclimate.yml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
engines:
|
||||||
|
duplication:
|
||||||
|
enabled: false
|
||||||
|
fixme:
|
||||||
|
enabled: true
|
||||||
|
markdownlint:
|
||||||
|
enabled: true
|
||||||
|
ratings:
|
||||||
|
paths:
|
||||||
|
- "**.c"
|
||||||
|
- "**.h"
|
||||||
|
- "**.l"
|
||||||
|
- "**.md"
|
||||||
36
.travis.yml
Normal file
36
.travis.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
sudo: required
|
||||||
|
dist: trusty
|
||||||
|
|
||||||
|
language: c
|
||||||
|
|
||||||
|
# download and install our required cross compilers
|
||||||
|
install:
|
||||||
|
# Make sure we can install i386 packages as some adtools binaries
|
||||||
|
# requires i386 libraries being installed to work in the 64bit env
|
||||||
|
# of Travis
|
||||||
|
- sudo dpkg --add-architecture i386
|
||||||
|
- sudo apt-get -qq update || true
|
||||||
|
- sudo apt-get -qq install libc6:i386
|
||||||
|
# Install all adtools related stuff we need
|
||||||
|
- curl -L https://dl.bintray.com/jens-maus/adtools/adtools-utils.tar.bz2 | sudo tar xj -C /
|
||||||
|
- if [[ ${BUILD} =~ os3|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-m68k-amigaos.tar.bz2 | sudo tar xj -C / ; fi
|
||||||
|
- if [[ ${BUILD} =~ os4|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-ppc-amigaos.tar.bz2 | sudo tar xj -C / ; fi
|
||||||
|
- if [[ ${BUILD} =~ mos|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-ppc-morphos.tar.bz2 | sudo tar xj -C / ; fi
|
||||||
|
- if [[ ${BUILD} =~ aros-ppc|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-ppc-aros.tar.bz2 | sudo tar xj -C / ; fi
|
||||||
|
- if [[ ${BUILD} =~ aros-i386|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-i386-aros.tar.bz2 | sudo tar xj -C / ; fi
|
||||||
|
- if [[ ${BUILD} =~ aros-x86_64|release ]]; then curl -L https://dl.bintray.com/jens-maus/adtools/adtools-x86_64-aros.tar.bz2 | sudo tar xj -C / ; fi
|
||||||
|
- if [[ ${BUILD} =~ mingw32|release ]]; then sudo apt-get -qq install binutils-mingw-w64-i686 gcc-mingw-w64-i686 ; fi
|
||||||
|
|
||||||
|
# set the PATH variable to the directories the cross compilers are installed.
|
||||||
|
before_script:
|
||||||
|
- export PATH=/usr/local/amiga/bin:/opt/m68k-amigaos/bin:/opt/ppc-amigaos/bin:/opt/ppc-morphos/bin:${PATH}
|
||||||
|
|
||||||
|
# specify a list of variables to test (here we test the build for our supported
|
||||||
|
# list of operating systems).
|
||||||
|
env:
|
||||||
|
- BUILD="-f GNUmakefile.68k OS=os3"
|
||||||
|
- BUILD="-f GNUmakefile.os4 OS=os4"
|
||||||
|
|
||||||
|
# the build command to execute for each test
|
||||||
|
script:
|
||||||
|
- make -C library -j1 ${BUILD}
|
||||||
29
LICENSE
Normal file
29
LICENSE
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2016, Olaf Barthel
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
@ -1,4 +1,9 @@
|
|||||||
# An ISO 'C' (1994) compliant runtime library for the Amiga
|
# clib2 – An ISO 'C' (1994) compliant runtime library for AmigaOS
|
||||||
|
|
||||||
|
[](https://travis-ci.org/adtools/clib2)
|
||||||
|
[](https://codeclimate.com/github/adtools/clib2)
|
||||||
|
[](https://opensource.org/licenses/BSD-3-Clause)
|
||||||
|
[](https://github.com/adtools/clib2/issues)
|
||||||
|
|
||||||
## What is this?
|
## What is this?
|
||||||
|
|
||||||
|
|||||||
@ -327,11 +327,15 @@ C_LIB = \
|
|||||||
stdlib_exit.o \
|
stdlib_exit.o \
|
||||||
stdlib_free.o \
|
stdlib_free.o \
|
||||||
stdlib_free_unused_slabs.o \
|
stdlib_free_unused_slabs.o \
|
||||||
|
stdlib_decay_unused_slabs.o \
|
||||||
stdlib_getdefstacksize.o \
|
stdlib_getdefstacksize.o \
|
||||||
stdlib_getenv.o \
|
stdlib_getenv.o \
|
||||||
stdlib_getmemstats.o \
|
stdlib_getmemstats.o \
|
||||||
stdlib_getsp.o \
|
stdlib_getsp.o \
|
||||||
stdlib_get_errno.o \
|
stdlib_get_errno.o \
|
||||||
|
stdlib_get_slab_usage.o \
|
||||||
|
stdlib_get_slab_allocations.o \
|
||||||
|
stdlib_get_slab_stats.o \
|
||||||
stdlib_isresident.o \
|
stdlib_isresident.o \
|
||||||
stdlib_labs.o \
|
stdlib_labs.o \
|
||||||
stdlib_llabs.o \
|
stdlib_llabs.o \
|
||||||
@ -371,6 +375,7 @@ C_LIB = \
|
|||||||
stdlib_showerror.o \
|
stdlib_showerror.o \
|
||||||
stdlib_slab.o \
|
stdlib_slab.o \
|
||||||
stdlib_slab_max_size.o \
|
stdlib_slab_max_size.o \
|
||||||
|
stdlib_slab_purge_threshold.o \
|
||||||
stdlib_srand.o \
|
stdlib_srand.o \
|
||||||
stdlib_stacksize.o \
|
stdlib_stacksize.o \
|
||||||
stdlib_stack_usage.o \
|
stdlib_stack_usage.o \
|
||||||
@ -1122,21 +1127,31 @@ $(LIBC_OBJS)/stdlib_getdefstacksize.o : stdlib_getdefstacksize.c stdlib_gcc_help
|
|||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_shell_escape.o : stdlib_shell_escape.c stdlib_gcc_help.h
|
$(LIBC_OBJS)/stdlib_shell_escape.o : stdlib_shell_escape.c stdlib_gcc_help.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_alloca.o : stdlib_alloca.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_alloca.o : stdlib_alloca.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_calloc.o : stdlib_calloc.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_calloc.o : stdlib_calloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_free.o : stdlib_free.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_free.o : stdlib_free.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_malloc.o : stdlib_malloc.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_malloc.o : stdlib_malloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_slab.o : stdlib_slab.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_slab.o : stdlib_slab.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_slab_purge_threshold.o : stdlib_slab_purge_threshold.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_get_slab_stats.o : stdlib_get_slab_stats.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
$(LIBC_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h
|
$(LIBC_OBJS)/stdlib_free_unused_slabs.o : stdlib_free_unused_slabs.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBC_OBJS)/stdlib_decay_unused_slabs.o : stdlib_decay_unused_slabs.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBC_OBJS)/stdlib_get_slab_usage.o : stdlib_get_slab_usage.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBC_OBJS)/stdlib_get_slab_allocations.o : stdlib_get_slab_allocations.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBC_OBJS)/stdlib_realloc.o : stdlib_realloc.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
|
$(LIBC_OBJS)/stdlib_red_black.o : stdlib_red_black.c stdlib_memory.h include/stdlib.h
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
|
|||||||
@ -54,7 +54,8 @@ LOG_COMMAND := 2>&1 | tee -a compiler.log
|
|||||||
|
|
||||||
WARNINGS := \
|
WARNINGS := \
|
||||||
-Wall -W -Wpointer-arith -Wsign-compare -Wmissing-prototypes \
|
-Wall -W -Wpointer-arith -Wsign-compare -Wmissing-prototypes \
|
||||||
-Wundef -Wbad-function-cast -Wmissing-declarations -Wunused -Wwrite-strings
|
-Wundef -Wbad-function-cast -Wmissing-declarations -Wunused -Wwrite-strings \
|
||||||
|
-Wno-deprecated-declarations \
|
||||||
|
|
||||||
# -Wconversion -Wshadow
|
# -Wconversion -Wshadow
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 207
|
#define REVISION 214
|
||||||
#define DATE "18.11.2016"
|
#define DATE "27.4.2017"
|
||||||
#define VERS "amiga.lib 1.207"
|
#define VERS "amiga.lib 1.214"
|
||||||
#define VSTRING "amiga.lib 1.207 (18.11.2016)\r\n"
|
#define VSTRING "amiga.lib 1.214 (27.4.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: amiga.lib 1.207 (18.11.2016)"
|
#define VERSTAG "\0$VER: amiga.lib 1.214 (27.4.2017)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
207
|
214
|
||||||
|
|||||||
@ -79,6 +79,8 @@ DoTimer(struct timeval *tv,LONG unit,LONG command)
|
|||||||
struct MsgPort * mp;
|
struct MsgPort * mp;
|
||||||
LONG error;
|
LONG error;
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
|
||||||
assert( tv != NULL );
|
assert( tv != NULL );
|
||||||
|
|
||||||
#if defined(__amigaos4__)
|
#if defined(__amigaos4__)
|
||||||
@ -129,14 +131,10 @@ DoTimer(struct timeval *tv,LONG unit,LONG command)
|
|||||||
tr->tr_time.tv_secs = tv->tv_secs;
|
tr->tr_time.tv_secs = tv->tv_secs;
|
||||||
tr->tr_time.tv_micro = tv->tv_micro;
|
tr->tr_time.tv_micro = tv->tv_micro;
|
||||||
|
|
||||||
PROFILE_OFF();
|
|
||||||
|
|
||||||
SetSignal(0,(1UL << mp->mp_SigBit));
|
SetSignal(0,(1UL << mp->mp_SigBit));
|
||||||
|
|
||||||
error = DoIO((struct IORequest *)tr);
|
error = DoIO((struct IORequest *)tr);
|
||||||
|
|
||||||
PROFILE_ON();
|
|
||||||
|
|
||||||
tv->tv_secs = tr->tr_time.tv_secs;
|
tv->tv_secs = tr->tr_time.tv_secs;
|
||||||
tv->tv_micro = tr->tr_time.tv_micro;
|
tv->tv_micro = tr->tr_time.tv_micro;
|
||||||
|
|
||||||
@ -161,5 +159,7 @@ DoTimer(struct timeval *tv,LONG unit,LONG command)
|
|||||||
}
|
}
|
||||||
#endif /* __amigaos4__ */
|
#endif /* __amigaos4__ */
|
||||||
|
|
||||||
|
PROFILE_ON();
|
||||||
|
|
||||||
return(error);
|
return(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -262,9 +262,8 @@ STATIC VOID
|
|||||||
_SetValue(struct Environment * env,struct NexxStr * value,struct Node * symbol_table_node)
|
_SetValue(struct Environment * env,struct NexxStr * value,struct Node * symbol_table_node)
|
||||||
{
|
{
|
||||||
STATIC CONST UWORD code[] = { 0x4EAE,0xFFAC,0x4E75 }; /* jsr -84(a6) ; rts */
|
STATIC CONST UWORD code[] = { 0x4EAE,0xFFAC,0x4E75 }; /* jsr -84(a6) ; rts */
|
||||||
struct Node * result;
|
|
||||||
|
|
||||||
result = (struct Node *)EmulateTags(code,
|
EmulateTags(code,
|
||||||
ET_RegisterA0,env,
|
ET_RegisterA0,env,
|
||||||
ET_RegisterA1,value,
|
ET_RegisterA1,value,
|
||||||
ET_RegisterD0,symbol_table_node,
|
ET_RegisterD0,symbol_table_node,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 207
|
#define REVISION 214
|
||||||
#define DATE "18.11.2016"
|
#define DATE "27.4.2017"
|
||||||
#define VERS "c.lib 1.207"
|
#define VERS "c.lib 1.214"
|
||||||
#define VSTRING "c.lib 1.207 (18.11.2016)\r\n"
|
#define VSTRING "c.lib 1.214 (27.4.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: c.lib 1.207 (18.11.2016)"
|
#define VERSTAG "\0$VER: c.lib 1.214 (27.4.2017)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
207
|
214
|
||||||
|
|||||||
127
library/changes
127
library/changes
@ -1,3 +1,130 @@
|
|||||||
|
c.lib 1.214 (27.4.2017)
|
||||||
|
|
||||||
|
- Added integer overflow test to calloc().
|
||||||
|
|
||||||
|
- Tiny change in getopt_long() so that the value pointed to by longindex
|
||||||
|
is always initialized to an invalid index position (that being -1),
|
||||||
|
instead of 0. The value of 0 can break some shell commands, most notably
|
||||||
|
GNU wget.
|
||||||
|
|
||||||
|
|
||||||
|
c.lib 1.213 (4.12.2016)
|
||||||
|
|
||||||
|
- Added the __decay_unused_slabs() function which brings all currently
|
||||||
|
empty slabs which are still protected from reuse closer to getting
|
||||||
|
reused or released.
|
||||||
|
|
||||||
|
- The slab-test program now exercises the memory allocation functions
|
||||||
|
to a greater degree. Memory is allocated in random chunk sizes,
|
||||||
|
the allocations are resized (to other random chunk sizes),
|
||||||
|
33% of all allocations are randomly freed, empty slabs readied for
|
||||||
|
reuse then discarded. The output in JSON format now shows a bit
|
||||||
|
more information as to what is being done.
|
||||||
|
|
||||||
|
- Rewrote __get_slab_stats() to use setjmp() and longjmp() in the
|
||||||
|
print() callback invocation.
|
||||||
|
|
||||||
|
- __get_slab_stats() now reports how many times a slab was reused
|
||||||
|
after having stuck around in the "empty slab" list.
|
||||||
|
|
||||||
|
- Changing the slab size through an environment variable is now
|
||||||
|
a feature of the debug build.
|
||||||
|
|
||||||
|
- Small changes to allow the library to be built with SAS/C again.
|
||||||
|
This includes adding code to disable/re-enable profiling,
|
||||||
|
fixing "stdlib_profile.h" and updating the smakefiles.
|
||||||
|
|
||||||
|
- Still not sure what it does, but _CXV45 now sits along with _CX25
|
||||||
|
and _CX35 in "sas_cxv.asm". "sas_cxv54.asm" is not needed any
|
||||||
|
more.
|
||||||
|
|
||||||
|
- Found the last use of MEMF_PRIVATE which should have been compiled
|
||||||
|
only for the OS4 version.
|
||||||
|
|
||||||
|
|
||||||
|
c.lib 1.212 (27.11.2016)
|
||||||
|
|
||||||
|
- Unused slabs which get recycled are no longer reinitialized from
|
||||||
|
scratch if their chunk size matches what the allocator needed.
|
||||||
|
If the chunk size matches, the list of available chunks is
|
||||||
|
left unchanged, and just the various counters are reset.
|
||||||
|
|
||||||
|
- Added __get_slab_stats() function.
|
||||||
|
|
||||||
|
- Added support for global __slab_purge_threshold tuning variable.
|
||||||
|
|
||||||
|
|
||||||
|
c.lib 1.211 (23.11.2016)
|
||||||
|
|
||||||
|
- Added more consistency checking to the slab allocator, which is
|
||||||
|
built if DEBUG is defined in "stdlib_slab.c".
|
||||||
|
|
||||||
|
- Memory allocations are no longer guaranteed to be aligned to
|
||||||
|
64 bit word boundaries. In fact, this has not even worked
|
||||||
|
reliably in the past 10 years.
|
||||||
|
|
||||||
|
- Memory allocation request sizes are now rounded to multiples of
|
||||||
|
32 bit words (the size of an address pointer) instead to the
|
||||||
|
size of a 64 bit word.
|
||||||
|
|
||||||
|
- Reduced the memory footprint of the memory allocation management
|
||||||
|
data structures by reusing the most significant bit of the
|
||||||
|
memory allocation size. This allows many more allocations to fit
|
||||||
|
into the 32 byte chunk slabs, but limits the maximum memory
|
||||||
|
allocation size to a little less than 2 GBytes.
|
||||||
|
|
||||||
|
- Added integer overflow checks to the memory management code.
|
||||||
|
|
||||||
|
- Reduced the memory management overhead further. This cuts an
|
||||||
|
additional 8 bytes per allocation, unless neither the slab
|
||||||
|
allocator nor memory pools are available. With this reduction
|
||||||
|
the slab allocator is able to use 16 byte chunks, which cover
|
||||||
|
memory allocation requests of 1..8 bytes.
|
||||||
|
|
||||||
|
- Fixed a bug caused by returning an allocation back to a slab
|
||||||
|
which passed the wrong pointer.
|
||||||
|
|
||||||
|
|
||||||
|
c.lib 1.210 (22.11.2016)
|
||||||
|
|
||||||
|
- Added __get_slab_allocations() function which will report information
|
||||||
|
about each memory allocation made by the slab allocator which does
|
||||||
|
not come from a slab.
|
||||||
|
|
||||||
|
- If the first slab in the list of slabs which share the same chunk
|
||||||
|
size has no more room, it means that all other slabs following
|
||||||
|
it have no room either. This speeds up the test to find a slab with
|
||||||
|
free space, which can now abort and directly proceed to allocate
|
||||||
|
memory for a new slab.
|
||||||
|
|
||||||
|
- If an empty slab's decay count hits zero, it is moved to the front
|
||||||
|
of the empty slab list to be reclaimed more quickly.
|
||||||
|
|
||||||
|
- Allocations made from the slab now carry a pointer back to the
|
||||||
|
slab which they are a part of. This speeds up deallocation but
|
||||||
|
has the downside of making the smallest usable slab chunk size
|
||||||
|
64 bytes, which is double what used to be the minimum before.
|
||||||
|
|
||||||
|
|
||||||
|
c.lib 1.209 (21.11.2016)
|
||||||
|
|
||||||
|
- The maximum slab size is now 2^17 bytes (= 131072). If you request
|
||||||
|
a slab size larger than this, you will get slab sizes of 131072
|
||||||
|
bytes instead.
|
||||||
|
|
||||||
|
- Enabling the memory management debugging code no longer produces
|
||||||
|
compiler errors.
|
||||||
|
|
||||||
|
|
||||||
|
c.lib 1.208 (19.11.2016)
|
||||||
|
|
||||||
|
- Updated <stdlib.h> with new functions and data structures for
|
||||||
|
use with the slab allocator.
|
||||||
|
|
||||||
|
- Added __get_slab_usage() function which can be used to query
|
||||||
|
the slab allocator memory usage at runtime.
|
||||||
|
|
||||||
|
|
||||||
c.lib 1.207 (18.11.2016)
|
c.lib 1.207 (18.11.2016)
|
||||||
|
|
||||||
- Added a slab allocator which replaces the use of memory pools or the
|
- Added a slab allocator which replaces the use of memory pools or the
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 207
|
#define REVISION 214
|
||||||
#define DATE "18.11.2016"
|
#define DATE "27.4.2017"
|
||||||
#define VERS "debug.lib 1.207"
|
#define VERS "debug.lib 1.214"
|
||||||
#define VSTRING "debug.lib 1.207 (18.11.2016)\r\n"
|
#define VSTRING "debug.lib 1.214 (27.4.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: debug.lib 1.207 (18.11.2016)"
|
#define VERSTAG "\0$VER: debug.lib 1.214 (27.4.2017)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
207
|
214
|
||||||
|
|||||||
@ -296,7 +296,7 @@ static int getopt_long_internal(int argc, const char **argv, const char *optstri
|
|||||||
optp = strchr(optstring, c);
|
optp = strchr(optstring, c);
|
||||||
|
|
||||||
/* We never find a long option in a compound option */
|
/* We never find a long option in a compound option */
|
||||||
*longindex = 0;
|
*longindex = -1;
|
||||||
|
|
||||||
/* Check if it's legal */
|
/* Check if it's legal */
|
||||||
if (c == ':' || (optp == NULL))
|
if (c == ':' || (optp == NULL))
|
||||||
|
|||||||
@ -161,6 +161,227 @@ extern int rand_r(unsigned int * seed);
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You can switch the built-in memory allocator, which is a thin wrapper
|
||||||
|
* around the AmigaOS built-in memory management system, to use a slab
|
||||||
|
* allocator. For this to work, you need to declare a global variable
|
||||||
|
* and set it to the size of the slabs to be used. This variable must
|
||||||
|
* be initialized at load time when the clib2 startup code runs:
|
||||||
|
*
|
||||||
|
* unsigned long __slab_max_size = 4096;
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern unsigned long __slab_max_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The slab allocator will periodically free all currently unused memory.
|
||||||
|
* You can control how much memory should be released, instead of
|
||||||
|
* releasing everything.
|
||||||
|
*
|
||||||
|
* This would make the slab allocator release only up to 512 KBytes of
|
||||||
|
* unused memory at a time:
|
||||||
|
*
|
||||||
|
* unsigned long __slab_purge_threshold = 512 * 1024;
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern unsigned long __slab_purge_threshold;
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If you are using the slab allocator and need to quickly release the
|
||||||
|
* memory of all slabs which are currently unused, you can call the
|
||||||
|
* following function to do so.
|
||||||
|
*
|
||||||
|
* Please note that this function works within the context of the memory
|
||||||
|
* allocation system and is not safe to call from interrupt code. It may
|
||||||
|
* break a Forbid() or Disable() condition.
|
||||||
|
*/
|
||||||
|
extern void __free_unused_slabs(void);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You can accelerate the reuse of currently unused slabs by calling
|
||||||
|
* the __decay_unused_slabs() function. Each call decrements the decay
|
||||||
|
* counter until it reaches 0, at which point an unused slab can be
|
||||||
|
* reused instead of allocating a new slab. Also, at 0 unused slabs
|
||||||
|
* will be freed by the allocator.
|
||||||
|
*
|
||||||
|
* Please note that this function works within the context of the memory
|
||||||
|
* allocation system and is not safe to call from interrupt code. It may
|
||||||
|
* break a Forbid() or Disable() condition.
|
||||||
|
*/
|
||||||
|
extern void __decay_unused_slabs(void);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You can obtain runtime statistics about the slab allocator by
|
||||||
|
* invoking the __get_slab_usage() function which in turn invokes
|
||||||
|
* your callback function for each single slab currently in play.
|
||||||
|
*
|
||||||
|
* Your callback function must return 0 if it wants to be called again,
|
||||||
|
* for the next slab, or return -1 to stop. Note that your callback
|
||||||
|
* function may not be called if the slab allocator is currently
|
||||||
|
* not operational.
|
||||||
|
*
|
||||||
|
* Please note that this function works within the context of the memory
|
||||||
|
* allocation system and is not safe to call from interrupt code. It may
|
||||||
|
* break a Forbid() or Disable() condition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* This is what your callback function will see when it is invoked. */
|
||||||
|
struct __slab_usage_information
|
||||||
|
{
|
||||||
|
/* The size of all slabs, in bytes. */
|
||||||
|
size_t sui_slab_size;
|
||||||
|
|
||||||
|
/* Number of allocations which are not managed by slabs, but
|
||||||
|
* are handled separate.
|
||||||
|
*/
|
||||||
|
size_t sui_num_single_allocations;
|
||||||
|
|
||||||
|
/* Total number of bytes allocated for memory not managed
|
||||||
|
* by slabs. This includes the management overhead for
|
||||||
|
* each allocation.
|
||||||
|
*/
|
||||||
|
size_t sui_total_single_allocation_size;
|
||||||
|
|
||||||
|
/* Number of slabs currently in play. This can be 0. */
|
||||||
|
size_t sui_num_slabs;
|
||||||
|
|
||||||
|
/* Number of currently unused slabs which contain no data. */
|
||||||
|
size_t sui_num_empty_slabs;
|
||||||
|
|
||||||
|
/* Number of slabs in use which are completely filled with data. */
|
||||||
|
size_t sui_num_full_slabs;
|
||||||
|
|
||||||
|
/* Total number of bytes allocated for all slabs. */
|
||||||
|
size_t sui_total_slab_allocation_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following data is updated for each slab which
|
||||||
|
* your callback function sees.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Index number of the slab being reported (0 = no slabs are in use). */
|
||||||
|
int sui_slab_index;
|
||||||
|
|
||||||
|
/* How large are the memory chunks managed by this slab? */
|
||||||
|
size_t sui_chunk_size;
|
||||||
|
|
||||||
|
/* How many memory chunks fit into this slab? */
|
||||||
|
size_t sui_num_chunks;
|
||||||
|
|
||||||
|
/* How many memory chunks in this slab are being used? */
|
||||||
|
size_t sui_num_chunks_used;
|
||||||
|
|
||||||
|
/* How many time was this slab reused without reinitializing
|
||||||
|
* it all over again from scratch?
|
||||||
|
*/
|
||||||
|
size_t sui_num_reused;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
typedef int (*__slab_usage_callback)(const struct __slab_usage_information * sui);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void __get_slab_usage(__slab_usage_callback callback);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You can obtain runtime statistics about the memory allocations
|
||||||
|
* which the slab allocator did not fit into slabs. This works
|
||||||
|
* just like __get_slab_usage() in that the callback function
|
||||||
|
* you provide will be called for each single allocation that
|
||||||
|
* is not part of a slab.
|
||||||
|
*
|
||||||
|
* Your callback function must return 0 if it wants to be called again,
|
||||||
|
* for the next slab, or return -1 to stop. Note that your callback
|
||||||
|
* function may not be called if the slab allocator did not
|
||||||
|
* allocate memory outside of slabs.
|
||||||
|
*
|
||||||
|
* Please note that this function works within the context of the memory
|
||||||
|
* allocation system and is not safe to call from interrupt code. It may
|
||||||
|
* break a Forbid() or Disable() condition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This is what your callback function will see when it is invoked. */
|
||||||
|
struct __slab_allocation_information
|
||||||
|
{
|
||||||
|
/* Number of allocations which are not managed by slabs, but
|
||||||
|
* are handled separate.
|
||||||
|
*/
|
||||||
|
size_t sai_num_single_allocations;
|
||||||
|
|
||||||
|
/* Total number of bytes allocated for memory not managed
|
||||||
|
* by slabs. This includes the management overhead for
|
||||||
|
* each allocation.
|
||||||
|
*/
|
||||||
|
size_t sai_total_single_allocation_size;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following data is updated for each slab which
|
||||||
|
* your callback function sees.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Index number of the allocation being reported (0 = no allocations
|
||||||
|
* outside of slabs are in use).
|
||||||
|
*/
|
||||||
|
int sai_allocation_index;
|
||||||
|
|
||||||
|
/* Size of this allocation, as requested by the program which
|
||||||
|
* called malloc(), realloc() or alloca().
|
||||||
|
*/
|
||||||
|
size_t sai_allocation_size;
|
||||||
|
|
||||||
|
/* Total size of this allocation, including management data
|
||||||
|
* structure overhead.
|
||||||
|
*/
|
||||||
|
size_t sai_total_allocation_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
typedef int (*__slab_allocation_callback)(const struct __slab_allocation_information * sui);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void __get_slab_allocations(__slab_allocation_callback callback);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* You can obtain information about the memory managed by the slab allocator,
|
||||||
|
* as well as additional information about the slab allocator's performance
|
||||||
|
* in JSON format. This format can be used for more detailed analysis.
|
||||||
|
*
|
||||||
|
* You supply a function which will be called for each line of the JSON
|
||||||
|
* data produced. You can store this data in a file, or in the clipboard,
|
||||||
|
* for later use. Your function must return 0 if it wants to be called
|
||||||
|
* again, or return -1 if it wants to stop (e.g. if an error occured
|
||||||
|
* when writing the JSON data to disk). The same "user_data" pointer which
|
||||||
|
* you pass to __get_slab_stats() will be passed to your callback function.
|
||||||
|
*
|
||||||
|
* Please note that this function works within the context of the memory
|
||||||
|
* allocation system and is not safe to call from interrupt code. It may
|
||||||
|
* break a Forbid() or Disable() condition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef int (* __slab_status_callback)(void * user_data, const char * line, size_t line_length);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
extern void __get_slab_stats(void * user_data, __slab_status_callback callback);
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* You can request to use the alloca() variant that actually does allocate
|
* You can request to use the alloca() variant that actually does allocate
|
||||||
* memory from the system rather than the current stack frame, which will
|
* memory from the system rather than the current stack frame, which will
|
||||||
|
|||||||
@ -212,12 +212,16 @@ C_LIB := \
|
|||||||
stdlib_dosbase.o \
|
stdlib_dosbase.o \
|
||||||
stdlib_exit.o \
|
stdlib_exit.o \
|
||||||
stdlib_free.o \
|
stdlib_free.o \
|
||||||
|
stdlib_decay_unused_slabs.o \
|
||||||
stdlib_free_unused_slabs.o \
|
stdlib_free_unused_slabs.o \
|
||||||
stdlib_getdefstacksize.o \
|
stdlib_getdefstacksize.o \
|
||||||
stdlib_getenv.o \
|
stdlib_getenv.o \
|
||||||
stdlib_getmemstats.o \
|
stdlib_getmemstats.o \
|
||||||
stdlib_getsp.o \
|
stdlib_getsp.o \
|
||||||
stdlib_get_errno.o \
|
stdlib_get_errno.o \
|
||||||
|
stdlib_get_slab_usage.o \
|
||||||
|
stdlib_get_slab_allocations.o \
|
||||||
|
stdlib_get_slab_stats.o \
|
||||||
stdlib_isresident.o \
|
stdlib_isresident.o \
|
||||||
stdlib_labs.o \
|
stdlib_labs.o \
|
||||||
stdlib_llabs.o \
|
stdlib_llabs.o \
|
||||||
@ -258,6 +262,7 @@ C_LIB := \
|
|||||||
stdlib_showerror.o \
|
stdlib_showerror.o \
|
||||||
stdlib_slab.o \
|
stdlib_slab.o \
|
||||||
stdlib_slab_max_size.o \
|
stdlib_slab_max_size.o \
|
||||||
|
stdlib_slab_purge_threshold.o \
|
||||||
stdlib_srand.o \
|
stdlib_srand.o \
|
||||||
stdlib_stacksize.o \
|
stdlib_stacksize.o \
|
||||||
stdlib_stack_usage.o \
|
stdlib_stack_usage.o \
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 207
|
#define REVISION 214
|
||||||
#define DATE "18.11.2016"
|
#define DATE "27.4.2017"
|
||||||
#define VERS "m.lib 1.207"
|
#define VERS "m.lib 1.214"
|
||||||
#define VSTRING "m.lib 1.207 (18.11.2016)\r\n"
|
#define VSTRING "m.lib 1.214 (27.4.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: m.lib 1.207 (18.11.2016)"
|
#define VERSTAG "\0$VER: m.lib 1.214 (27.4.2017)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
207
|
214
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 207
|
#define REVISION 214
|
||||||
#define DATE "18.11.2016"
|
#define DATE "27.4.2017"
|
||||||
#define VERS "m881.lib 1.207"
|
#define VERS "m881.lib 1.214"
|
||||||
#define VSTRING "m881.lib 1.207 (18.11.2016)\r\n"
|
#define VSTRING "m881.lib 1.214 (27.4.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: m881.lib 1.207 (18.11.2016)"
|
#define VERSTAG "\0$VER: m881.lib 1.214 (27.4.2017)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
207
|
214
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 207
|
#define REVISION 214
|
||||||
#define DATE "18.11.2016"
|
#define DATE "27.4.2017"
|
||||||
#define VERS "net.lib 1.207"
|
#define VERS "net.lib 1.214"
|
||||||
#define VSTRING "net.lib 1.207 (18.11.2016)\r\n"
|
#define VSTRING "net.lib 1.214 (27.4.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: net.lib 1.207 (18.11.2016)"
|
#define VERSTAG "\0$VER: net.lib 1.214 (27.4.2017)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
207
|
214
|
||||||
|
|||||||
@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
xdef __CXV25
|
xdef __CXV25
|
||||||
xdef __CXV35
|
xdef __CXV35
|
||||||
|
xdef __CXV45
|
||||||
xdef __CXNRM5
|
xdef __CXNRM5
|
||||||
xdef __CXTAB5
|
xdef __CXTAB5
|
||||||
|
|
||||||
@ -74,6 +75,43 @@ L44: MOVE.W D0,D1
|
|||||||
MOVEM.L (SP)+,D2-D5/A1
|
MOVEM.L (SP)+,D2-D5/A1
|
||||||
RTS
|
RTS
|
||||||
|
|
||||||
|
__CXV45:
|
||||||
|
|
||||||
|
MOVE.L D0,D1
|
||||||
|
SWAP D1
|
||||||
|
AND.W #$7FFF,D1
|
||||||
|
CMP.W #$80,D1
|
||||||
|
BLT .1
|
||||||
|
CMP.W #$7F80,D1
|
||||||
|
BGE .3
|
||||||
|
ASR.L #3,D0
|
||||||
|
AND.L #$8FFFFFFF,D0
|
||||||
|
ADD.L #$38000000,D0
|
||||||
|
SWAP D1
|
||||||
|
AND.L #7,D1
|
||||||
|
ROR.L #3,D1
|
||||||
|
.2 RTS
|
||||||
|
|
||||||
|
.1 TST.L D1
|
||||||
|
BEQ.S .2
|
||||||
|
MOVEM.L D2-D5,-(SP)
|
||||||
|
SWAP D0
|
||||||
|
MOVE.W D0,D4
|
||||||
|
AND.W #$8000,D4
|
||||||
|
MOVE.W #$39D0,D5
|
||||||
|
MOVEQ #0,D0
|
||||||
|
SWAP D1
|
||||||
|
JSR __CXNRM5(PC)
|
||||||
|
MOVEM.L (SP)+,D2-D5
|
||||||
|
RTS
|
||||||
|
|
||||||
|
.3 ASR.L #3,D0
|
||||||
|
OR.L #$7FF00000,D0
|
||||||
|
SWAP D1
|
||||||
|
AND.L #7,D1
|
||||||
|
ROR.L #3,D1
|
||||||
|
RTS
|
||||||
|
|
||||||
__CXNRM5:
|
__CXNRM5:
|
||||||
|
|
||||||
CMP.L #$20,D0
|
CMP.L #$20,D0
|
||||||
|
|||||||
106
library/sas_cxv52.asm
Normal file
106
library/sas_cxv52.asm
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
*
|
||||||
|
* :ts=8
|
||||||
|
*
|
||||||
|
* Adapted from reassembled SAS/C runtime library code.
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
|
||||||
|
xdef __CXV52
|
||||||
|
xdef __CXV53
|
||||||
|
|
||||||
|
xref __CXFERR
|
||||||
|
|
||||||
|
section text,code
|
||||||
|
|
||||||
|
__CXV52:
|
||||||
|
|
||||||
|
MOVEM.L D2/D3,-(SP)
|
||||||
|
MOVEQ #-1,D3
|
||||||
|
MOVE.L D0,D2
|
||||||
|
BPL.W lab04A
|
||||||
|
CMPI.L #$BFF00000,D0
|
||||||
|
BCS.W lab07A
|
||||||
|
MOVEM.L D0/D1/A0/A1,-(SP)
|
||||||
|
PEA (2).L
|
||||||
|
JSR __CXFERR
|
||||||
|
ADDQ.W #4,SP
|
||||||
|
MOVEM.L (SP)+,D0/D1/A0/A1
|
||||||
|
BRA.W lab07A
|
||||||
|
|
||||||
|
__CXV53:
|
||||||
|
|
||||||
|
MOVEM.L D2/D3,-(SP)
|
||||||
|
MOVE.L #$7FFFFFFF,D3
|
||||||
|
MOVE.L D0,D2
|
||||||
|
BPL.W lab04A
|
||||||
|
ADDQ.L #1,D3
|
||||||
|
EOR.L D3,D0
|
||||||
|
lab04A: SWAP D0
|
||||||
|
MOVE.W D0,D2
|
||||||
|
ANDI.W #$7FF0,D2
|
||||||
|
EOR.W D2,D0
|
||||||
|
SUBI.W #$3FF0,D2
|
||||||
|
BLT.W lab07A
|
||||||
|
EORI.W #$10,D0
|
||||||
|
SWAP D0
|
||||||
|
ASR.W #4,D2
|
||||||
|
SUBI.W #$14,D2
|
||||||
|
BGT.W lab09A
|
||||||
|
NEG.W D2
|
||||||
|
LSR.L D2,D0
|
||||||
|
TST.L D2
|
||||||
|
BMI.W lab0B2
|
||||||
|
BRA.W lab0B4
|
||||||
|
|
||||||
|
lab07A: MOVEQ #0,D0
|
||||||
|
BRA.W lab0B4
|
||||||
|
|
||||||
|
lab080: MOVEM.L D0/D1/A0/A1,-(SP)
|
||||||
|
PEA (2).L
|
||||||
|
JSR __CXFERR
|
||||||
|
ADDQ.W #4,SP
|
||||||
|
MOVEM.L (SP)+,D0/D1/A0/A1
|
||||||
|
MOVE.L D3,D0
|
||||||
|
BRA.W lab0B4
|
||||||
|
|
||||||
|
lab09A: CMPI.W #11,D2
|
||||||
|
BGT.B lab080
|
||||||
|
EOR.L D1,D0
|
||||||
|
ROL.L D2,D0
|
||||||
|
LSL.L D2,D1
|
||||||
|
EOR.L D1,D0
|
||||||
|
CMP.L D3,D0
|
||||||
|
BHI.B lab080
|
||||||
|
TST.L D2
|
||||||
|
BPL.W lab0B4
|
||||||
|
lab0B2: NEG.L D0
|
||||||
|
lab0B4: MOVEM.L (SP)+,D2/D3
|
||||||
|
RTS
|
||||||
|
|
||||||
|
end
|
||||||
@ -1,6 +1,4 @@
|
|||||||
*
|
*
|
||||||
* $Id: sas_cxv54.asm,v 1.1.1.1 2004-07-26 16:31:04 obarthel Exp $
|
|
||||||
*
|
|
||||||
* :ts=8
|
* :ts=8
|
||||||
*
|
*
|
||||||
* Adapted from reassembled SAS/C runtime library code.
|
* Adapted from reassembled SAS/C runtime library code.
|
||||||
@ -38,7 +36,8 @@
|
|||||||
xdef __CXV54
|
xdef __CXV54
|
||||||
xref __CXFERR
|
xref __CXFERR
|
||||||
|
|
||||||
__CXV54
|
__CXV54:
|
||||||
|
|
||||||
MOVEM.L A0/A1,-(SP)
|
MOVEM.L A0/A1,-(SP)
|
||||||
MOVE.L D4,A0
|
MOVE.L D4,A0
|
||||||
SWAP D0
|
SWAP D0
|
||||||
@ -47,11 +46,11 @@ __CXV54
|
|||||||
EOR.W D4,D0
|
EOR.W D4,D0
|
||||||
SUB.W #$3800,D0
|
SUB.W #$3800,D0
|
||||||
CMP.W #$10,D0
|
CMP.W #$10,D0
|
||||||
BLT lbC000098
|
BLT lab098
|
||||||
CMP.W #$FEF,D0
|
CMP.W #$FEF,D0
|
||||||
BLT lbC000102
|
BLT lab102
|
||||||
CMP.W #$47F0,D0
|
CMP.W #$47F0,D0
|
||||||
BLT lbC000058
|
BLT lab058
|
||||||
SWAP D0
|
SWAP D0
|
||||||
LSL.L #3,D0
|
LSL.L #3,D0
|
||||||
ROL.L #3,D1
|
ROL.L #3,D1
|
||||||
@ -59,17 +58,16 @@ __CXV54
|
|||||||
EOR.L D1,D0
|
EOR.L D1,D0
|
||||||
SWAP D0
|
SWAP D0
|
||||||
OR.W #$7F80,D0
|
OR.W #$7F80,D0
|
||||||
BRA lbC000112
|
BRA lab112
|
||||||
|
|
||||||
lbC000058
|
lab058: CMP.W #$FF0,D0
|
||||||
CMP.W #$FF0,D0
|
BGE lab074
|
||||||
BGE lbC000074
|
|
||||||
CMP.L #$FFFF0FEF,D0
|
CMP.L #$FFFF0FEF,D0
|
||||||
BNE lbC000102
|
BNE lab102
|
||||||
CMP.L #$F0000000,D1
|
CMP.L #$F0000000,D1
|
||||||
BCS lbC000102
|
BCS lab102
|
||||||
lbC000074
|
|
||||||
MOVEM.L D0/D1/A0/A1,-(SP)
|
lab074: MOVEM.L D0/D1/A0/A1,-(SP)
|
||||||
PEA 2.L
|
PEA 2.L
|
||||||
JSR __CXFERR
|
JSR __CXFERR
|
||||||
ADDQ.W #4,SP
|
ADDQ.W #4,SP
|
||||||
@ -78,63 +76,56 @@ lbC000074
|
|||||||
EOR.W D4,D0
|
EOR.W D4,D0
|
||||||
SWAP D0
|
SWAP D0
|
||||||
MOVEQ #0,D1
|
MOVEQ #0,D1
|
||||||
BRA lbC000116
|
BRA lab116
|
||||||
|
|
||||||
lbC000098
|
lab098: CMP.W #$FE90,D0
|
||||||
CMP.W #$FE90,D0
|
BGE lab0C4
|
||||||
BGE lbC0000C4
|
|
||||||
ADD.W #$3800,D0
|
ADD.W #$3800,D0
|
||||||
OR.L D1,D0
|
OR.L D1,D0
|
||||||
BEQ lbC000112
|
BEQ lab112
|
||||||
MOVEM.L D0/D1/A0/A1,-(SP)
|
MOVEM.L D0/D1/A0/A1,-(SP)
|
||||||
PEA 1.L
|
PEA 1.L
|
||||||
JSR __CXFERR
|
JSR __CXFERR
|
||||||
ADDQ.W #4,SP
|
ADDQ.W #4,SP
|
||||||
MOVEM.L (SP)+,D0/D1/A0/A1
|
MOVEM.L (SP)+,D0/D1/A0/A1
|
||||||
MOVEQ #0,D0
|
MOVEQ #0,D0
|
||||||
BRA lbC000112
|
BRA lab112
|
||||||
|
|
||||||
lbC0000C4
|
lab0C4: MOVE.L D5,A1
|
||||||
MOVE.L D5,A1
|
|
||||||
MOVE.W D0,D5
|
MOVE.W D0,D5
|
||||||
AND.W #15,D0
|
AND.W #15,D0
|
||||||
EOR.W #$10,D0
|
EOR.W #$10,D0
|
||||||
SWAP D0
|
SWAP D0
|
||||||
ASR.W #4,D5
|
ASR.W #4,D5
|
||||||
ADDQ.W #2,D5
|
ADDQ.W #2,D5
|
||||||
BGE lbC0000E6
|
BGE lab0E6
|
||||||
NEG.W D5
|
NEG.W D5
|
||||||
LSR.L D5,D0
|
LSR.L D5,D0
|
||||||
MOVEQ #0,D5
|
MOVEQ #0,D5
|
||||||
ADDX.L D5,D0
|
ADDX.L D5,D0
|
||||||
BRA lbC0000F6
|
BRA lab0F6
|
||||||
|
|
||||||
lbC0000E6
|
lab0E6: CLR.W D1
|
||||||
CLR.W D1
|
|
||||||
LSL.L D5,D0
|
LSL.L D5,D0
|
||||||
ADDQ.W #1,D5
|
ADDQ.W #1,D5
|
||||||
ROXL.L D5,D1
|
ROXL.L D5,D1
|
||||||
AND.L #15,D1
|
AND.L #15,D1
|
||||||
ADDX.L D1,D0
|
ADDX.L D1,D0
|
||||||
lbC0000F6
|
lab0F6: MOVE.L A1,D5
|
||||||
MOVE.L A1,D5
|
|
||||||
SWAP D0
|
SWAP D0
|
||||||
EOR.W D4,D0
|
EOR.W D4,D0
|
||||||
SWAP D0
|
SWAP D0
|
||||||
BRA lbC000116
|
BRA lab116
|
||||||
|
|
||||||
lbC000102
|
lab102: SWAP D0
|
||||||
SWAP D0
|
|
||||||
LSL.L #3,D0
|
LSL.L #3,D0
|
||||||
ROXL.L #4,D1
|
ROXL.L #4,D1
|
||||||
AND.L #7,D1
|
AND.L #7,D1
|
||||||
ADDX.L D1,D0
|
ADDX.L D1,D0
|
||||||
SWAP D0
|
SWAP D0
|
||||||
lbC000112
|
lab112: EOR.W D4,D0
|
||||||
EOR.W D4,D0
|
|
||||||
SWAP D0
|
SWAP D0
|
||||||
lbC000116
|
lab116: MOVE.L A0,D4
|
||||||
MOVE.L A0,D4
|
|
||||||
MOVEM.L (SP)+,A0/A1
|
MOVEM.L (SP)+,A0/A1
|
||||||
RTS
|
RTS
|
||||||
|
|
||||||
|
|||||||
1621
library/smakefile
1621
library/smakefile
File diff suppressed because it is too large
Load Diff
75
library/stdlib_decay_unused_slabs.c
Normal file
75
library/stdlib_decay_unused_slabs.c
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_HEADERS_H
|
||||||
|
#include "stdlib_headers.h"
|
||||||
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_MEMORY_H
|
||||||
|
#include "stdlib_memory.h"
|
||||||
|
#endif /* _STDLIB_MEMORY_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Look at all currently unused slabs, decrementing the decay
|
||||||
|
* counter which prevents them from being reused.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
__decay_unused_slabs(void)
|
||||||
|
{
|
||||||
|
if(__slab_data.sd_InUse)
|
||||||
|
{
|
||||||
|
struct MinNode * free_node;
|
||||||
|
struct MinNode * free_node_next;
|
||||||
|
struct SlabNode * sn;
|
||||||
|
|
||||||
|
__memory_lock();
|
||||||
|
|
||||||
|
for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ;
|
||||||
|
free_node->mln_Succ != NULL ;
|
||||||
|
free_node = free_node_next)
|
||||||
|
{
|
||||||
|
free_node_next = (struct MinNode *)free_node->mln_Succ;
|
||||||
|
|
||||||
|
/* free_node points to SlabNode.sn_EmptyLink, which
|
||||||
|
* directly follows the SlabNode.sn_MinNode.
|
||||||
|
*/
|
||||||
|
sn = (struct SlabNode *)&free_node[-1];
|
||||||
|
|
||||||
|
if(sn->sn_EmptyDecay > 0)
|
||||||
|
sn->sn_EmptyDecay--;
|
||||||
|
}
|
||||||
|
|
||||||
|
__memory_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -31,6 +31,8 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*#define DEBUG*/
|
||||||
|
|
||||||
#ifndef _STDLIB_HEADERS_H
|
#ifndef _STDLIB_HEADERS_H
|
||||||
#include "stdlib_headers.h"
|
#include "stdlib_headers.h"
|
||||||
#endif /* _STDLIB_HEADERS_H */
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
@ -165,7 +167,7 @@ dump_memory(unsigned char * m,int size,int ignore)
|
|||||||
STATIC VOID
|
STATIC VOID
|
||||||
check_memory_node(struct MemoryNode * mn,const char * file,int line)
|
check_memory_node(struct MemoryNode * mn,const char * file,int line)
|
||||||
{
|
{
|
||||||
size_t size = mn->mn_Size;
|
ULONG size = GET_MN_SIZE(mn);
|
||||||
unsigned char * head = (unsigned char *)(mn + 1);
|
unsigned char * head = (unsigned char *)(mn + 1);
|
||||||
unsigned char * body = head + MALLOC_HEAD_SIZE;
|
unsigned char * body = head + MALLOC_HEAD_SIZE;
|
||||||
unsigned char * tail = body + size;
|
unsigned char * tail = body + size;
|
||||||
@ -227,10 +229,12 @@ check_memory_node(struct MemoryNode * mn,const char * file,int line)
|
|||||||
|
|
||||||
if(mn->mn_AlreadyFree)
|
if(mn->mn_AlreadyFree)
|
||||||
{
|
{
|
||||||
for(i = 0 ; i < size ; i++)
|
ULONG j;
|
||||||
|
|
||||||
|
for(j = 0 ; j < size ; j++)
|
||||||
{
|
{
|
||||||
if(body[i] != MALLOC_FREE_FILL)
|
if(body[j] != MALLOC_FREE_FILL)
|
||||||
max_body_damage = i+1;
|
max_body_damage = j+1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(max_body_damage > 0)
|
if(max_body_damage > 0)
|
||||||
@ -345,17 +349,17 @@ remove_and_free_memory_node(struct MemoryNode * mn)
|
|||||||
|
|
||||||
__memory_lock();
|
__memory_lock();
|
||||||
|
|
||||||
Remove((struct Node *)mn);
|
#if defined(__MEM_DEBUG)
|
||||||
|
|
||||||
#if defined(__USE_MEM_TREES) && defined(__MEM_DEBUG)
|
|
||||||
{
|
{
|
||||||
__red_black_tree_remove(&__memory_tree,mn);
|
Remove((struct Node *)mn);
|
||||||
}
|
|
||||||
#endif /* __USE_MEM_TREES && __MEM_DEBUG */
|
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#if defined(__USE_MEM_TREES)
|
||||||
{
|
{
|
||||||
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + mn->mn_Size + MALLOC_TAIL_SIZE;
|
__red_black_tree_remove(&__memory_tree,mn);
|
||||||
|
}
|
||||||
|
#endif /* __USE_MEM_TREES */
|
||||||
|
|
||||||
|
allocation_size = sizeof(*mn) + MALLOC_HEAD_SIZE + GET_MN_SIZE(mn) + MALLOC_TAIL_SIZE;
|
||||||
|
|
||||||
assert( allocation_size == mn->mn_AllocationSize );
|
assert( allocation_size == mn->mn_AllocationSize );
|
||||||
|
|
||||||
@ -363,26 +367,79 @@ remove_and_free_memory_node(struct MemoryNode * mn)
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
allocation_size = sizeof(*mn) + mn->mn_Size;
|
allocation_size = sizeof(*mn) + GET_MN_SIZE(mn);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
{
|
{
|
||||||
/* Are we using the slab allocator? */
|
/* Are we using the slab allocator? */
|
||||||
if (__slab_data.sd_InUse)
|
if(__slab_data.sd_InUse)
|
||||||
|
{
|
||||||
__slab_free(mn,allocation_size);
|
__slab_free(mn,allocation_size);
|
||||||
else if (__memory_pool != NULL)
|
}
|
||||||
FreePooled(__memory_pool,mn,allocation_size);
|
|
||||||
else
|
else
|
||||||
FreeMem(mn,allocation_size);
|
{
|
||||||
|
if(__memory_pool != NULL)
|
||||||
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreePooled(__memory_pool,mn,allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#if defined(__MEM_DEBUG)
|
||||||
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeMem(mn,allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
struct MinNode * mln = (struct MinNode *)mn;
|
||||||
|
|
||||||
|
mln--;
|
||||||
|
|
||||||
|
Remove((struct Node *)mln);
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeMem(mln,sizeof(*mln) + allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
#endif /* __MEM_DEBUG */
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if (__memory_pool != NULL)
|
if(__memory_pool != NULL)
|
||||||
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
FreePooled(__memory_pool,mn,allocation_size);
|
FreePooled(__memory_pool,mn,allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
FreeMem(mn,allocation_size);
|
{
|
||||||
|
#if defined(__MEM_DEBUG)
|
||||||
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeMem(mn,allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
struct MinNode * mln = (struct MinNode *)mn;
|
||||||
|
|
||||||
|
mln--;
|
||||||
|
|
||||||
|
Remove((struct Node *)mln);
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeMem(mln,sizeof(*mln) + allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
#endif /* __MEM_DEBUG */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
|
|
||||||
@ -401,7 +458,7 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
|
|||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
size_t size = mn->mn_Size;
|
ULONG size = GET_MN_SIZE(mn);
|
||||||
|
|
||||||
check_memory_node(mn,file,line);
|
check_memory_node(mn,file,line);
|
||||||
|
|
||||||
@ -409,7 +466,7 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
|
|||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,mn->mn_Size,mn->mn_Allocation);
|
kprintf("[%s] - %10ld 0x%08lx [",__program_name,size,mn->mn_Allocation);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if(mn->mn_File != NULL)
|
||||||
kprintf("allocated at %s:%ld, ",mn->mn_File,mn->mn_Line);
|
kprintf("allocated at %s:%ld, ",mn->mn_File,mn->mn_Line);
|
||||||
@ -436,14 +493,14 @@ __free_memory_node(struct MemoryNode * mn,const char * UNUSED file,int UNUSED li
|
|||||||
{
|
{
|
||||||
#ifdef __MEM_DEBUG_LOG
|
#ifdef __MEM_DEBUG_LOG
|
||||||
{
|
{
|
||||||
kprintf("[%s] - %10ld 0x%08lx [",__program_name,mn->mn_Size,mn->mn_Allocation);
|
kprintf("[%s] - %10ld 0x%08lx [",__program_name,size,mn->mn_Allocation);
|
||||||
|
|
||||||
kprintf("FAILED]\n");
|
kprintf("FAILED]\n");
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
kprintf("[%s] %s:%ld:Allocation at address 0x%08lx, size %ld",
|
kprintf("[%s] %s:%ld:Allocation at address 0x%08lx, size %ld",
|
||||||
__program_name,file,line,mn->mn_Allocation,mn->mn_Size);
|
__program_name,file,line,mn->mn_Allocation,size);
|
||||||
|
|
||||||
if(mn->mn_File != NULL)
|
if(mn->mn_File != NULL)
|
||||||
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
kprintf(", allocated at %s:%ld",mn->mn_File,mn->mn_Line);
|
||||||
@ -467,6 +524,9 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
|
|||||||
|
|
||||||
assert(ptr != NULL);
|
assert(ptr != NULL);
|
||||||
|
|
||||||
|
SHOWPOINTER(ptr);
|
||||||
|
SHOWVALUE(force);
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
/*if((rand() % 16) == 0)
|
/*if((rand() % 16) == 0)
|
||||||
@ -480,7 +540,7 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
|
|||||||
{
|
{
|
||||||
if(mn != NULL)
|
if(mn != NULL)
|
||||||
{
|
{
|
||||||
if(force || (NOT mn->mn_NeverFree))
|
if(force || FLAG_IS_CLEAR(mn->mn_Size, MN_SIZE_NEVERFREE))
|
||||||
__free_memory_node(mn,file,line);
|
__free_memory_node(mn,file,line);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -502,7 +562,9 @@ __free_memory(void * ptr,BOOL force,const char * file,int line)
|
|||||||
{
|
{
|
||||||
assert( mn != NULL );
|
assert( mn != NULL );
|
||||||
|
|
||||||
if(mn != NULL && (force || (NOT mn->mn_NeverFree)))
|
SHOWVALUE(mn->mn_Size);
|
||||||
|
|
||||||
|
if(mn != NULL && (force || FLAG_IS_CLEAR(mn->mn_Size, MN_SIZE_NEVERFREE)))
|
||||||
__free_memory_node(mn,file,line);
|
__free_memory_node(mn,file,line);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|||||||
82
library/stdlib_free_unused_slabs.c
Normal file
82
library/stdlib_free_unused_slabs.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_HEADERS_H
|
||||||
|
#include "stdlib_headers.h"
|
||||||
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_MEMORY_H
|
||||||
|
#include "stdlib_memory.h"
|
||||||
|
#endif /* _STDLIB_MEMORY_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* Free all currently unused slabs, regardless of whether they
|
||||||
|
* are ready to be purged (SlabNode.sn_EmptyDecay == 0).
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
__free_unused_slabs(void)
|
||||||
|
{
|
||||||
|
if(__slab_data.sd_InUse)
|
||||||
|
{
|
||||||
|
struct MinNode * free_node;
|
||||||
|
struct MinNode * free_node_next;
|
||||||
|
struct SlabNode * sn;
|
||||||
|
|
||||||
|
__memory_lock();
|
||||||
|
|
||||||
|
for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ;
|
||||||
|
free_node->mln_Succ != NULL ;
|
||||||
|
free_node = free_node_next)
|
||||||
|
{
|
||||||
|
free_node_next = (struct MinNode *)free_node->mln_Succ;
|
||||||
|
|
||||||
|
/* free_node points to SlabNode.sn_EmptyLink, which
|
||||||
|
* directly follows the SlabNode.sn_MinNode.
|
||||||
|
*/
|
||||||
|
sn = (struct SlabNode *)&free_node[-1];
|
||||||
|
|
||||||
|
/* Unlink from list of empty slabs. */
|
||||||
|
Remove((struct Node *)free_node);
|
||||||
|
|
||||||
|
/* Unlink from list of slabs of the same size. */
|
||||||
|
Remove((struct Node *)sn);
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeVec(sn);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
|
||||||
|
__memory_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
82
library/stdlib_get_slab_allocations.c
Normal file
82
library/stdlib_get_slab_allocations.c
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_HEADERS_H
|
||||||
|
#include "stdlib_headers.h"
|
||||||
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_MEMORY_H
|
||||||
|
#include "stdlib_memory.h"
|
||||||
|
#endif /* _STDLIB_MEMORY_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
__get_slab_allocations(__slab_allocation_callback callback)
|
||||||
|
{
|
||||||
|
if(__slab_data.sd_InUse)
|
||||||
|
{
|
||||||
|
struct __slab_allocation_information sai;
|
||||||
|
|
||||||
|
memset(&sai,0,sizeof(sai));
|
||||||
|
|
||||||
|
__memory_lock();
|
||||||
|
|
||||||
|
sai.sai_num_single_allocations = __slab_data.sd_NumSingleAllocations;
|
||||||
|
sai.sai_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize;
|
||||||
|
|
||||||
|
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
|
||||||
|
{
|
||||||
|
const struct SlabSingleAllocation * ssa;
|
||||||
|
|
||||||
|
for(ssa = (struct SlabSingleAllocation *)__slab_data.sd_SingleAllocations.mlh_Head ;
|
||||||
|
ssa->ssa_MinNode.mln_Succ != NULL ;
|
||||||
|
ssa = (struct SlabSingleAllocation *)ssa->ssa_MinNode.mln_Succ)
|
||||||
|
{
|
||||||
|
sai.sai_allocation_index++;
|
||||||
|
|
||||||
|
sai.sai_allocation_size = ssa->ssa_Size - sizeof(*ssa);
|
||||||
|
sai.sai_total_allocation_size = ssa->ssa_Size;
|
||||||
|
|
||||||
|
if((*callback)(&sai) != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*callback)(&sai);
|
||||||
|
}
|
||||||
|
|
||||||
|
__memory_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
206
library/stdlib_get_slab_stats.c
Normal file
206
library/stdlib_get_slab_stats.c
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_HEADERS_H
|
||||||
|
#include "stdlib_headers.h"
|
||||||
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_MEMORY_H
|
||||||
|
#include "stdlib_memory.h"
|
||||||
|
#endif /* _STDLIB_MEMORY_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#include <setjmp.h>
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
struct context
|
||||||
|
{
|
||||||
|
jmp_buf abort_buf;
|
||||||
|
void * user_data;
|
||||||
|
__slab_status_callback callback;
|
||||||
|
char * buffer;
|
||||||
|
size_t buffer_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
static void print(struct context * ct, const char * format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
va_start(args,format);
|
||||||
|
len = vsnprintf(ct->buffer, ct->buffer_size, format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
/* This shouldn't happen: the buffer ought to be large enough
|
||||||
|
* to hold every single line.
|
||||||
|
*/
|
||||||
|
if(len >= (int)ct->buffer_size)
|
||||||
|
len = strlen(ct->buffer);
|
||||||
|
|
||||||
|
if((*ct->callback)(ct->user_data, ct->buffer, len) != 0)
|
||||||
|
longjmp(ct->abort_buf,-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
__get_slab_stats(void * user_data, __slab_status_callback callback)
|
||||||
|
{
|
||||||
|
if(__slab_data.sd_InUse)
|
||||||
|
{
|
||||||
|
static int times_checked = 1;
|
||||||
|
|
||||||
|
const struct SlabNode * sn;
|
||||||
|
volatile size_t num_empty_slabs = 0;
|
||||||
|
volatile size_t num_full_slabs = 0;
|
||||||
|
volatile size_t num_slabs = 0;
|
||||||
|
volatile size_t slab_allocation_size = 0;
|
||||||
|
volatile size_t total_slab_allocation_size = 0;
|
||||||
|
struct context ct;
|
||||||
|
char line[1024];
|
||||||
|
char time_buffer[40];
|
||||||
|
time_t now;
|
||||||
|
struct tm when;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(&ct, 0, sizeof(ct));
|
||||||
|
|
||||||
|
ct.user_data = user_data;
|
||||||
|
ct.callback = callback;
|
||||||
|
ct.buffer = line;
|
||||||
|
ct.buffer_size = sizeof(line);
|
||||||
|
|
||||||
|
__memory_lock();
|
||||||
|
|
||||||
|
if(setjmp(ct.abort_buf) == 0)
|
||||||
|
{
|
||||||
|
now = time(NULL);
|
||||||
|
localtime_r(&now, &when);
|
||||||
|
|
||||||
|
strftime(time_buffer, sizeof(time_buffer), "%Y-%m-%dT%H:%M:%S", &when);
|
||||||
|
|
||||||
|
print(&ct,"{\n");
|
||||||
|
|
||||||
|
print(&ct,"\t\"when\": \"%s\",\n", time_buffer);
|
||||||
|
print(&ct,"\t\"times_checked\": %d,\n", times_checked++);
|
||||||
|
print(&ct,"\t\"slab_size\": %zu,\n", __slab_data.sd_StandardSlabSize);
|
||||||
|
print(&ct,"\t\"num_single_allocations\": %zu,\n", __slab_data.sd_NumSingleAllocations);
|
||||||
|
print(&ct,"\t\"total_single_allocation_size\": %zu,\n", __slab_data.sd_TotalSingleAllocationSize);
|
||||||
|
|
||||||
|
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
|
||||||
|
{
|
||||||
|
const struct SlabSingleAllocation * ssa;
|
||||||
|
|
||||||
|
print(&ct,"\t\"single_allocations\": [\n");
|
||||||
|
|
||||||
|
for(ssa = (struct SlabSingleAllocation *)__slab_data.sd_SingleAllocations.mlh_Head ;
|
||||||
|
ssa->ssa_MinNode.mln_Succ != NULL ;
|
||||||
|
ssa = (struct SlabSingleAllocation *)ssa->ssa_MinNode.mln_Succ)
|
||||||
|
{
|
||||||
|
print(&ct,"\t\t{ \"size\": %lu, \"total_size\": %lu }%s\n",
|
||||||
|
ssa->ssa_Size - sizeof(*ssa), ssa->ssa_Size,
|
||||||
|
ssa->ssa_MinNode.mln_Succ->mln_Succ != NULL ? "," : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
print(&ct,"\t],\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print(&ct,"\t\"single_allocations\": [],\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||||
|
{
|
||||||
|
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||||
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
|
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||||
|
{
|
||||||
|
if (sn->sn_UseCount == 0)
|
||||||
|
num_empty_slabs++;
|
||||||
|
else if (sn->sn_UseCount == sn->sn_Count)
|
||||||
|
num_full_slabs++;
|
||||||
|
|
||||||
|
num_slabs++;
|
||||||
|
|
||||||
|
slab_allocation_size += sn->sn_ChunkSize * sn->sn_UseCount;
|
||||||
|
total_slab_allocation_size += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print(&ct,"\t\"num_slabs\": %zu,\n", num_slabs);
|
||||||
|
print(&ct,"\t\"num_empty_slabs\": %zu,\n", num_empty_slabs);
|
||||||
|
print(&ct,"\t\"num_full_slabs\": %zu,\n", num_full_slabs);
|
||||||
|
print(&ct,"\t\"slab_allocation_size\": %zu,\n", slab_allocation_size);
|
||||||
|
print(&ct,"\t\"total_slab_allocation_size\": %zu,\n", total_slab_allocation_size);
|
||||||
|
|
||||||
|
if(num_slabs > 0)
|
||||||
|
{
|
||||||
|
const char * eol = "";
|
||||||
|
|
||||||
|
print(&ct,"\t\"slabs\": [\n");
|
||||||
|
|
||||||
|
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||||
|
{
|
||||||
|
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||||
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
|
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||||
|
{
|
||||||
|
print(&ct,"%s\t\t{ \"size\": %lu, \"chunks\": %lu, \"chunks_in_use\": %lu, \"times_reused\": %lu, \"empty_decay\": %lu }",
|
||||||
|
eol,
|
||||||
|
sn->sn_ChunkSize,
|
||||||
|
sn->sn_Count,
|
||||||
|
sn->sn_UseCount,
|
||||||
|
sn->sn_NumReused,
|
||||||
|
sn->sn_EmptyDecay);
|
||||||
|
|
||||||
|
eol = ",\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print(&ct,"\n\t]\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
print(&ct,"\t\"slabs\": []\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
print(&ct,"}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
__memory_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
109
library/stdlib_get_slab_usage.c
Normal file
109
library/stdlib_get_slab_usage.c
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_HEADERS_H
|
||||||
|
#include "stdlib_headers.h"
|
||||||
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_MEMORY_H
|
||||||
|
#include "stdlib_memory.h"
|
||||||
|
#endif /* _STDLIB_MEMORY_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
__get_slab_usage(__slab_usage_callback callback)
|
||||||
|
{
|
||||||
|
if(__slab_data.sd_InUse)
|
||||||
|
{
|
||||||
|
struct __slab_usage_information sui;
|
||||||
|
const struct SlabNode * sn;
|
||||||
|
BOOL stop;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(&sui,0,sizeof(sui));
|
||||||
|
|
||||||
|
__memory_lock();
|
||||||
|
|
||||||
|
sui.sui_slab_size = __slab_data.sd_StandardSlabSize;
|
||||||
|
sui.sui_num_single_allocations = __slab_data.sd_NumSingleAllocations;
|
||||||
|
sui.sui_total_single_allocation_size = __slab_data.sd_TotalSingleAllocationSize;
|
||||||
|
|
||||||
|
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||||
|
{
|
||||||
|
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||||
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
|
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||||
|
{
|
||||||
|
if (sn->sn_UseCount == 0)
|
||||||
|
sui.sui_num_empty_slabs++;
|
||||||
|
else if (sn->sn_Count == sn->sn_UseCount)
|
||||||
|
sui.sui_num_full_slabs++;
|
||||||
|
|
||||||
|
sui.sui_num_slabs++;
|
||||||
|
|
||||||
|
sui.sui_total_slab_allocation_size += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(sui.sui_num_slabs > 0)
|
||||||
|
{
|
||||||
|
for(i = 0, stop = FALSE ; NOT stop && i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||||
|
{
|
||||||
|
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
||||||
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
|
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
||||||
|
{
|
||||||
|
sui.sui_chunk_size = sn->sn_ChunkSize;
|
||||||
|
sui.sui_num_chunks = sn->sn_Count;
|
||||||
|
sui.sui_num_chunks_used = sn->sn_UseCount;
|
||||||
|
sui.sui_num_reused = sn->sn_NumReused;
|
||||||
|
|
||||||
|
sui.sui_slab_index++;
|
||||||
|
|
||||||
|
if((*callback)(&sui) != 0)
|
||||||
|
{
|
||||||
|
stop = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(*callback)(&sui);
|
||||||
|
}
|
||||||
|
|
||||||
|
__memory_unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -37,6 +37,10 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L))
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
lldiv_t
|
lldiv_t
|
||||||
lldiv(long long n,long long d)
|
lldiv(long long n,long long d)
|
||||||
{
|
{
|
||||||
@ -49,3 +53,7 @@ lldiv(long long n,long long d)
|
|||||||
|
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@ -117,9 +117,20 @@ call_main(void)
|
|||||||
struct Process * this_process = (struct Process *)FindTask(NULL);
|
struct Process * this_process = (struct Process *)FindTask(NULL);
|
||||||
UBYTE * arg_str = GetArgStr();
|
UBYTE * arg_str = GetArgStr();
|
||||||
size_t arg_str_len = strlen(arg_str);
|
size_t arg_str_len = strlen(arg_str);
|
||||||
UBYTE * arg_str_copy = AllocVec(arg_str_len+1,MEMF_PRIVATE);
|
UBYTE * arg_str_copy;
|
||||||
UBYTE current_dir_name[256];
|
UBYTE current_dir_name[256];
|
||||||
|
|
||||||
|
#if defined(__amigaos4__)
|
||||||
|
{
|
||||||
|
arg_str_copy = AllocVec(arg_str_len+1,MEMF_PRIVATE);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
arg_str_copy = AllocVec(arg_str_len+1,MEMF_ANY);
|
||||||
|
}
|
||||||
|
#endif /* __amigaos4__ */
|
||||||
|
|
||||||
|
|
||||||
if(arg_str_copy != NULL && NameFromLock(this_process->pr_CurrentDir,current_dir_name,sizeof(current_dir_name)))
|
if(arg_str_copy != NULL && NameFromLock(this_process->pr_CurrentDir,current_dir_name,sizeof(current_dir_name)))
|
||||||
{
|
{
|
||||||
strcpy(arg_str_copy,arg_str);
|
strcpy(arg_str_copy,arg_str);
|
||||||
|
|||||||
@ -31,6 +31,8 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*#define DEBUG*/
|
||||||
|
|
||||||
#ifndef _STDLIB_HEADERS_H
|
#ifndef _STDLIB_HEADERS_H
|
||||||
#include "stdlib_headers.h"
|
#include "stdlib_headers.h"
|
||||||
#endif /* _STDLIB_HEADERS_H */
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
@ -72,27 +74,8 @@ struct MinList NOCOMMON __memory_list;
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
size_t
|
|
||||||
__get_allocation_size(size_t size)
|
|
||||||
{
|
|
||||||
#ifndef __MEM_DEBUG
|
|
||||||
{
|
|
||||||
size_t total_allocation_size;
|
|
||||||
|
|
||||||
total_allocation_size = sizeof(struct MemoryNode) + size;
|
|
||||||
|
|
||||||
/* Round up the allocation size to the physical allocation granularity. */
|
|
||||||
size += ((total_allocation_size + MEM_BLOCKMASK) & ~((ULONG)MEM_BLOCKMASK)) - total_allocation_size;
|
|
||||||
}
|
|
||||||
#endif /* __MEM_DEBUG */
|
|
||||||
|
|
||||||
return(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
|
|
||||||
void *
|
void *
|
||||||
__allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,int UNUSED unused_line)
|
__allocate_memory(size_t size,BOOL never_free,const char * UNUSED debug_file_name,int UNUSED debug_line_number)
|
||||||
{
|
{
|
||||||
struct MemoryNode * mn;
|
struct MemoryNode * mn;
|
||||||
size_t allocation_size;
|
size_t allocation_size;
|
||||||
@ -135,54 +118,114 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,in
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
/* Round up the allocation size to the physical allocation granularity. */
|
/* Round up allocation to a multiple of 32 bits. */
|
||||||
size = __get_allocation_size(size);
|
if((size & 3) != 0)
|
||||||
|
size += 4 - (size & 3);
|
||||||
|
|
||||||
allocation_size = sizeof(*mn) + size;
|
allocation_size = sizeof(*mn) + size;
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
|
/* Integer overflow has occured? */
|
||||||
|
if(size == 0 || allocation_size < size)
|
||||||
|
{
|
||||||
|
__set_errno(ENOMEM);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We reuse the MemoryNode.mn_Size field to mark
|
||||||
|
* allocations are not suitable for use with
|
||||||
|
* free() and realloc(). This limits allocation
|
||||||
|
* sizes to a little less than 2 GBytes.
|
||||||
|
*/
|
||||||
|
if(allocation_size & MN_SIZE_NEVERFREE)
|
||||||
|
{
|
||||||
|
__set_errno(ENOMEM);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
{
|
{
|
||||||
/* Are we using the slab allocator? */
|
/* Are we using the slab allocator? */
|
||||||
if (__slab_data.sd_InUse)
|
if(__slab_data.sd_InUse)
|
||||||
{
|
{
|
||||||
mn = __slab_allocate(allocation_size);
|
mn = __slab_allocate(allocation_size);
|
||||||
}
|
}
|
||||||
else if (__memory_pool != NULL)
|
|
||||||
{
|
|
||||||
mn = AllocPooled(__memory_pool,allocation_size);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if defined(__amigaos4__)
|
if (__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
mn = AllocMem(allocation_size,MEMF_PRIVATE);
|
PROFILE_OFF();
|
||||||
|
mn = AllocPooled(__memory_pool,allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
#else
|
else
|
||||||
{
|
{
|
||||||
mn = AllocMem(allocation_size,MEMF_ANY);
|
#ifdef __MEM_DEBUG
|
||||||
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
|
mn = AllocMem(allocation_size,MEMF_ANY);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
struct MinNode * mln;
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY);
|
||||||
|
PROFILE_ON();
|
||||||
|
|
||||||
|
if(mln != NULL)
|
||||||
|
{
|
||||||
|
AddTail((struct List *)&__memory_list,(struct Node *)mln);
|
||||||
|
|
||||||
|
mn = (struct MemoryNode *)&mln[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mn = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* __MEM_DEBUG */
|
||||||
}
|
}
|
||||||
#endif /* __amigaos4__ */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
if(__memory_pool != NULL)
|
if(__memory_pool != NULL)
|
||||||
{
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
mn = AllocPooled(__memory_pool,allocation_size);
|
mn = AllocPooled(__memory_pool,allocation_size);
|
||||||
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#if defined(__amigaos4__)
|
#ifdef __MEM_DEBUG
|
||||||
{
|
{
|
||||||
mn = AllocMem(allocation_size,MEMF_PRIVATE);
|
PROFILE_OFF();
|
||||||
|
mn = AllocMem(allocation_size,MEMF_ANY);
|
||||||
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
mn = AllocMem(allocation_size,MEMF_ANY);
|
struct MinNode * mln;
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
mln = AllocMem(sizeof(*mln) + allocation_size,MEMF_ANY);
|
||||||
|
PROFILE_ON();
|
||||||
|
|
||||||
|
if(mln != NULL)
|
||||||
|
{
|
||||||
|
AddTail((struct List *)&__memory_list,(struct Node *)mln);
|
||||||
|
|
||||||
|
mn = (struct MemoryNode *)&mln[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mn = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* __amigaos4__ */
|
#endif /* __MEM_DEBUG */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __USE_SLAB_ALLOCATOR */
|
#endif /* __USE_SLAB_ALLOCATOR */
|
||||||
@ -193,10 +236,10 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,in
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
mn->mn_Size = size;
|
mn->mn_Size = size;
|
||||||
mn->mn_NeverFree = never_free;
|
|
||||||
|
|
||||||
AddTail((struct List *)&__memory_list,(struct Node *)mn);
|
if(never_free)
|
||||||
|
SET_FLAG(mn->mn_Size, MN_SIZE_NEVERFREE);
|
||||||
|
|
||||||
__current_memory_allocated += allocation_size;
|
__current_memory_allocated += allocation_size;
|
||||||
if(__maximum_memory_allocated < __current_memory_allocated)
|
if(__maximum_memory_allocated < __current_memory_allocated)
|
||||||
@ -212,11 +255,13 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,in
|
|||||||
char * body = head + MALLOC_HEAD_SIZE;
|
char * body = head + MALLOC_HEAD_SIZE;
|
||||||
char * tail = body + size;
|
char * tail = body + size;
|
||||||
|
|
||||||
|
AddTail((struct List *)&__memory_list,(struct Node *)mn);
|
||||||
|
|
||||||
mn->mn_AlreadyFree = FALSE;
|
mn->mn_AlreadyFree = FALSE;
|
||||||
mn->mn_Allocation = body;
|
mn->mn_Allocation = body;
|
||||||
mn->mn_AllocationSize = allocation_size;
|
mn->mn_AllocationSize = allocation_size;
|
||||||
mn->mn_File = (char *)file;
|
mn->mn_File = (char *)debug_file_name;
|
||||||
mn->mn_Line = line;
|
mn->mn_Line = debug_line_number;
|
||||||
mn->mn_FreeFile = NULL;
|
mn->mn_FreeFile = NULL;
|
||||||
mn->mn_FreeLine = 0;
|
mn->mn_FreeLine = 0;
|
||||||
|
|
||||||
@ -228,7 +273,7 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,in
|
|||||||
{
|
{
|
||||||
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,body);
|
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,body);
|
||||||
|
|
||||||
kprintf("allocated at %s:%ld]\n",file,line);
|
kprintf("allocated at %s:%ld]\n",debug_file_name,debug_line_number);
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
|
|
||||||
@ -264,7 +309,7 @@ __allocate_memory(size_t size,BOOL never_free,const char * UNUSED unused_file,in
|
|||||||
{
|
{
|
||||||
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,NULL);
|
kprintf("[%s] + %10ld 0x%08lx [",__program_name,size,NULL);
|
||||||
|
|
||||||
kprintf("FAILED: allocated at %s:%ld]\n",file,line);
|
kprintf("FAILED: allocated at %s:%ld]\n",debug_file_name,debug_line_number);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG_LOG */
|
#endif /* __MEM_DEBUG_LOG */
|
||||||
@ -327,8 +372,12 @@ static struct SignalSemaphore * memory_semaphore;
|
|||||||
void
|
void
|
||||||
__memory_lock(void)
|
__memory_lock(void)
|
||||||
{
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
|
|
||||||
if(memory_semaphore != NULL)
|
if(memory_semaphore != NULL)
|
||||||
ObtainSemaphore(memory_semaphore);
|
ObtainSemaphore(memory_semaphore);
|
||||||
|
|
||||||
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -336,8 +385,12 @@ __memory_lock(void)
|
|||||||
void
|
void
|
||||||
__memory_unlock(void)
|
__memory_unlock(void)
|
||||||
{
|
{
|
||||||
|
PROFILE_OFF();
|
||||||
|
|
||||||
if(memory_semaphore != NULL)
|
if(memory_semaphore != NULL)
|
||||||
ReleaseSemaphore(memory_semaphore);
|
ReleaseSemaphore(memory_semaphore);
|
||||||
|
|
||||||
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
@ -475,7 +528,7 @@ STDLIB_CONSTRUCTOR(stdlib_memory_init)
|
|||||||
#if defined(__USE_SLAB_ALLOCATOR)
|
#if defined(__USE_SLAB_ALLOCATOR)
|
||||||
{
|
{
|
||||||
/* ZZZ this is just for the purpose of testing */
|
/* ZZZ this is just for the purpose of testing */
|
||||||
#if 0
|
#if DEBUG
|
||||||
{
|
{
|
||||||
TEXT slab_size_var[20];
|
TEXT slab_size_var[20];
|
||||||
|
|
||||||
|
|||||||
@ -65,7 +65,6 @@
|
|||||||
*/
|
*/
|
||||||
#define __USE_SLAB_ALLOCATOR
|
#define __USE_SLAB_ALLOCATOR
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -125,7 +124,6 @@
|
|||||||
#define __find_memory_node __find_memory_node_debug
|
#define __find_memory_node __find_memory_node_debug
|
||||||
#define __free_memory_node __free_memory_node_debug
|
#define __free_memory_node __free_memory_node_debug
|
||||||
|
|
||||||
#define __get_allocation_size __get_allocation_size_debug
|
|
||||||
#define __allocate_memory __allocate_memory_debug
|
#define __allocate_memory __allocate_memory_debug
|
||||||
|
|
||||||
#define __memory_pool __memory_pool_debug
|
#define __memory_pool __memory_pool_debug
|
||||||
@ -152,16 +150,24 @@ extern char * __getcwd(char * buffer,size_t buffer_size,const char *file,int lin
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
/* If this flag is set in mn_Size, then this memory allocation
|
||||||
|
* cannot be released with free() or used with realloc(). This
|
||||||
|
* flag is set by alloca().
|
||||||
|
*/
|
||||||
|
#define MN_SIZE_NEVERFREE (0x80000000UL)
|
||||||
|
|
||||||
|
/* This obtains the allocation size from a memory node, ignoring
|
||||||
|
* the "never free" flag altogether.
|
||||||
|
*/
|
||||||
|
#define GET_MN_SIZE(mn) ((mn)->mn_Size & ~MN_SIZE_NEVERFREE)
|
||||||
|
|
||||||
struct MemoryNode
|
struct MemoryNode
|
||||||
{
|
{
|
||||||
struct MinNode mn_MinNode;
|
|
||||||
size_t mn_Size;
|
|
||||||
|
|
||||||
UBYTE mn_NeverFree;
|
|
||||||
|
|
||||||
#ifdef __MEM_DEBUG
|
#ifdef __MEM_DEBUG
|
||||||
|
struct MinNode mn_MinNode;
|
||||||
|
|
||||||
UBYTE mn_AlreadyFree;
|
UBYTE mn_AlreadyFree;
|
||||||
UBYTE mn_Pad0[2];
|
UBYTE mn_Pad0[3];
|
||||||
|
|
||||||
void * mn_Allocation;
|
void * mn_Allocation;
|
||||||
size_t mn_AllocationSize;
|
size_t mn_AllocationSize;
|
||||||
@ -180,9 +186,9 @@ struct MemoryNode
|
|||||||
UBYTE mn_Pad1[3];
|
UBYTE mn_Pad1[3];
|
||||||
#endif /* __USE_MEM_TREES */
|
#endif /* __USE_MEM_TREES */
|
||||||
|
|
||||||
#else
|
|
||||||
UBYTE mn_Pad0[3];
|
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
|
ULONG mn_Size;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __USE_MEM_TREES
|
#ifdef __USE_MEM_TREES
|
||||||
@ -201,7 +207,7 @@ struct MemoryTree
|
|||||||
/* This keeps track of individual slabs. Each slab begins with this
|
/* This keeps track of individual slabs. Each slab begins with this
|
||||||
* header and is followed by the memory it manages. The size of that
|
* header and is followed by the memory it manages. The size of that
|
||||||
* memory "slab" is fixed and matches what is stored in
|
* memory "slab" is fixed and matches what is stored in
|
||||||
* SlabData.sd_MaxSlabSize.
|
* SlabData.sd_StandardSlabSize.
|
||||||
*
|
*
|
||||||
* Each slab manages allocations of a specific maximum size, e.g. 8, 16, 32,
|
* Each slab manages allocations of a specific maximum size, e.g. 8, 16, 32,
|
||||||
* 64, etc. bytes. Multiple slabs can exist which manage allocations of the same
|
* 64, etc. bytes. Multiple slabs can exist which manage allocations of the same
|
||||||
@ -229,12 +235,26 @@ struct SlabNode
|
|||||||
/* How many chunks of this slab are currently in use? */
|
/* How many chunks of this slab are currently in use? */
|
||||||
ULONG sn_UseCount;
|
ULONG sn_UseCount;
|
||||||
|
|
||||||
|
/* How many times was this slab reused instead of allocating
|
||||||
|
* it from system memory?
|
||||||
|
*/
|
||||||
|
ULONG sn_NumReused;
|
||||||
|
|
||||||
/* This contains all the chunks of memory which are available
|
/* This contains all the chunks of memory which are available
|
||||||
* for allocation.
|
* for allocation.
|
||||||
*/
|
*/
|
||||||
struct MinList sn_FreeList;
|
struct MinList sn_FreeList;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Memory allocations which are not part of a slab are
|
||||||
|
* tracked using this data structure.
|
||||||
|
*/
|
||||||
|
struct SlabSingleAllocation
|
||||||
|
{
|
||||||
|
struct MinNode ssa_MinNode;
|
||||||
|
ULONG ssa_Size;
|
||||||
|
};
|
||||||
|
|
||||||
/* This is the global bookkeeping information for managing
|
/* This is the global bookkeeping information for managing
|
||||||
* memory allocations from the slab data structure.
|
* memory allocations from the slab data structure.
|
||||||
*/
|
*/
|
||||||
@ -246,13 +266,13 @@ struct SlabData
|
|||||||
* which are 8 bytes in size, sd_Slabs[4] is for 16 byte
|
* which are 8 bytes in size, sd_Slabs[4] is for 16 byte
|
||||||
* chunks, etc. The minimum chunk size is 8, which is why
|
* chunks, etc. The minimum chunk size is 8, which is why
|
||||||
* lists 0..2 are not used. Currently, there is an upper limit
|
* lists 0..2 are not used. Currently, there is an upper limit
|
||||||
* of 2^31 bytes per chunk, but you should not be using slab
|
* of 2^17 bytes per chunk, but you should not be using slab
|
||||||
* chunks much larger than 4096 bytes.
|
* chunks much larger than 4096 bytes.
|
||||||
*/
|
*/
|
||||||
struct MinList sd_Slabs[31];
|
struct MinList sd_Slabs[17];
|
||||||
|
|
||||||
/* Memory allocations which are larger than the limit
|
/* Memory allocations which are larger than the limit
|
||||||
* found in the sd_MaxSlabSize field are kept in this list.
|
* found in the sd_StandardSlabSize field are kept in this list.
|
||||||
* They are never associated with a slab.
|
* They are never associated with a slab.
|
||||||
*/
|
*/
|
||||||
struct MinList sd_SingleAllocations;
|
struct MinList sd_SingleAllocations;
|
||||||
@ -263,18 +283,20 @@ struct SlabData
|
|||||||
*/
|
*/
|
||||||
struct MinList sd_EmptySlabs;
|
struct MinList sd_EmptySlabs;
|
||||||
|
|
||||||
/* This is the maximum size of a memory allocation which may
|
/* This is the standard size of a memory allocation which may
|
||||||
* be made from a slab that can accommodate it. This number
|
* be made from a slab that can accommodate it. This number
|
||||||
* is initialized from the __slab_max_size global variable,
|
* is initialized from the __slab_max_size global variable,
|
||||||
* if > 0, and unless it already is a power of two, it will
|
* if > 0, and unless it already is a power of two, it will
|
||||||
* be rounded up to the next largest power of two.
|
* be rounded up to the next largest power of two.
|
||||||
*/
|
*/
|
||||||
size_t sd_MaxSlabSize;
|
size_t sd_StandardSlabSize;
|
||||||
|
|
||||||
/* This field keeps track of how many entries there are in
|
/* These fields keep track of how many entries there are in
|
||||||
* the sd_SingleAllocations list.
|
* the sd_SingleAllocations list, and how much memory these
|
||||||
|
* allocations occupy.
|
||||||
*/
|
*/
|
||||||
ULONG sd_NumSingleAllocations;
|
size_t sd_NumSingleAllocations;
|
||||||
|
size_t sd_TotalSingleAllocationSize;
|
||||||
|
|
||||||
/* If this is set to TRUE, then memory allocations will be
|
/* If this is set to TRUE, then memory allocations will be
|
||||||
* be managed through slabs.
|
* be managed through slabs.
|
||||||
@ -285,7 +307,8 @@ struct SlabData
|
|||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
extern struct SlabData NOCOMMON __slab_data;
|
extern struct SlabData NOCOMMON __slab_data;
|
||||||
extern ULONG NOCOMMON __slab_max_size;
|
extern unsigned long NOCOMMON __slab_max_size;
|
||||||
|
extern unsigned long NOCOMMON __slab_purge_threshold;
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
|||||||
@ -45,8 +45,8 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
extern void ASM _PROLOG(REG(a0,char *));
|
extern void __asm _PROLOG(register __a0 char *);
|
||||||
extern void ASM _EPILOG(REG(a0,char *));
|
extern void __asm _EPILOG(register __a0 char *);
|
||||||
|
|
||||||
#if _PROFILE
|
#if _PROFILE
|
||||||
#define PROFILE_OFF() _PROLOG(0L)
|
#define PROFILE_OFF() _PROLOG(0L)
|
||||||
|
|||||||
@ -31,6 +31,8 @@
|
|||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*#define DEBUG*/
|
||||||
|
|
||||||
#ifndef _STDLIB_HEADERS_H
|
#ifndef _STDLIB_HEADERS_H
|
||||||
#include "stdlib_headers.h"
|
#include "stdlib_headers.h"
|
||||||
#endif /* _STDLIB_HEADERS_H */
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
@ -76,6 +78,7 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
#endif /* UNIX_PATH_SEMANTICS */
|
#endif /* UNIX_PATH_SEMANTICS */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
size_t old_size;
|
||||||
struct MemoryNode * mn;
|
struct MemoryNode * mn;
|
||||||
BOOL reallocate;
|
BOOL reallocate;
|
||||||
|
|
||||||
@ -108,29 +111,23 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
|
|
||||||
if(mn == NULL || mn->mn_NeverFree)
|
if(mn == NULL || FLAG_IS_SET(mn->mn_Size, MN_SIZE_NEVERFREE))
|
||||||
{
|
{
|
||||||
SHOWMSG("cannot free this chunk");
|
SHOWMSG("cannot free this chunk");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
old_size = GET_MN_SIZE(mn);
|
||||||
|
|
||||||
/* Don't do anything unless the size of the allocation
|
/* Don't do anything unless the size of the allocation
|
||||||
has really changed. */
|
has really changed. */
|
||||||
#if defined(__MEM_DEBUG)
|
#if defined(__MEM_DEBUG)
|
||||||
{
|
{
|
||||||
reallocate = (mn->mn_Size != size);
|
reallocate = (old_size != size);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
size_t rounded_allocation_size;
|
if(size > old_size)
|
||||||
|
|
||||||
/* Round the total allocation size to the operating system
|
|
||||||
granularity. */
|
|
||||||
rounded_allocation_size = __get_allocation_size(size);
|
|
||||||
|
|
||||||
assert( rounded_allocation_size >= size );
|
|
||||||
|
|
||||||
if(rounded_allocation_size > mn->mn_Size)
|
|
||||||
{
|
{
|
||||||
/* Allocation size should grow. */
|
/* Allocation size should grow. */
|
||||||
reallocate = TRUE;
|
reallocate = TRUE;
|
||||||
@ -143,7 +140,7 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
allocation. We also take into account that the
|
allocation. We also take into account that the
|
||||||
actual size of the allocation is affected by a
|
actual size of the allocation is affected by a
|
||||||
certain operating system imposed granularity. */
|
certain operating system imposed granularity. */
|
||||||
reallocate = (rounded_allocation_size < mn->mn_Size && rounded_allocation_size <= mn->mn_Size / 2);
|
reallocate = (size < old_size && size <= old_size / 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* __MEM_DEBUG */
|
#endif /* __MEM_DEBUG */
|
||||||
@ -152,7 +149,7 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
{
|
{
|
||||||
void * new_ptr;
|
void * new_ptr;
|
||||||
|
|
||||||
D(("realloc() size has changed; old=%ld, new=%ld",mn->mn_Size,size));
|
D(("realloc() size has changed; old=%ld, new=%ld",old_size,size));
|
||||||
|
|
||||||
/* We allocate the new memory chunk before we
|
/* We allocate the new memory chunk before we
|
||||||
attempt to replace the old. */
|
attempt to replace the old. */
|
||||||
@ -164,8 +161,8 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Copy the contents of the old allocation to the new buffer. */
|
/* Copy the contents of the old allocation to the new buffer. */
|
||||||
if(size > mn->mn_Size)
|
if(size > old_size)
|
||||||
size = mn->mn_Size;
|
size = old_size;
|
||||||
|
|
||||||
memmove(new_ptr,ptr,size);
|
memmove(new_ptr,ptr,size);
|
||||||
|
|
||||||
@ -177,7 +174,7 @@ __realloc(void *ptr,size_t size,const char * file,int line)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",mn->mn_Size,size));
|
D(("size didn't actually change that much (%ld -> %ld); returning memory block as is.",old_size,size));
|
||||||
|
|
||||||
/* No change in size. */
|
/* No change in size. */
|
||||||
result = ptr;
|
result = ptr;
|
||||||
|
|||||||
@ -47,45 +47,76 @@ struct SlabData NOCOMMON __slab_data;
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
struct SlabChunk
|
||||||
|
{
|
||||||
|
struct SlabNode * sc_Parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
void *
|
void *
|
||||||
__slab_allocate(size_t allocation_size)
|
__slab_allocate(size_t allocation_size)
|
||||||
{
|
{
|
||||||
|
struct SlabChunk * chunk;
|
||||||
void * allocation = NULL;
|
void * allocation = NULL;
|
||||||
|
size_t allocation_size_with_chunk_header;
|
||||||
|
|
||||||
D(("allocating %lu bytes of memory",allocation_size));
|
D(("allocating %lu bytes of memory",allocation_size));
|
||||||
|
|
||||||
assert( __slab_data.sd_MaxSlabSize > 0 );
|
assert( __slab_data.sd_StandardSlabSize > 0 );
|
||||||
|
|
||||||
|
/* Check for integer overflow. */
|
||||||
|
allocation_size_with_chunk_header = sizeof(*chunk) + allocation_size;
|
||||||
|
if(allocation_size_with_chunk_header < allocation_size)
|
||||||
|
return(NULL);
|
||||||
|
|
||||||
/* Number of bytes to allocate exceeds the slab size?
|
/* Number of bytes to allocate exceeds the slab size?
|
||||||
* If so, allocate this memory chunk separately and
|
* If so, allocate this memory chunk separately and
|
||||||
* keep track of it.
|
* keep track of it.
|
||||||
*/
|
*/
|
||||||
if(allocation_size > __slab_data.sd_MaxSlabSize)
|
if(allocation_size_with_chunk_header > __slab_data.sd_StandardSlabSize)
|
||||||
{
|
{
|
||||||
struct MinNode * single_allocation;
|
struct SlabSingleAllocation * ssa;
|
||||||
|
ULONG total_single_allocation_size = sizeof(*ssa) + allocation_size;
|
||||||
|
|
||||||
D(("allocation size is > %ld; this will be stored separately",__slab_data.sd_MaxSlabSize));
|
D(("allocation size is > %ld; this will be stored separately",__slab_data.sd_StandardSlabSize));
|
||||||
D(("allocating %ld (MinNode) + %ld = %ld bytes",sizeof(*single_allocation),allocation_size,sizeof(*single_allocation) + allocation_size));
|
D(("allocating %ld (MinNode+Size) + %ld = %ld bytes",sizeof(*ssa),allocation_size,total_single_allocation_size));
|
||||||
|
|
||||||
#if defined(__amigaos4__)
|
/* No integer overflow? */
|
||||||
|
if(allocation_size < total_single_allocation_size)
|
||||||
{
|
{
|
||||||
single_allocation = AllocVec(sizeof(*single_allocation) + allocation_size,MEMF_PRIVATE);
|
PROFILE_OFF();
|
||||||
|
|
||||||
|
#if defined(__amigaos4__)
|
||||||
|
{
|
||||||
|
ssa = AllocMem(total_single_allocation_size,MEMF_PRIVATE);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
ssa = AllocMem(total_single_allocation_size,MEMF_ANY);
|
||||||
|
}
|
||||||
|
#endif /* __amigaos4__ */
|
||||||
|
|
||||||
|
PROFILE_ON();
|
||||||
}
|
}
|
||||||
#else
|
/* Integer overflow has occured. */
|
||||||
|
else
|
||||||
{
|
{
|
||||||
single_allocation = AllocVec(sizeof(*single_allocation) + allocation_size,MEMF_ANY);
|
ssa = NULL;
|
||||||
}
|
}
|
||||||
#endif /* __amigaos4__ */
|
|
||||||
|
|
||||||
if(single_allocation != NULL)
|
if(ssa != NULL)
|
||||||
{
|
{
|
||||||
|
ssa->ssa_Size = total_single_allocation_size;
|
||||||
|
|
||||||
|
allocation = &ssa[1];
|
||||||
|
|
||||||
D(("single allocation = 0x%08lx",allocation));
|
D(("single allocation = 0x%08lx",allocation));
|
||||||
|
|
||||||
AddTail((struct List *)&__slab_data.sd_SingleAllocations,(struct Node *)single_allocation);
|
AddTail((struct List *)&__slab_data.sd_SingleAllocations,(struct Node *)ssa);
|
||||||
|
|
||||||
__slab_data.sd_NumSingleAllocations++;
|
__slab_data.sd_NumSingleAllocations++;
|
||||||
|
__slab_data.sd_TotalSingleAllocationSize += total_single_allocation_size;
|
||||||
allocation = &single_allocation[1];
|
|
||||||
|
|
||||||
D(("single allocation succeeded at 0x%08lx (number of single allocations = %lu)", allocation, __slab_data.sd_NumSingleAllocations));
|
D(("single allocation succeeded at 0x%08lx (number of single allocations = %lu)", allocation, __slab_data.sd_NumSingleAllocations));
|
||||||
}
|
}
|
||||||
@ -98,27 +129,34 @@ __slab_allocate(size_t allocation_size)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct MinList * slab_list = NULL;
|
struct MinList * slab_list = NULL;
|
||||||
|
BOOL slab_reused = FALSE;
|
||||||
ULONG entry_size;
|
ULONG entry_size;
|
||||||
ULONG chunk_size;
|
ULONG chunk_size;
|
||||||
int slab_index;
|
int slab_index;
|
||||||
|
|
||||||
D(("allocation size is <= %ld; this will be allocated from a slab",__slab_data.sd_MaxSlabSize));
|
D(("allocation size is <= %ld; this will be allocated from a slab",__slab_data.sd_StandardSlabSize));
|
||||||
|
|
||||||
|
/* Add room for a pointer back to the slab which
|
||||||
|
* the chunk belongs to.
|
||||||
|
*/
|
||||||
|
entry_size = sizeof(*chunk) + allocation_size;
|
||||||
|
|
||||||
/* Chunks must be at least as small as a MinNode, because
|
/* Chunks must be at least as small as a MinNode, because
|
||||||
* that's what we use for keeping track of the chunks which
|
* that's what we use for keeping track of the chunks which
|
||||||
* are available for allocation within each slab.
|
* are available for allocation within each slab.
|
||||||
*/
|
*/
|
||||||
entry_size = allocation_size;
|
|
||||||
if(entry_size < sizeof(struct MinNode))
|
if(entry_size < sizeof(struct MinNode))
|
||||||
entry_size = sizeof(struct MinNode);
|
entry_size = sizeof(struct MinNode);
|
||||||
|
|
||||||
|
D(("final entry size prior to picking slab size = %ld bytes",entry_size));
|
||||||
|
|
||||||
/* Find a slab which keeps track of chunks that are no
|
/* Find a slab which keeps track of chunks that are no
|
||||||
* larger than the amount of memory which needs to be
|
* larger than the amount of memory which needs to be
|
||||||
* allocated. We end up picking the smallest chunk
|
* allocated. We end up picking the smallest chunk
|
||||||
* size that still works.
|
* size that still works.
|
||||||
*/
|
*/
|
||||||
for(slab_index = 2, chunk_size = (1UL << slab_index) ;
|
for(slab_index = 2, chunk_size = (1UL << slab_index) ;
|
||||||
slab_index < 31 ;
|
slab_index < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ;
|
||||||
slab_index++, chunk_size += chunk_size)
|
slab_index++, chunk_size += chunk_size)
|
||||||
{
|
{
|
||||||
if(entry_size <= chunk_size)
|
if(entry_size <= chunk_size)
|
||||||
@ -138,18 +176,28 @@ __slab_allocate(size_t allocation_size)
|
|||||||
|
|
||||||
SHOWVALUE(chunk_size);
|
SHOWVALUE(chunk_size);
|
||||||
|
|
||||||
/* Find the first slab which has a free chunk and use it. */
|
/* The slab list is organized in such a way that the first
|
||||||
for(sn = (struct SlabNode *)slab_list->mlh_Head ;
|
* entry always has a free chunk ready for allocation. If
|
||||||
sn->sn_MinNode.mln_Succ != NULL ;
|
* there is no such free chunk, it means that no other
|
||||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
* slab nodes in this list have any free chunks.
|
||||||
|
*/
|
||||||
|
sn = (struct SlabNode *)slab_list->mlh_Head;
|
||||||
|
|
||||||
|
/* Make sure that the slab list is not empty. */
|
||||||
|
if(sn->sn_MinNode.mln_Succ != NULL)
|
||||||
{
|
{
|
||||||
D(("slab = 0x%08lx, chunk size = %ld", sn, sn->sn_ChunkSize));
|
D(("slab = 0x%08lx, chunk size = %ld", sn, sn->sn_ChunkSize));
|
||||||
|
|
||||||
assert( sn->sn_ChunkSize == chunk_size );
|
assert( sn->sn_ChunkSize == chunk_size );
|
||||||
|
|
||||||
allocation = (struct MemoryNode *)RemHead((struct List *)&sn->sn_FreeList);
|
chunk = (struct SlabChunk *)RemHead((struct List *)&sn->sn_FreeList);
|
||||||
if(allocation != NULL)
|
if(chunk != NULL)
|
||||||
{
|
{
|
||||||
|
/* Keep track of this chunk's parent slab. */
|
||||||
|
chunk->sc_Parent = sn;
|
||||||
|
|
||||||
|
allocation = &chunk[1];
|
||||||
|
|
||||||
D(("allocation succeeded at 0x%08lx in slab 0x%08lx (slab use count = %lu)",allocation,sn,sn->sn_UseCount));
|
D(("allocation succeeded at 0x%08lx in slab 0x%08lx (slab use count = %lu)",allocation,sn,sn->sn_UseCount));
|
||||||
|
|
||||||
/* Was this slab empty before we began using it again? */
|
/* Was this slab empty before we began using it again? */
|
||||||
@ -157,9 +205,11 @@ __slab_allocate(size_t allocation_size)
|
|||||||
{
|
{
|
||||||
D(("slab is no longer empty"));
|
D(("slab is no longer empty"));
|
||||||
|
|
||||||
/* Mark it as no longer empty. */
|
/* Pull it out of the list of slabs available for reuse. */
|
||||||
Remove((struct Node *)&sn->sn_EmptyLink);
|
Remove((struct Node *)&sn->sn_EmptyLink);
|
||||||
|
|
||||||
sn->sn_EmptyDecay = 0;
|
sn->sn_EmptyDecay = 0;
|
||||||
|
sn->sn_NumReused++;
|
||||||
}
|
}
|
||||||
|
|
||||||
sn->sn_UseCount++;
|
sn->sn_UseCount++;
|
||||||
@ -177,8 +227,6 @@ __slab_allocate(size_t allocation_size)
|
|||||||
Remove((struct Node *)sn);
|
Remove((struct Node *)sn);
|
||||||
AddTail((struct List *)slab_list, (struct Node *)sn);
|
AddTail((struct List *)slab_list, (struct Node *)sn);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,13 +260,27 @@ __slab_allocate(size_t allocation_size)
|
|||||||
/* Unlink from list of empty slabs. */
|
/* Unlink from list of empty slabs. */
|
||||||
Remove((struct Node *)free_node);
|
Remove((struct Node *)free_node);
|
||||||
|
|
||||||
/* Unlink from list of slabs which keep chunks
|
/* If the chunk size of the reused slab matches
|
||||||
* of the same size.
|
* exactly what we need then we won't have to
|
||||||
|
* completely reinitialize it again.
|
||||||
*/
|
*/
|
||||||
Remove((struct Node *)sn);
|
if(sn->sn_ChunkSize == chunk_size)
|
||||||
|
{
|
||||||
|
slab_reused = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Unlink from list of slabs which keep chunks
|
||||||
|
* of the same size. It will be added there
|
||||||
|
* again, at a different position.
|
||||||
|
*/
|
||||||
|
Remove((struct Node *)sn);
|
||||||
|
}
|
||||||
|
|
||||||
D(("reusing a slab"));
|
D(("reusing a slab"));
|
||||||
|
|
||||||
|
sn->sn_NumReused++;
|
||||||
|
|
||||||
new_sn = sn;
|
new_sn = sn;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -229,74 +291,102 @@ __slab_allocate(size_t allocation_size)
|
|||||||
*/
|
*/
|
||||||
if(new_sn == NULL)
|
if(new_sn == NULL)
|
||||||
{
|
{
|
||||||
D(("no slab is available for reuse; allocating a new slab (%lu bytes)",sizeof(*sn) + __slab_data.sd_MaxSlabSize));
|
D(("no slab is available for reuse; allocating a new slab (%lu bytes)",sizeof(*new_sn) + __slab_data.sd_StandardSlabSize));
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
|
||||||
#if defined(__amigaos4__)
|
#if defined(__amigaos4__)
|
||||||
{
|
{
|
||||||
new_sn = (struct SlabNode *)AllocVec(sizeof(*sn) + __slab_data.sd_MaxSlabSize,MEMF_PRIVATE);
|
new_sn = (struct SlabNode *)AllocVec(sizeof(*new_sn) + __slab_data.sd_StandardSlabSize,MEMF_PRIVATE);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
new_sn = (struct SlabNode *)AllocVec(sizeof(*sn) + __slab_data.sd_MaxSlabSize,MEMF_ANY);
|
new_sn = (struct SlabNode *)AllocVec(sizeof(*new_sn) + __slab_data.sd_StandardSlabSize,MEMF_ANY);
|
||||||
}
|
}
|
||||||
#endif /* __amigaos4__ */
|
#endif /* __amigaos4__ */
|
||||||
|
|
||||||
|
PROFILE_ON();
|
||||||
|
|
||||||
if(new_sn == NULL)
|
if(new_sn == NULL)
|
||||||
D(("slab allocation failed"));
|
D(("slab allocation failed"));
|
||||||
|
|
||||||
|
/* If this allocation went well, try to free all currently unused
|
||||||
|
* slabs which are ready for purging. This is done so that we don't
|
||||||
|
* keep allocating new memory all the time without cutting back on
|
||||||
|
* unused slabs.
|
||||||
|
*/
|
||||||
purge = TRUE;
|
purge = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(new_sn != NULL)
|
if(new_sn != NULL)
|
||||||
{
|
{
|
||||||
struct MinNode * free_chunk;
|
|
||||||
ULONG num_free_chunks = 0;
|
|
||||||
BYTE * first_byte;
|
|
||||||
BYTE * last_byte;
|
|
||||||
|
|
||||||
D(("setting up slab 0x%08lx", new_sn));
|
D(("setting up slab 0x%08lx", new_sn));
|
||||||
|
|
||||||
assert( chunk_size <= __slab_data.sd_MaxSlabSize );
|
assert( chunk_size <= __slab_data.sd_StandardSlabSize );
|
||||||
|
|
||||||
memset(new_sn,0,sizeof(*new_sn));
|
/* Do we have to completely initialize this slab from scratch? */
|
||||||
|
if(NOT slab_reused)
|
||||||
NewList((struct List *)&new_sn->sn_FreeList);
|
|
||||||
|
|
||||||
/* Split up the slab memory into individual chunks
|
|
||||||
* of the same size and keep track of them
|
|
||||||
* in the free list. The memory managed by
|
|
||||||
* this slab immediately follows the
|
|
||||||
* SlabNode header.
|
|
||||||
*/
|
|
||||||
first_byte = (BYTE *)&new_sn[1];
|
|
||||||
last_byte = &first_byte[__slab_data.sd_MaxSlabSize - chunk_size];
|
|
||||||
|
|
||||||
for(free_chunk = (struct MinNode *)first_byte ;
|
|
||||||
free_chunk <= (struct MinNode *)last_byte;
|
|
||||||
free_chunk = (struct MinNode *)(((BYTE *)free_chunk) + chunk_size))
|
|
||||||
{
|
{
|
||||||
AddTail((struct List *)&new_sn->sn_FreeList, (struct Node *)free_chunk);
|
struct SlabChunk * free_chunk;
|
||||||
num_free_chunks++;
|
ULONG num_free_chunks = 0;
|
||||||
|
BYTE * first_byte;
|
||||||
|
BYTE * last_byte;
|
||||||
|
|
||||||
|
memset(new_sn,0,sizeof(*new_sn));
|
||||||
|
|
||||||
|
NewList((struct List *)&new_sn->sn_FreeList);
|
||||||
|
|
||||||
|
/* This slab has room for new allocations, so make sure that
|
||||||
|
* it goes to the front of the slab list. It will be used
|
||||||
|
* by the next allocation request of this size.
|
||||||
|
*/
|
||||||
|
AddHead((struct List *)slab_list,(struct Node *)new_sn);
|
||||||
|
|
||||||
|
/* Split up the slab memory into individual chunks
|
||||||
|
* of the same size and keep track of them
|
||||||
|
* in the free list. The memory managed by
|
||||||
|
* this slab immediately follows the
|
||||||
|
* SlabNode header.
|
||||||
|
*/
|
||||||
|
first_byte = (BYTE *)&new_sn[1];
|
||||||
|
last_byte = &first_byte[__slab_data.sd_StandardSlabSize - chunk_size];
|
||||||
|
|
||||||
|
for(free_chunk = (struct SlabChunk *)first_byte ;
|
||||||
|
free_chunk <= (struct SlabChunk *)last_byte;
|
||||||
|
free_chunk = (struct SlabChunk *)(((BYTE *)free_chunk) + chunk_size))
|
||||||
|
{
|
||||||
|
AddTail((struct List *)&new_sn->sn_FreeList, (struct Node *)free_chunk);
|
||||||
|
num_free_chunks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_sn->sn_Count = num_free_chunks;
|
||||||
|
new_sn->sn_ChunkSize = chunk_size;
|
||||||
|
|
||||||
|
D(("new slab contains %lu chunks, %lu bytes each",num_free_chunks,chunk_size));
|
||||||
|
}
|
||||||
|
/* This slab was reused and need not be reinitialized from scratch. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert( new_sn->sn_FreeList.mlh_Head != NULL );
|
||||||
|
assert( new_sn->sn_ChunkSize == chunk_size );
|
||||||
|
assert( new_sn->sn_Count == 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
D(("slab contains %lu chunks, %lu bytes each",num_free_chunks,chunk_size));
|
|
||||||
|
|
||||||
/* Grab the first free chunk (there has to be one). */
|
/* Grab the first free chunk (there has to be one). */
|
||||||
allocation = (struct MemoryNode *)RemHead((struct List *)&new_sn->sn_FreeList);
|
chunk = (struct SlabChunk *)RemHead((struct List *)&new_sn->sn_FreeList);
|
||||||
|
|
||||||
D(("allocation succeeded at 0x%08lx in slab 0x%08lx (slab use count = %lu)",allocation,new_sn,new_sn->sn_UseCount+1));
|
/* Keep track of this chunk's parent slab. */
|
||||||
|
chunk->sc_Parent = new_sn;
|
||||||
|
|
||||||
assert( allocation != NULL );
|
assert( chunk != NULL );
|
||||||
|
assert( chunk->sc_Parent == new_sn );
|
||||||
|
|
||||||
/* Set up the new slab and put it where it belongs. */
|
allocation = &chunk[1];
|
||||||
new_sn->sn_EmptyDecay = 0;
|
|
||||||
new_sn->sn_UseCount = 1;
|
|
||||||
new_sn->sn_Count = num_free_chunks;
|
|
||||||
new_sn->sn_ChunkSize = chunk_size;
|
|
||||||
|
|
||||||
SHOWVALUE(new_sn->sn_ChunkSize);
|
/* This slab is now in use. */
|
||||||
|
new_sn->sn_UseCount = 1;
|
||||||
|
|
||||||
AddHead((struct List *)slab_list,(struct Node *)new_sn);
|
D(("allocation succeeded at 0x%08lx in slab 0x%08lx (slab use count = %lu)",allocation,new_sn,new_sn->sn_UseCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mark unused slabs for purging, and purge those which
|
/* Mark unused slabs for purging, and purge those which
|
||||||
@ -304,6 +394,8 @@ __slab_allocate(size_t allocation_size)
|
|||||||
*/
|
*/
|
||||||
if(purge)
|
if(purge)
|
||||||
{
|
{
|
||||||
|
size_t total_purged = 0;
|
||||||
|
|
||||||
D(("purging empty slabs"));
|
D(("purging empty slabs"));
|
||||||
|
|
||||||
for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ;
|
for(free_node = (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head ;
|
||||||
@ -328,12 +420,36 @@ __slab_allocate(size_t allocation_size)
|
|||||||
/* Unlink from list of slabs of the same size. */
|
/* Unlink from list of slabs of the same size. */
|
||||||
Remove((struct Node *)sn);
|
Remove((struct Node *)sn);
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
FreeVec(sn);
|
FreeVec(sn);
|
||||||
|
PROFILE_ON();
|
||||||
|
|
||||||
|
total_purged += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
|
||||||
|
|
||||||
|
/* Stop releasing memory if we reach the threshold. If no
|
||||||
|
* threshold has been set, we will free as much memory
|
||||||
|
* as possible.
|
||||||
|
*/
|
||||||
|
if(__slab_purge_threshold > 0 && total_purged >= __slab_purge_threshold)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
/* Give it another chance. */
|
/* Give it another chance. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sn->sn_EmptyDecay--;
|
sn->sn_EmptyDecay--;
|
||||||
|
|
||||||
|
/* Is this slab ready for reuse now? */
|
||||||
|
if(sn->sn_EmptyDecay == 0)
|
||||||
|
{
|
||||||
|
/* Move it to the front of the list, so that
|
||||||
|
* it will be collected as soon as possible.
|
||||||
|
*/
|
||||||
|
if(free_node != (struct MinNode *)__slab_data.sd_EmptySlabs.mlh_Head)
|
||||||
|
{
|
||||||
|
Remove((struct Node *)free_node);
|
||||||
|
AddHead((struct List *)&__slab_data.sd_EmptySlabs,(struct Node *)free_node);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,26 +469,66 @@ __slab_allocate(size_t allocation_size)
|
|||||||
void
|
void
|
||||||
__slab_free(void * address,size_t allocation_size)
|
__slab_free(void * address,size_t allocation_size)
|
||||||
{
|
{
|
||||||
|
struct SlabChunk * chunk;
|
||||||
|
|
||||||
D(("freeing allocation at 0x%08lx, %lu bytes",address,allocation_size));
|
D(("freeing allocation at 0x%08lx, %lu bytes",address,allocation_size));
|
||||||
|
|
||||||
assert( __slab_data.sd_MaxSlabSize > 0 );
|
assert( __slab_data.sd_StandardSlabSize > 0 );
|
||||||
|
|
||||||
/* Number of bytes allocated exceeds the slab size?
|
/* Number of bytes allocated exceeds the slab size?
|
||||||
* Then the chunk was allocated separately.
|
* Then the chunk was allocated separately.
|
||||||
*/
|
*/
|
||||||
if(allocation_size > __slab_data.sd_MaxSlabSize)
|
if(sizeof(*chunk) + allocation_size > __slab_data.sd_StandardSlabSize)
|
||||||
{
|
{
|
||||||
struct MinNode * mn = address;
|
struct SlabSingleAllocation * ssa = address;
|
||||||
|
ULONG size;
|
||||||
|
|
||||||
D(("allocation size is > %ld; this was stored separately",__slab_data.sd_MaxSlabSize));
|
D(("allocation size is > %ld; this was stored separately",__slab_data.sd_StandardSlabSize));
|
||||||
|
|
||||||
Remove((struct Node *)&mn[-1]);
|
|
||||||
|
|
||||||
FreeVec(&mn[-1]);
|
|
||||||
|
|
||||||
assert( __slab_data.sd_NumSingleAllocations > 0 );
|
assert( __slab_data.sd_NumSingleAllocations > 0 );
|
||||||
|
|
||||||
|
/* Management information (MinNode linkage, size in bytes) precedes
|
||||||
|
* the address returned by malloc(), etc.
|
||||||
|
*/
|
||||||
|
ssa--;
|
||||||
|
|
||||||
|
/* Verify that the allocation is really on the list we
|
||||||
|
* will remove it from.
|
||||||
|
*/
|
||||||
|
#if DEBUG
|
||||||
|
{
|
||||||
|
struct MinNode * mln;
|
||||||
|
BOOL found_allocation_in_list = FALSE;
|
||||||
|
|
||||||
|
for(mln = __slab_data.sd_SingleAllocations.mlh_Head ;
|
||||||
|
mln->mln_Succ != NULL ;
|
||||||
|
mln = mln->mln_Succ)
|
||||||
|
{
|
||||||
|
if(mln == (struct MinNode *)ssa)
|
||||||
|
{
|
||||||
|
found_allocation_in_list = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( found_allocation_in_list );
|
||||||
|
}
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
size = ssa->ssa_Size;
|
||||||
|
|
||||||
|
assert( size > 0 );
|
||||||
|
assert( sizeof(*ssa) + allocation_size == size );
|
||||||
|
assert( size <= __slab_data.sd_TotalSingleAllocationSize );
|
||||||
|
|
||||||
|
Remove((struct Node *)ssa);
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeMem(ssa, size);
|
||||||
|
PROFILE_ON();
|
||||||
|
|
||||||
__slab_data.sd_NumSingleAllocations--;
|
__slab_data.sd_NumSingleAllocations--;
|
||||||
|
__slab_data.sd_TotalSingleAllocationSize -= size;
|
||||||
|
|
||||||
D(("number of single allocations = %ld", __slab_data.sd_NumSingleAllocations));
|
D(("number of single allocations = %ld", __slab_data.sd_NumSingleAllocations));
|
||||||
}
|
}
|
||||||
@ -384,13 +540,17 @@ __slab_free(void * address,size_t allocation_size)
|
|||||||
ULONG chunk_size;
|
ULONG chunk_size;
|
||||||
int slab_index;
|
int slab_index;
|
||||||
|
|
||||||
D(("allocation size is <= %ld; this was allocated from a slab",__slab_data.sd_MaxSlabSize));
|
D(("allocation size is <= %ld; this was allocated from a slab",__slab_data.sd_StandardSlabSize));
|
||||||
|
|
||||||
|
/* Add room for a pointer back to the slab which
|
||||||
|
* the chunk belongs to.
|
||||||
|
*/
|
||||||
|
entry_size = sizeof(*chunk) + allocation_size;
|
||||||
|
|
||||||
/* Chunks must be at least as small as a MinNode, because
|
/* Chunks must be at least as small as a MinNode, because
|
||||||
* that's what we use for keeping track of the chunks which
|
* that's what we use for keeping track of the chunks which
|
||||||
* are available for allocation within each slab.
|
* are available for allocation within each slab.
|
||||||
*/
|
*/
|
||||||
entry_size = allocation_size;
|
|
||||||
if(entry_size < sizeof(struct MinNode))
|
if(entry_size < sizeof(struct MinNode))
|
||||||
entry_size = sizeof(struct MinNode);
|
entry_size = sizeof(struct MinNode);
|
||||||
|
|
||||||
@ -400,7 +560,7 @@ __slab_free(void * address,size_t allocation_size)
|
|||||||
* size that still works.
|
* size that still works.
|
||||||
*/
|
*/
|
||||||
for(slab_index = 2, chunk_size = (1UL << slab_index) ;
|
for(slab_index = 2, chunk_size = (1UL << slab_index) ;
|
||||||
slab_index < 31 ;
|
slab_index < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ;
|
||||||
slab_index++, chunk_size += chunk_size)
|
slab_index++, chunk_size += chunk_size)
|
||||||
{
|
{
|
||||||
if(entry_size <= chunk_size)
|
if(entry_size <= chunk_size)
|
||||||
@ -414,69 +574,122 @@ __slab_free(void * address,size_t allocation_size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the slab which contains the memory chunk. */
|
/* Pick the slab which contains the memory chunk. */
|
||||||
if(slab_list != NULL)
|
if(slab_list != NULL)
|
||||||
{
|
{
|
||||||
const size_t usable_range = __slab_data.sd_MaxSlabSize - chunk_size;
|
|
||||||
struct SlabNode * sn;
|
struct SlabNode * sn;
|
||||||
BYTE * first_byte;
|
|
||||||
BYTE * last_byte;
|
|
||||||
BOOL freed = FALSE;
|
|
||||||
|
|
||||||
assert( chunk_size <= __slab_data.sd_MaxSlabSize );
|
assert( chunk_size <= __slab_data.sd_StandardSlabSize );
|
||||||
|
|
||||||
for(sn = (struct SlabNode *)slab_list->mlh_Head ;
|
/* The pointer back to the slab which this chunk belongs
|
||||||
sn->sn_MinNode.mln_Succ != NULL ;
|
* to precedes the address which __slab_allocate()
|
||||||
sn = (struct SlabNode *)sn->sn_MinNode.mln_Succ)
|
* returned.
|
||||||
|
*/
|
||||||
|
chunk = address;
|
||||||
|
chunk--;
|
||||||
|
|
||||||
|
sn = chunk->sc_Parent;
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
{
|
{
|
||||||
SHOWVALUE(sn->sn_ChunkSize);
|
struct SlabNode * other_sn;
|
||||||
|
BOOL slab_found = FALSE;
|
||||||
|
BOOL chunk_found = FALSE;
|
||||||
|
|
||||||
assert( sn->sn_ChunkSize == chunk_size );
|
for(other_sn = (struct SlabNode *)slab_list->mlh_Head ;
|
||||||
|
other_sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
first_byte = (BYTE *)&sn[1];
|
other_sn = (struct SlabNode *)other_sn->sn_MinNode.mln_Succ)
|
||||||
last_byte = &first_byte[usable_range];
|
|
||||||
|
|
||||||
/* Is this where the chunk belongs? */
|
|
||||||
if(first_byte <= (BYTE *)address && (BYTE *)address <= last_byte)
|
|
||||||
{
|
{
|
||||||
D(("allocation is part of slab 0x%08lx (slab use count = %ld)",sn,sn->sn_UseCount));
|
if(other_sn == sn)
|
||||||
|
|
||||||
AddTail((struct List *)&sn->sn_FreeList, (struct Node *)address);
|
|
||||||
|
|
||||||
assert( sn->sn_UseCount > 0 );
|
|
||||||
|
|
||||||
sn->sn_UseCount--;
|
|
||||||
|
|
||||||
/* If this slab is empty, mark it as unused and
|
|
||||||
* allow it to be purged.
|
|
||||||
*/
|
|
||||||
if(sn->sn_UseCount == 0)
|
|
||||||
{
|
{
|
||||||
D(("slab is now empty"));
|
slab_found = TRUE;
|
||||||
|
break;
|
||||||
AddTail((struct List *)&__slab_data.sd_EmptySlabs,(struct Node *)&sn->sn_EmptyLink);
|
|
||||||
sn->sn_EmptyDecay = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This slab now has room. Move it to front of the list
|
|
||||||
* so that searching for a free chunk will pick it
|
|
||||||
* first.
|
|
||||||
*/
|
|
||||||
if(sn != (struct SlabNode *)slab_list->mlh_Head)
|
|
||||||
{
|
|
||||||
D(("moving slab to the head of the list"));
|
|
||||||
|
|
||||||
Remove((struct Node *)sn);
|
|
||||||
AddHead((struct List *)slab_list, (struct Node *)sn);
|
|
||||||
}
|
|
||||||
|
|
||||||
freed = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert( slab_found );
|
||||||
|
|
||||||
|
if(slab_found)
|
||||||
|
{
|
||||||
|
struct MinNode * free_chunk;
|
||||||
|
BYTE * first_byte;
|
||||||
|
BYTE * last_byte;
|
||||||
|
|
||||||
|
first_byte = (BYTE *)&sn[1];
|
||||||
|
last_byte = &first_byte[__slab_data.sd_StandardSlabSize - chunk_size];
|
||||||
|
|
||||||
|
for(free_chunk = (struct MinNode *)first_byte ;
|
||||||
|
free_chunk <= (struct MinNode *)last_byte;
|
||||||
|
free_chunk = (struct MinNode *)(((BYTE *)free_chunk) + chunk_size))
|
||||||
|
{
|
||||||
|
if(free_chunk == (struct MinNode *)chunk)
|
||||||
|
{
|
||||||
|
chunk_found = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( chunk_found );
|
||||||
|
}
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
SHOWVALUE(sn->sn_ChunkSize);
|
||||||
|
|
||||||
|
assert( sn->sn_ChunkSize != 0 );
|
||||||
|
|
||||||
|
assert( sn->sn_ChunkSize == chunk_size );
|
||||||
|
|
||||||
|
D(("allocation is part of slab 0x%08lx (slab use count = %ld)",sn,sn->sn_UseCount));
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
{
|
||||||
|
struct MinNode * mln;
|
||||||
|
BOOL chunk_already_free = FALSE;
|
||||||
|
|
||||||
|
for(mln = sn->sn_FreeList.mlh_Head ;
|
||||||
|
mln->mln_Succ != NULL ;
|
||||||
|
mln = mln->mln_Succ)
|
||||||
|
{
|
||||||
|
if(mln == (struct MinNode *)chunk)
|
||||||
|
{
|
||||||
|
chunk_already_free = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( NOT chunk_already_free );
|
||||||
|
}
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
AddHead((struct List *)&sn->sn_FreeList, (struct Node *)chunk);
|
||||||
|
|
||||||
|
assert( sn->sn_UseCount > 0 );
|
||||||
|
|
||||||
|
sn->sn_UseCount--;
|
||||||
|
|
||||||
|
/* If this slab is empty, mark it as unused and
|
||||||
|
* allow it to be purged.
|
||||||
|
*/
|
||||||
|
if(sn->sn_UseCount == 0)
|
||||||
|
{
|
||||||
|
D(("slab is now empty"));
|
||||||
|
|
||||||
|
AddTail((struct List *)&__slab_data.sd_EmptySlabs,(struct Node *)&sn->sn_EmptyLink);
|
||||||
|
sn->sn_EmptyDecay = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!freed)
|
/* This slab now has room. Move it to front of the list
|
||||||
D(("allocation at 0x%08lx could not be freed",address));
|
* so that searching for a free chunk will pick it
|
||||||
|
* first.
|
||||||
|
*/
|
||||||
|
if(sn != (struct SlabNode *)slab_list->mlh_Head)
|
||||||
|
{
|
||||||
|
D(("moving slab to the head of the list"));
|
||||||
|
|
||||||
|
Remove((struct Node *)sn);
|
||||||
|
AddHead((struct List *)slab_list, (struct Node *)sn);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -490,15 +703,22 @@ __slab_free(void * address,size_t allocation_size)
|
|||||||
void
|
void
|
||||||
__slab_init(size_t slab_size)
|
__slab_init(size_t slab_size)
|
||||||
{
|
{
|
||||||
|
const size_t max_slab_size = (1UL << (NUM_ENTRIES(__slab_data.sd_Slabs)));
|
||||||
size_t size;
|
size_t size;
|
||||||
|
|
||||||
SETDEBUGLEVEL(2);
|
SETDEBUGLEVEL(2);
|
||||||
|
|
||||||
D(("slab_size = %ld",slab_size));
|
D(("slab_size = %ld",slab_size));
|
||||||
|
|
||||||
|
/* Do not allow for a slab size that is larger than
|
||||||
|
* what we support.
|
||||||
|
*/
|
||||||
|
if(slab_size > max_slab_size)
|
||||||
|
slab_size = max_slab_size;
|
||||||
|
|
||||||
/* If the maximum allocation size to be made from the slab
|
/* If the maximum allocation size to be made from the slab
|
||||||
* is not already a power of 2, round it up. We do not
|
* is not already a power of 2, round it up. We do not
|
||||||
* support allocations larger than 2^31, and the maximum
|
* support allocations larger than 2^17, and the maximum
|
||||||
* allocation size should be much smaller.
|
* allocation size should be much smaller.
|
||||||
*
|
*
|
||||||
* Note that the maximum allocation size also defines the
|
* Note that the maximum allocation size also defines the
|
||||||
@ -517,67 +737,127 @@ __slab_init(size_t slab_size)
|
|||||||
|
|
||||||
D(("activating slab allocator"));
|
D(("activating slab allocator"));
|
||||||
|
|
||||||
|
memset(&__slab_data,0,sizeof(__slab_data));
|
||||||
|
|
||||||
assert( size <= slab_size );
|
assert( size <= slab_size );
|
||||||
|
|
||||||
/* Start with an empty list of slabs for each chunk size. */
|
/* Start with an empty list of slabs for each chunk size. */
|
||||||
for(i = 0 ; i < 31 ; i++)
|
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||||
NewList((struct List *)&__slab_data.sd_Slabs[i]);
|
NewList((struct List *)&__slab_data.sd_Slabs[i]);
|
||||||
|
|
||||||
NewList((struct List *)&__slab_data.sd_SingleAllocations);
|
NewList((struct List *)&__slab_data.sd_SingleAllocations);
|
||||||
NewList((struct List *)&__slab_data.sd_EmptySlabs);
|
NewList((struct List *)&__slab_data.sd_EmptySlabs);
|
||||||
|
|
||||||
__slab_data.sd_MaxSlabSize = size;
|
__slab_data.sd_StandardSlabSize = size;
|
||||||
__slab_data.sd_InUse = TRUE;
|
__slab_data.sd_InUse = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
|
||||||
|
static int print_json(void * ignore,const char * buffer,size_t len)
|
||||||
|
{
|
||||||
|
extern void kputs(const char * str);
|
||||||
|
|
||||||
|
kputs(buffer);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
__slab_exit(void)
|
__slab_exit(void)
|
||||||
{
|
{
|
||||||
struct SlabNode * sn;
|
|
||||||
struct SlabNode * sn_next;
|
|
||||||
struct MinNode * mn;
|
|
||||||
struct MinNode * mn_next;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
ENTER();
|
ENTER();
|
||||||
|
|
||||||
D(("freeing slabs"));
|
if(__slab_data.sd_InUse)
|
||||||
|
|
||||||
/* Free the memory allocated for each slab. */
|
|
||||||
for(i = 0 ; i < 31 ; i++)
|
|
||||||
{
|
{
|
||||||
if(__slab_data.sd_Slabs[i].mlh_Head->mln_Succ != NULL)
|
struct SlabSingleAllocation * ssa;
|
||||||
D(("freeing slab #%ld (%lu bytes per chunk)", i, (1UL << i)));
|
struct SlabNode * sn;
|
||||||
|
struct SlabNode * sn_next;
|
||||||
|
struct MinNode * mn;
|
||||||
|
struct MinNode * mn_next;
|
||||||
|
size_t slab_count = 0, total_slab_size = 0;
|
||||||
|
size_t single_allocation_count = 0, total_single_allocation_size = 0;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head ;
|
#if DEBUG
|
||||||
sn->sn_MinNode.mln_Succ != NULL ;
|
|
||||||
sn = sn_next)
|
|
||||||
{
|
{
|
||||||
sn_next = (struct SlabNode *)sn->sn_MinNode.mln_Succ;
|
kprintf("---BEGIN JSON DATA ---\n");
|
||||||
|
|
||||||
FreeVec(sn);
|
__get_slab_stats(NULL, print_json);
|
||||||
|
|
||||||
|
kprintf("---END JSON DATA ---\n\n");
|
||||||
}
|
}
|
||||||
|
#endif /* DEBUG */
|
||||||
|
|
||||||
|
D(("freeing slabs"));
|
||||||
|
|
||||||
|
/* Free the memory allocated for each slab. */
|
||||||
|
for(i = 0 ; i < (int)NUM_ENTRIES(__slab_data.sd_Slabs) ; i++)
|
||||||
|
{
|
||||||
|
if(__slab_data.sd_Slabs[i].mlh_Head->mln_Succ != NULL)
|
||||||
|
D(("freeing slab slot #%ld (%lu bytes per chunk)", i, (1UL << i)));
|
||||||
|
|
||||||
|
for(sn = (struct SlabNode *)__slab_data.sd_Slabs[i].mlh_Head, j = 0 ;
|
||||||
|
sn->sn_MinNode.mln_Succ != NULL ;
|
||||||
|
sn = sn_next)
|
||||||
|
{
|
||||||
|
sn_next = (struct SlabNode *)sn->sn_MinNode.mln_Succ;
|
||||||
|
|
||||||
|
D((" slab #%ld.%ld at 0x%08lx",i, ++j, sn));
|
||||||
|
D((" fragmentation = %ld%%",100 * (__slab_data.sd_StandardSlabSize - sn->sn_Count * sn->sn_ChunkSize) / __slab_data.sd_StandardSlabSize));
|
||||||
|
D((" total space used = %ld (%ld%%)",sn->sn_UseCount * sn->sn_ChunkSize, 100 * sn->sn_UseCount / sn->sn_Count));
|
||||||
|
D((" number of chunks total = %ld",sn->sn_Count));
|
||||||
|
D((" number of chunks used = %ld%s",sn->sn_UseCount,sn->sn_UseCount == 0 ? " (empty)" : (sn->sn_UseCount == sn->sn_Count) ? " (full)" : ""));
|
||||||
|
D((" how often reused = %ld",sn->sn_NumReused));
|
||||||
|
|
||||||
|
total_slab_size += sizeof(*sn) + __slab_data.sd_StandardSlabSize;
|
||||||
|
slab_count++;
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeVec(sn);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(slab_count > 0)
|
||||||
|
D(("number of slabs = %ld, total slab size = %ld bytes",slab_count, total_slab_size));
|
||||||
|
|
||||||
|
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
|
||||||
|
D(("freeing single allocations"));
|
||||||
|
|
||||||
|
/* Free the memory allocated for each allocation which did not
|
||||||
|
* go into a slab.
|
||||||
|
*/
|
||||||
|
for(mn = __slab_data.sd_SingleAllocations.mlh_Head, j = 0 ;
|
||||||
|
mn->mln_Succ != NULL ;
|
||||||
|
mn = mn_next)
|
||||||
|
{
|
||||||
|
mn_next = mn->mln_Succ;
|
||||||
|
|
||||||
|
ssa = (struct SlabSingleAllocation *)mn;
|
||||||
|
|
||||||
|
D((" allocation #%ld at 0x%08lx, %lu bytes", ++j, ssa, ssa->ssa_Size));
|
||||||
|
|
||||||
|
total_single_allocation_size += ssa->ssa_Size;
|
||||||
|
single_allocation_count++;
|
||||||
|
|
||||||
|
PROFILE_OFF();
|
||||||
|
FreeMem(ssa, ssa->ssa_Size);
|
||||||
|
PROFILE_ON();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(single_allocation_count > 0)
|
||||||
|
D(("number of single allocations = %ld, total single allocation size = %ld", single_allocation_count, total_single_allocation_size));
|
||||||
|
|
||||||
|
__slab_data.sd_InUse = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(__slab_data.sd_SingleAllocations.mlh_Head->mln_Succ != NULL)
|
|
||||||
D(("freeing single allocations"));
|
|
||||||
|
|
||||||
/* Free the memory allocated for each allocation which did not
|
|
||||||
* go into a slab.
|
|
||||||
*/
|
|
||||||
for(mn = __slab_data.sd_SingleAllocations.mlh_Head ;
|
|
||||||
mn->mln_Succ != NULL ;
|
|
||||||
mn = mn_next)
|
|
||||||
{
|
|
||||||
mn_next = mn->mln_Succ;
|
|
||||||
|
|
||||||
FreeVec(mn);
|
|
||||||
}
|
|
||||||
|
|
||||||
__slab_data.sd_InUse = FALSE;
|
|
||||||
|
|
||||||
LEAVE();
|
LEAVE();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,4 +35,4 @@
|
|||||||
|
|
||||||
/****************************************************************************/
|
/****************************************************************************/
|
||||||
|
|
||||||
ULONG NOCOMMON __slab_max_size;
|
unsigned long __slab_max_size;
|
||||||
|
|||||||
38
library/stdlib_slab_purge_threshold.c
Normal file
38
library/stdlib_slab_purge_threshold.c
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* :ts=4
|
||||||
|
*
|
||||||
|
* Portable ISO 'C' (1994) runtime library for the Amiga computer
|
||||||
|
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Neither the name of Olaf Barthel nor the names of contributors
|
||||||
|
* may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _STDLIB_HEADERS_H
|
||||||
|
#include "stdlib_headers.h"
|
||||||
|
#endif /* _STDLIB_HEADERS_H */
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
unsigned long __slab_purge_threshold;
|
||||||
@ -184,7 +184,6 @@ __getcwd(char * buffer,size_t buffer_size,const char *file,int line)
|
|||||||
if(__unix_path_semantics)
|
if(__unix_path_semantics)
|
||||||
{
|
{
|
||||||
const char * path_name = buffer;
|
const char * path_name = buffer;
|
||||||
size_t len;
|
|
||||||
|
|
||||||
if(__translate_amiga_to_unix_path_name(&path_name,&buffer_nti) != 0)
|
if(__translate_amiga_to_unix_path_name(&path_name,&buffer_nti) != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#define VERSION 1
|
#define VERSION 1
|
||||||
#define REVISION 207
|
#define REVISION 214
|
||||||
#define DATE "18.11.2016"
|
#define DATE "27.4.2017"
|
||||||
#define VERS "unix.lib 1.207"
|
#define VERS "unix.lib 1.214"
|
||||||
#define VSTRING "unix.lib 1.207 (18.11.2016)\r\n"
|
#define VSTRING "unix.lib 1.214 (27.4.2017)\r\n"
|
||||||
#define VERSTAG "\0$VER: unix.lib 1.207 (18.11.2016)"
|
#define VERSTAG "\0$VER: unix.lib 1.214 (27.4.2017)"
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
207
|
214
|
||||||
|
|||||||
@ -13,7 +13,7 @@ DELETE = delete all quiet
|
|||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
@echo "Compiling $<"
|
@echo "Compiling $<"
|
||||||
@$(CC) -c $(CFLAGS) $<
|
$(CC) -c $(CFLAGS) $<
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ WARNINGS = \
|
|||||||
|
|
||||||
INCLUDE = -I../library/include
|
INCLUDE = -I../library/include
|
||||||
LIB = -L../library/lib
|
LIB = -L../library/lib
|
||||||
OPTIONS = -DNDEBUG -fno-builtin -fwritable-strings -DNO_INLINE_STDARG -DIEEE_FLOATING_POINT_SUPPORT
|
OPTIONS = -DNDEBUG -fno-builtin -fwritable-strings -DNO_INLINE_STDARG -DIEEE_FLOATING_POINT_SUPPORT -DVERBOSE=1
|
||||||
#OPTIONS = -D__MEM_DEBUG -fno-builtin
|
#OPTIONS = -D__MEM_DEBUG -fno-builtin
|
||||||
#OPTIONS = -DDEBUG -D__MEM_DEBUG -DNO_INLINE_STDARG -fno-builtin
|
#OPTIONS = -DDEBUG -D__MEM_DEBUG -DNO_INLINE_STDARG -fno-builtin
|
||||||
OPTIMIZE = -O
|
OPTIMIZE = -O
|
||||||
@ -49,13 +49,15 @@ LIBS = -lm -lc -lgcc
|
|||||||
all: test fgets_test iotest sscanf_test printf_test sprintf_test \
|
all: test fgets_test iotest sscanf_test printf_test sprintf_test \
|
||||||
stack_size_test translate_test strtok_test uname simple \
|
stack_size_test translate_test strtok_test uname simple \
|
||||||
fstat_stdout_test simple_sprintf date_test sscanf_64 factorial \
|
fstat_stdout_test simple_sprintf date_test sscanf_64 factorial \
|
||||||
execvp_test setlocale rand fstat_test base_dir_nametest
|
execvp_test setlocale rand fstat_test base_dir_nametest \
|
||||||
|
malloc-test slab-test
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(DELETE) #?.o #?.map test fgets_test iotest sscanf_test printf_test \
|
$(DELETE) #?.o #?.map test fgets_test iotest sscanf_test printf_test \
|
||||||
sprintf_test stack_size_test translate_test strtok_test uname \
|
sprintf_test stack_size_test translate_test strtok_test uname \
|
||||||
simple fstat_stdout_test fstat_test simple_sprintf date_test sscanf_64 \
|
simple fstat_stdout_test fstat_test simple_sprintf date_test sscanf_64 \
|
||||||
factorial execvp_test setlocale rand base_dir_nametest
|
factorial execvp_test setlocale rand base_dir_nametest \
|
||||||
|
malloc-test slab-test
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
@ -143,6 +145,14 @@ rand : rand.o
|
|||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ rand.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ rand.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
|
malloc-test : malloc-test.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
$(CC) $(CFLAGS) -o $@ malloc-test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
|
slab-test : slab-test.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
$(CC) $(CFLAGS) -o $@ slab-test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
mkid:
|
mkid:
|
||||||
|
|||||||
@ -21,104 +21,120 @@ WARNINGS = \
|
|||||||
-Wall -W -Wshadow -Wpointer-arith -Wsign-compare -Wmissing-prototypes \
|
-Wall -W -Wshadow -Wpointer-arith -Wsign-compare -Wmissing-prototypes \
|
||||||
-Wundef -Wbad-function-cast -Wmissing-declarations -Wconversion
|
-Wundef -Wbad-function-cast -Wmissing-declarations -Wconversion
|
||||||
|
|
||||||
|
V = /V
|
||||||
INCLUDE = -I$(V)/include -I../library/include
|
INCLUDE = -I$(V)/include -I../library/include
|
||||||
LIB = -L../library/lib
|
#OPTIONS = -D__MEM_DEBUG
|
||||||
#OPTIONS = -DNDEBUG -fno-builtin -DNO_INLINE_STDARG -DIEEE_FLOATING_POINT_SUPPORT
|
#OPTIONS = -DDEBUG
|
||||||
#OPTIONS = -D__MEM_DEBUG -fno-builtin
|
OPTIONS = -DNDEBUG
|
||||||
OPTIONS = -DDEBUG -DNO_INLINE_STDARG -fno-builtin
|
#OPTIMIZE = -O3
|
||||||
#OPTIMIZE = -O
|
#DEBUG = -ggdb
|
||||||
#OPTIMIZE = -O2 -fomit-frame-pointer
|
|
||||||
DEBUG = -ggdb
|
|
||||||
|
|
||||||
CFLAGS = $(WARNINGS) $(OPTIMIZE) $(DEBUG) $(OPTIONS) $(CODE_TYPE) $(INCLUDE) $(LIB)
|
# Note: Because the matching startup code needs to be used for
|
||||||
|
# correctly linking the test programs, you need to make sure
|
||||||
|
# that the current development version of clib2 is visible
|
||||||
|
# where the linker expects it (soft link). Some more tuning would be
|
||||||
|
# required here because you really should not need to tinker
|
||||||
|
# with the location of library and the options "-L. -L../library/lib"
|
||||||
|
# should be sufficient.
|
||||||
|
|
||||||
|
CFLAGS = -mcrt=clib2 -fno-builtin $(WARNINGS) $(OPTIMIZE) $(DEBUG) $(OPTIONS) $(INCLUDE)
|
||||||
|
LFLAGS = -Wl,-d
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
LIBS = -lm -lc -ldebug -lgcc
|
LIBS = -ldebug -lm -lc
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
all: test fgets_test iotest sscanf_test printf_test sprintf_test \
|
all: test fgets_test iotest sscanf_test printf_test sprintf_test \
|
||||||
stack_size_test translate_test strtok_test uname simple \
|
stack_size_test translate_test strtok_test uname simple \
|
||||||
fstat_stdout_test simple_sprintf date_test sscanf_64 \
|
fstat_stdout_test simple_sprintf date_test sscanf_64 \
|
||||||
factorial setlocale
|
factorial setlocale rand malloc-test slab-test
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$(DELETE) *.o *.map test fgets_test iotest sscanf_test printf_test \
|
$(DELETE) *.o *.map test fgets_test iotest sscanf_test printf_test \
|
||||||
sprintf_test stack_size_test translate_test strtok_test \
|
sprintf_test stack_size_test translate_test strtok_test \
|
||||||
uname simple fstat_stdout_test simple_sprintf date_test \
|
uname simple fstat_stdout_test simple_sprintf date_test \
|
||||||
sscanf_64 factorial setlocale rand
|
sscanf_64 factorial setlocale rand malloc-test slab-test
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
setlocale : setlocale.o
|
setlocale : setlocale.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ setlocale.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ setlocale.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
test : test.o
|
test : test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
date_test : date_test.o
|
date_test : date_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
fgets_test : fgets_test.o
|
fgets_test : fgets_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ fgets_test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ fgets_test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
strtok_test : strtok_test.o
|
strtok_test : strtok_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ strtok_test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ strtok_test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
iotest : iotest.o
|
iotest : iotest.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ iotest.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ iotest.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
sscanf_test : sscanf_test.o
|
sscanf_test : sscanf_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ sscanf_test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ sscanf_test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
printf_test : printf_test.o
|
printf_test : printf_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ printf_test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ printf_test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
sprintf_test : sprintf_test.o
|
sprintf_test : sprintf_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ sprintf_test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ sprintf_test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
stack_size_test : stack_size_test.o
|
stack_size_test : stack_size_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ stack_size_test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ stack_size_test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
translate_test : translate_test.o
|
translate_test : translate_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ translate_test.o -lunix $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ translate_test.o -lunix $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
uname : uname.o
|
uname : uname.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ uname.o -lunix $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ uname.o -lunix $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
simple : simple.o
|
simple : simple.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ simple.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ simple.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
fstat_stdout_test : fstat_stdout_test.o
|
fstat_stdout_test : fstat_stdout_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) $(CFLAGS) -o $@ fstat_stdout_test.o $(LIBS) -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ fstat_stdout_test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
simple_sprintf : simple_sprintf.o
|
simple_sprintf : simple_sprintf.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) -nostdlib $(CFLAGS) -o $@ simple_sprintf.o -lc -lgcc -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -nostdlib -o $@ simple_sprintf.o -lc -lgcc $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
sscanf_64 : sscanf_64.o
|
sscanf_64 : sscanf_64.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) -nostdlib $(CFLAGS) -o $@ sscanf_64.o -lc -lgcc -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ sscanf_64.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
factorial : factorial.o
|
factorial : factorial.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) -nostdlib $(CFLAGS) -o $@ factorial.o -lc -lgcc -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ factorial.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
rand : rand.o
|
rand : rand.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
$(CC) -nostdlib $(CFLAGS) -o $@ rand.o -lc -lgcc -Wl,--cref,-M,-Map=$@.map
|
$(CC) $(CFLAGS) -o $@ rand.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
|
malloc-test : malloc-test.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
$(CC) $(CFLAGS) -o $@ malloc-test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|
||||||
|
slab-test : slab-test.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
$(CC) $(CFLAGS) -o $@ slab-test.o $(LIBS) $(LFLAGS) -Wl,--cref,-M,-Map=$@.map
|
||||||
|
|||||||
489
test_programs/malloc-test.c
Normal file
489
test_programs/malloc-test.c
Normal file
@ -0,0 +1,489 @@
|
|||||||
|
/* malloc-test.c
|
||||||
|
* by Wolfram Gloger 1995, 1996
|
||||||
|
*
|
||||||
|
* This program is provided `as is', there is no warranty.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__STDC__)
|
||||||
|
#define __STDC__ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MEMORY
|
||||||
|
#define MEMORY 4000000l
|
||||||
|
#endif
|
||||||
|
#ifndef BINS_MAX
|
||||||
|
#define BINS_MAX 32768
|
||||||
|
#endif
|
||||||
|
#define SBINS_MAX 1024
|
||||||
|
#define SIZE 4024
|
||||||
|
#define I_MAX 5000
|
||||||
|
#ifndef I_AVERAGE
|
||||||
|
#define I_AVERAGE 200
|
||||||
|
#endif
|
||||||
|
#define ACTIONS_MAX 50
|
||||||
|
#ifndef SBRK_AVG
|
||||||
|
#define SBRK_AVG 0
|
||||||
|
#endif
|
||||||
|
#ifndef MMAP_THRESH
|
||||||
|
#define MMAP_THRESH 0
|
||||||
|
#endif
|
||||||
|
#ifndef TEST
|
||||||
|
#define TEST 4 /* minimal testing */
|
||||||
|
#endif
|
||||||
|
#ifndef TEST_INC
|
||||||
|
#define TEST_INC 2047
|
||||||
|
#endif
|
||||||
|
#if defined(__i386__) || defined(__sparc__) || defined(mips) || defined(_WIN32)
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#elif defined(__alpha__)
|
||||||
|
#define PAGE_SIZE 8192
|
||||||
|
#elif defined(__SVR4)
|
||||||
|
#define PAGE_SIZE 8192
|
||||||
|
#else
|
||||||
|
#define PAGE_SIZE 4096 /* default */
|
||||||
|
#endif
|
||||||
|
#define RANDOM(s) (lran2(0) % (s))
|
||||||
|
|
||||||
|
/* All probabilities are parts in 1024. */
|
||||||
|
#ifndef PROB_MEMALIGN
|
||||||
|
#define PROB_MEMALIGN 0
|
||||||
|
#endif
|
||||||
|
#ifndef PROB_REALLOC
|
||||||
|
#define PROB_REALLOC 48
|
||||||
|
#endif
|
||||||
|
#ifndef PROB_CALLOC
|
||||||
|
#define PROB_CALLOC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct bin {
|
||||||
|
unsigned char *ptr;
|
||||||
|
unsigned long size;
|
||||||
|
} m[BINS_MAX], sm[SBINS_MAX];
|
||||||
|
|
||||||
|
unsigned long size = SIZE, bins=0, sbins=0;
|
||||||
|
unsigned long total_size=0, total_size_max=0;
|
||||||
|
unsigned char *base_ptr;
|
||||||
|
unsigned long base_save;
|
||||||
|
|
||||||
|
long
|
||||||
|
#if __STDC__
|
||||||
|
lran2(long seed)
|
||||||
|
#else
|
||||||
|
lran2(seed) long seed;
|
||||||
|
#endif
|
||||||
|
#define LRAN2_MAX 714025l /* constants for portable */
|
||||||
|
#define IA 1366l /* random number generator */
|
||||||
|
#define IC 150889l /* (see Numerical Recipes p. 211) */
|
||||||
|
{
|
||||||
|
static int first = 1;
|
||||||
|
static long x, y, v[97];
|
||||||
|
int j;
|
||||||
|
|
||||||
|
if(seed || first) {
|
||||||
|
first = 0;
|
||||||
|
x = (IC - seed) % LRAN2_MAX;
|
||||||
|
if(x < 0) x = -x;
|
||||||
|
for(j=0; j<97; j++) {
|
||||||
|
x = (IA*x + IC) % LRAN2_MAX;
|
||||||
|
v[j] = x;
|
||||||
|
}
|
||||||
|
x = (IA*x + IC) % LRAN2_MAX;
|
||||||
|
y = x;
|
||||||
|
}
|
||||||
|
j = y % 97;
|
||||||
|
y = v[j];
|
||||||
|
x = (IA*x + IC) % LRAN2_MAX;
|
||||||
|
v[j] = x;
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
#undef IA
|
||||||
|
#undef IC
|
||||||
|
|
||||||
|
void
|
||||||
|
#if __STDC__
|
||||||
|
mem_init(unsigned char *ptr, unsigned long size)
|
||||||
|
#else
|
||||||
|
mem_init(ptr, size) unsigned char *ptr; unsigned long size;
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
unsigned long i, j;
|
||||||
|
|
||||||
|
if(size == 0) return;
|
||||||
|
if(size > sizeof(unsigned long)) {
|
||||||
|
/* Try the complete initial word. */
|
||||||
|
*(unsigned long *)ptr = (unsigned long)ptr ^ size;
|
||||||
|
i = TEST_INC;
|
||||||
|
} else
|
||||||
|
i = 0;
|
||||||
|
for(; i<size; i+=TEST_INC) {
|
||||||
|
j = (unsigned long)ptr ^ i;
|
||||||
|
ptr[i] = ((j ^ (j>>8)) & 0xFF);
|
||||||
|
}
|
||||||
|
j = (unsigned long)ptr ^ (size-1);
|
||||||
|
ptr[size-1] = ((j ^ (j>>8)) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
#if __STDC__
|
||||||
|
mem_check(unsigned char *ptr, unsigned long size)
|
||||||
|
#else
|
||||||
|
mem_check(ptr, size) unsigned char *ptr; unsigned long size;
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
unsigned long i, j;
|
||||||
|
|
||||||
|
if(size == 0) return 0;
|
||||||
|
if(size > sizeof(unsigned long)) {
|
||||||
|
if(*(unsigned long *)ptr != ((unsigned long)ptr ^ size)) {
|
||||||
|
printf ("failed size check: expected %x, found %x!\n",
|
||||||
|
((unsigned long) ptr ^ size), *(unsigned long *) ptr);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
i = TEST_INC;
|
||||||
|
} else
|
||||||
|
i = 0;
|
||||||
|
for(; i<size; i+=TEST_INC) {
|
||||||
|
j = (unsigned long)ptr ^ i;
|
||||||
|
if(ptr[i] != ((j ^ (j>>8)) & 0xFF)) return 2;
|
||||||
|
}
|
||||||
|
j = (unsigned long)ptr ^ (size-1);
|
||||||
|
if(ptr[size-1] != ((j ^ (j>>8)) & 0xFF)) {
|
||||||
|
printf ("failed last byte check: expected %x, found %x!\n",
|
||||||
|
((unsigned long) ((j ^ (j>>8)) & 0xFF)), ptr[size-1]);
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long
|
||||||
|
#if __STDC__
|
||||||
|
random_size(long max)
|
||||||
|
#else
|
||||||
|
random_size(max) long max;
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
long r1, r2, r, max_pages;
|
||||||
|
|
||||||
|
max_pages = max/PAGE_SIZE;
|
||||||
|
if(max_pages > 0) {
|
||||||
|
r1 = RANDOM(1024);
|
||||||
|
r2 = (r1 & 7)*4;
|
||||||
|
if(r1 < 512) {
|
||||||
|
/* small value near power of two */
|
||||||
|
r = (1L << (r1 >> 6)) + r2;
|
||||||
|
} else if(r1 < 512+20) {
|
||||||
|
/* value near a multiple of the page size */
|
||||||
|
r = (RANDOM(max_pages)+1)*PAGE_SIZE + r2 - 16;
|
||||||
|
/*printf("r = %4lx\n", r);*/
|
||||||
|
} else r = RANDOM(max) + 1;
|
||||||
|
} else r = RANDOM(max) + 1;
|
||||||
|
/*if(r <= 0) exit(-1);*/
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
#if __STDC__
|
||||||
|
bin_alloc(struct bin *m)
|
||||||
|
#else
|
||||||
|
bin_alloc(m) struct bin *m;
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
long r, key;
|
||||||
|
unsigned long sz;
|
||||||
|
|
||||||
|
#if TEST > 0
|
||||||
|
if(mem_check(m->ptr, m->size)) {
|
||||||
|
printf("bin_alloc: memory corrupt at %p, size=%lu!\n", m->ptr, m->size);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
total_size -= m->size;
|
||||||
|
r = RANDOM(1024);
|
||||||
|
if(r < PROB_MEMALIGN) {
|
||||||
|
#if !defined(_WIN32)
|
||||||
|
if(m->size > 0) free(m->ptr);
|
||||||
|
m->size = random_size(size);
|
||||||
|
#if PROB_MEMALIGN
|
||||||
|
m->ptr = (unsigned char *)memalign(4 << RANDOM(8), m->size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
} else if(r < (PROB_MEMALIGN + PROB_REALLOC)) {
|
||||||
|
if(m->size == 0) {
|
||||||
|
#ifndef __sparc__
|
||||||
|
m->ptr = NULL;
|
||||||
|
#else
|
||||||
|
/* SunOS4 does not realloc() a NULL pointer */
|
||||||
|
m->ptr = (unsigned char *)malloc(1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#if TEST > 2
|
||||||
|
key = RANDOM(256);
|
||||||
|
sz = m->size;
|
||||||
|
for(r=0; r<sz; r++) m->ptr[r] = (r ^ key) & 0xFF;
|
||||||
|
#endif
|
||||||
|
m->size = random_size(size);
|
||||||
|
/*printf("realloc %d\n", (int)m->size);*/
|
||||||
|
m->ptr = (unsigned char *)realloc(m->ptr, m->size);
|
||||||
|
#if TEST > 2
|
||||||
|
if(m->size < sz) sz = m->size;
|
||||||
|
for(r=0; r<sz; r++)
|
||||||
|
if(m->ptr[r] != ((r ^ key) & 0xFF)) {
|
||||||
|
printf("realloc bug !\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if(r < (PROB_MEMALIGN + PROB_REALLOC + PROB_CALLOC)) {
|
||||||
|
if(m->size > 0) free(m->ptr);
|
||||||
|
m->size = random_size(size);
|
||||||
|
m->ptr = (unsigned char *)calloc(m->size, 1);
|
||||||
|
#if TEST > 2
|
||||||
|
for(r=0; r<m->size; r++)
|
||||||
|
if(m->ptr[r] != '\0') {
|
||||||
|
printf("calloc bug !\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else { /* normal malloc call */
|
||||||
|
if(m->size > 0) free(m->ptr);
|
||||||
|
m->size = random_size(size);
|
||||||
|
m->ptr = (unsigned char *)malloc(m->size);
|
||||||
|
}
|
||||||
|
if(!m->ptr) {
|
||||||
|
printf("out of memory!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
total_size += m->size;
|
||||||
|
if(total_size > total_size_max) total_size_max = total_size;
|
||||||
|
#if TEST > 0
|
||||||
|
mem_init(m->ptr, m->size);
|
||||||
|
#endif
|
||||||
|
if(m->ptr < base_ptr) {
|
||||||
|
#ifdef VERBOSE
|
||||||
|
printf("hmmm, allocating below brk...\n");
|
||||||
|
#endif
|
||||||
|
base_ptr = m->ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
#if __STDC__
|
||||||
|
bin_free(struct bin *m)
|
||||||
|
#else
|
||||||
|
bin_free(m) struct bin *m;
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if(m->size == 0) return;
|
||||||
|
#if TEST > 0
|
||||||
|
if(mem_check(m->ptr, m->size)) {
|
||||||
|
printf("bin_free: memory corrupt!\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
total_size -= m->size;
|
||||||
|
free(m->ptr);
|
||||||
|
m->size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bin_test()
|
||||||
|
{
|
||||||
|
unsigned int b;
|
||||||
|
int v;
|
||||||
|
// printf ("bin_test.\n");
|
||||||
|
|
||||||
|
for(b=0; b<bins; b++) {
|
||||||
|
if(v = mem_check(m[b].ptr, m[b].size)) {
|
||||||
|
printf("bin_test: memory corrupt! m[%d].ptr = %x, m[%d].size = %d\n",
|
||||||
|
b, m[b].ptr, b, m[b].size);
|
||||||
|
printf ("error = %d\n", v);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(b=0; b<sbins; b++) {
|
||||||
|
if(mem_check(sm[b].ptr, sm[b].size)) {
|
||||||
|
printf("bin_test: memory corrupt! sm[%d].ptr = %x, sm[%d].size = %d\n",
|
||||||
|
b, sm[b].ptr, b, sm[b].size);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
print_times()
|
||||||
|
{
|
||||||
|
#if !defined(_WIN32) && !defined(AMIGA)
|
||||||
|
struct rusage ru;
|
||||||
|
long total_sec, total_usec;
|
||||||
|
|
||||||
|
getrusage(RUSAGE_SELF, &ru);
|
||||||
|
printf(" u=%ld.%06ldsec",
|
||||||
|
(long)ru.ru_utime.tv_sec, (long)ru.ru_utime.tv_usec);
|
||||||
|
printf(" s=%ld.%06ldsec",
|
||||||
|
(long)ru.ru_stime.tv_sec, (long)ru.ru_stime.tv_usec);
|
||||||
|
total_usec = (long)ru.ru_utime.tv_usec + (long)ru.ru_stime.tv_usec;
|
||||||
|
total_sec = (long)ru.ru_utime.tv_sec + (long)ru.ru_stime.tv_sec;
|
||||||
|
if(total_usec >= 1000000) {
|
||||||
|
total_usec -= 1000000;
|
||||||
|
total_sec++;
|
||||||
|
}
|
||||||
|
printf(" t=%ld.%06ldsec", total_sec, total_usec);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
#if __STDC__
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
#else
|
||||||
|
main(argc, argv) int argc; char *argv[];
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
int i, j, next_i, count, max=I_MAX, actions;
|
||||||
|
unsigned int b;
|
||||||
|
long sbrk_max, sum;
|
||||||
|
double sbrk_used_sum, total_size_sum;
|
||||||
|
void* dummy = 0;
|
||||||
|
|
||||||
|
if(argc > 1) max = atoi(argv[1]);
|
||||||
|
if(argc > 2) size = atoi(argv[2]);
|
||||||
|
lran2((long)max ^ size);
|
||||||
|
bins = (MEMORY/size)*4;
|
||||||
|
if(bins > BINS_MAX) bins = BINS_MAX;
|
||||||
|
#if 0 // FIX ME? Disable sbrk...
|
||||||
|
base_ptr = (unsigned char *)sbrk(0);
|
||||||
|
sum = (long)base_ptr % PAGE_SIZE;
|
||||||
|
if(sum > 0) {
|
||||||
|
if((char *)sbrk((long)PAGE_SIZE - sum) == (char *)-1) exit(1);
|
||||||
|
base_ptr += (long)PAGE_SIZE - sum;
|
||||||
|
/*printf("base_ptr = %lx\n", (long)base_ptr);*/
|
||||||
|
}
|
||||||
|
/* attempt to fill up the region below the initial brk */
|
||||||
|
for(i=0; i<10000; i++) {
|
||||||
|
dummy = malloc(1);
|
||||||
|
if(dummy >= (void*)base_ptr) break;
|
||||||
|
}
|
||||||
|
free(dummy);
|
||||||
|
base_save = ((unsigned long)base_ptr >> 24) << 24;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MMAP_THRESH > 0
|
||||||
|
if(!mallopt(-3, MMAP_THRESH)) printf("mallopt failed!\n");
|
||||||
|
if(!mallopt(-4, 200)) printf("mallopt failed!\n");
|
||||||
|
#endif
|
||||||
|
#ifdef VERBOSE
|
||||||
|
printf("# mmap_thresh=%d\n", MMAP_THRESH);
|
||||||
|
printf("# bins=%d max=%d size=%d\n", bins, max, size);
|
||||||
|
printf("# base=%lx\n", base_save);
|
||||||
|
#endif
|
||||||
|
for(b=0; b<bins; b++) {
|
||||||
|
if(RANDOM(2) == 0) bin_alloc(&m[b]);
|
||||||
|
else m[b].size = 0;
|
||||||
|
}
|
||||||
|
sbrk_max = 0;
|
||||||
|
sbrk_used_sum = total_size_sum = 0.0;
|
||||||
|
for(i=next_i=count=0; i<=max;) {
|
||||||
|
#if TEST > 1
|
||||||
|
bin_test();
|
||||||
|
#endif
|
||||||
|
#ifdef MSTATS
|
||||||
|
malloc_stats();
|
||||||
|
#endif
|
||||||
|
actions = RANDOM(ACTIONS_MAX);
|
||||||
|
for(j=0; j<actions; j++) {
|
||||||
|
b = RANDOM(bins);
|
||||||
|
bin_free(&m[b]);
|
||||||
|
#if TEST > 3
|
||||||
|
bin_test();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
i += actions;
|
||||||
|
#ifdef AFTER_FREE
|
||||||
|
AFTER_FREE;
|
||||||
|
#endif
|
||||||
|
#if SBRK_AVG > 0
|
||||||
|
if(sbins<SBINS_MAX && RANDOM(SBRK_AVG)==0) {
|
||||||
|
/* throw in an explicit sbrk call */
|
||||||
|
sm[sbins].size = RANDOM(10000)+1;
|
||||||
|
sm[sbins].ptr = sbrk(sm[sbins].size);
|
||||||
|
if(sbins>0 && sm[sbins].ptr==(sm[sbins-1].ptr+sm[sbins-1].size)) {
|
||||||
|
sm[sbins-1].size += sm[sbins].size;
|
||||||
|
sbins--;
|
||||||
|
}
|
||||||
|
#ifdef VERBOSE
|
||||||
|
printf("sbrk #%d %p %ld\n", sbins, sm[sbins].ptr, sm[sbins].size);
|
||||||
|
#endif
|
||||||
|
#if TEST > 0
|
||||||
|
mem_init(sm[sbins].ptr, sm[sbins].size);
|
||||||
|
#endif
|
||||||
|
sbins++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
actions = RANDOM(ACTIONS_MAX);
|
||||||
|
for(j=0; j<actions; j++) {
|
||||||
|
b = RANDOM(bins);
|
||||||
|
bin_alloc(&m[b]);
|
||||||
|
#if TEST > 3
|
||||||
|
bin_test();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
i += actions;
|
||||||
|
if(i >= next_i) { /* gather statistics */
|
||||||
|
count++;
|
||||||
|
#if !defined(_WIN32) && !defined(AMIGA)
|
||||||
|
sum = (long)sbrk(0);
|
||||||
|
#else
|
||||||
|
sum = 0;
|
||||||
|
#endif
|
||||||
|
if(sum > sbrk_max) sbrk_max = sum;
|
||||||
|
sbrk_used_sum += sum;
|
||||||
|
total_size_sum += (double)total_size;
|
||||||
|
#ifdef VERBOSE
|
||||||
|
printf("%8d %7lu\n", i, total_size);
|
||||||
|
#endif
|
||||||
|
next_i += I_AVERAGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Correct sbrk values. */
|
||||||
|
sbrk_max -= (long)base_ptr;
|
||||||
|
sbrk_used_sum -= (double)count*(long)base_ptr;
|
||||||
|
#ifdef VERBOSE
|
||||||
|
printf("# initial brk: %lx\n", (long)base_ptr);
|
||||||
|
printf("# max. sbrk()'ed memory: %ld bytes\n", sbrk_max);
|
||||||
|
printf("# avg. sbrk()'ed memory: %ld bytes\n",
|
||||||
|
(long)(sbrk_used_sum/count));
|
||||||
|
printf("# current size allocated: %ld bytes\n", total_size);
|
||||||
|
printf("# maximum size allocated: %ld bytes\n", total_size_max);
|
||||||
|
printf("# average size allocated: %.1f bytes\n", total_size_sum/count);
|
||||||
|
printf("# current heap waste: %.2f%%\n",
|
||||||
|
(1.0 - (double)total_size_max/sbrk_max)*100.0);
|
||||||
|
printf("# average heap waste: %.2f%%\n",
|
||||||
|
(1.0 - (double)total_size_sum/sbrk_used_sum)*100.0);
|
||||||
|
printf("# total sbrk calls performed: %d\n", sbins);
|
||||||
|
#else
|
||||||
|
printf("size=%7ld waste=%7.3f%%", size,
|
||||||
|
/* (1.0 - (double)total_size_max/sbrk_max)*100.0, */
|
||||||
|
(1.0 - (double)total_size_sum/sbrk_used_sum)*100.0);
|
||||||
|
print_times();
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Local variables:
|
||||||
|
* tab-width:4
|
||||||
|
* compile-command: "gcc -Wall malloc-test.c -o malloc-test"
|
||||||
|
* End:
|
||||||
|
*/
|
||||||
|
|
||||||
90
test_programs/slab-test.c
Normal file
90
test_programs/slab-test.c
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
unsigned long __slab_max_size = 4096;
|
||||||
|
|
||||||
|
static int print_json(void * ignore,const char * buffer,size_t len)
|
||||||
|
{
|
||||||
|
fputs(buffer, stdout);
|
||||||
|
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc,char ** argv)
|
||||||
|
{
|
||||||
|
int num_allocations = 1000;
|
||||||
|
int max_allocation_size = 8192;
|
||||||
|
int random_free_percentage = 33;
|
||||||
|
char ** allocation_table;
|
||||||
|
char * allocation;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
allocation_table = malloc(sizeof(*allocation_table) * num_allocations);
|
||||||
|
if(allocation_table == NULL)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
srand(1);
|
||||||
|
|
||||||
|
printf("/* Allocating %d random length fragments of memory (maximum size = %ld bytes). */\n", num_allocations, max_allocation_size);
|
||||||
|
|
||||||
|
for(i = 0 ; i < num_allocations ; i++)
|
||||||
|
{
|
||||||
|
allocation = malloc(1 + (rand() % max_allocation_size));
|
||||||
|
if(allocation == NULL)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
allocation_table[i] = allocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
__get_slab_stats(NULL, print_json);
|
||||||
|
|
||||||
|
printf("\n/* Changing all allocations to different random lengths. */\n");
|
||||||
|
|
||||||
|
for(i = 0 ; i < num_allocations ; i++)
|
||||||
|
{
|
||||||
|
allocation = realloc(allocation_table[i], 1 + (rand() % max_allocation_size));
|
||||||
|
if(allocation == NULL)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
allocation_table[i] = allocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
__get_slab_stats(NULL, print_json);
|
||||||
|
|
||||||
|
printf("\n/* Freeing %d%% of all allocations. */\n", random_free_percentage);
|
||||||
|
|
||||||
|
for(i = 0 ; i < num_allocations ; i++)
|
||||||
|
{
|
||||||
|
if((rand() % 100) < 33)
|
||||||
|
{
|
||||||
|
free(allocation_table[i]);
|
||||||
|
allocation_table[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
__get_slab_stats(NULL, print_json);
|
||||||
|
|
||||||
|
printf("\n/* Marking unused slabs for reuse; reallocating memory/changing allocation lengths. */\n");
|
||||||
|
|
||||||
|
__decay_unused_slabs();
|
||||||
|
|
||||||
|
for(i = 0 ; i < num_allocations ; i++)
|
||||||
|
{
|
||||||
|
allocation = realloc(allocation_table[i], 1 + (rand() % max_allocation_size));
|
||||||
|
if(allocation == NULL)
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
allocation_table[i] = allocation;
|
||||||
|
}
|
||||||
|
|
||||||
|
__get_slab_stats(NULL, print_json);
|
||||||
|
|
||||||
|
printf("\n/* Freeing all unused slabs. */\n");
|
||||||
|
|
||||||
|
__free_unused_slabs();
|
||||||
|
|
||||||
|
__get_slab_stats(NULL, print_json);
|
||||||
|
|
||||||
|
return(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
@ -1,6 +1,4 @@
|
|||||||
#
|
#
|
||||||
# $Id: smakefile,v 1.9 2006-01-02 13:11:39 obarthel Exp $
|
|
||||||
#
|
|
||||||
# :ts=8
|
# :ts=8
|
||||||
#
|
#
|
||||||
|
|
||||||
@ -10,6 +8,10 @@
|
|||||||
@echo "Compiling $<"
|
@echo "Compiling $<"
|
||||||
@sc nover $(CFLAGS) $<
|
@sc nover $(CFLAGS) $<
|
||||||
|
|
||||||
|
.c.mo:
|
||||||
|
@echo "Compiling $<"
|
||||||
|
@sc nover $(CFLAGS) objname=$*.mo math=IEEE $<
|
||||||
|
|
||||||
.asm.o:
|
.asm.o:
|
||||||
@echo "Assembling $<"
|
@echo "Assembling $<"
|
||||||
@asm $(AFLAGS) $<
|
@asm $(AFLAGS) $<
|
||||||
@ -19,30 +21,31 @@
|
|||||||
# You might want to change this to the directory where your operating system
|
# You might want to change this to the directory where your operating system
|
||||||
# header files are stored. On my system, that's "V:include", but you might
|
# header files are stored. On my system, that's "V:include", but you might
|
||||||
# get lucky with "sc:include" instead, which is the default for SAS/C.
|
# get lucky with "sc:include" instead, which is the default for SAS/C.
|
||||||
INCLUDE_DIR = V:include
|
#INCLUDE_DIR = V:include
|
||||||
#INCLUDE_DIR = sc:include
|
INCLUDE_DIR = sc:include
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
# This is where the header files, the startup code and the c.lib files are
|
# This is where the header files, the startup code and the c.lib files are
|
||||||
# stored; see below how this prefix is used.
|
# stored; see below how this prefix is used.
|
||||||
LIB = /library/
|
LIB = /library
|
||||||
|
|
||||||
|
STARTUP = $(LIB)/startup.o
|
||||||
|
LIBS = $(LIB)/amiga.lib $(LIB)/c.lib $(LIB)/debug.lib
|
||||||
|
MATH_LIBS = $(LIB)/math.lib $(LIBS)
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
OPTIMIZE = optimize opttime optschedule optinline
|
OPTIMIZE = optimize opttime optschedule optinline
|
||||||
#DEBUG = debug=line noopt define=CHECK_FOR_NULL_POINTERS
|
#DEBUG = debug=line noopt define=CHECK_FOR_NULL_POINTERS
|
||||||
#DEBUG = debug=line
|
#DEBUG = debug=line
|
||||||
#DEBUG = debug=line define=NDEBUG
|
DEBUG = debug=line define=NDEBUG
|
||||||
DEBUG = debug=sf noopt
|
#DEBUG = debug=sf noopt
|
||||||
#DEBUG = debug=sf noopt define=CHECK_FOR_NULL_POINTERS
|
#DEBUG = debug=sf noopt define=CHECK_FOR_NULL_POINTERS
|
||||||
#PROFILE = profile
|
#PROFILE = profile
|
||||||
DATA = data=faronly
|
DATA = data=faronly
|
||||||
#CODE = code=far
|
#CODE = code=far
|
||||||
CPU = cpu=060
|
CPU = cpu=030
|
||||||
MATH = define=IEEE_FLOATING_POINT_SUPPORT math=IEEE
|
|
||||||
SUPPORT = define=UNIX_PATH_SEMANTICS define=SOCKET_SUPPORT define=USERGROUP_SUPPORT \
|
|
||||||
define=__C_MACROS__
|
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
@ -55,8 +58,9 @@ CFLAGS = \
|
|||||||
nostackcheck \
|
nostackcheck \
|
||||||
stringmerge \
|
stringmerge \
|
||||||
errorrexx \
|
errorrexx \
|
||||||
$(PROFILE) $(OPTIMIZE) $(CODE) $(DATA) $(CPU) $(MATH) \
|
$(PROFILE) $(OPTIMIZE) $(CODE) $(DATA) $(CPU) $(DEBUG) \
|
||||||
$(SUPPORT) $(DEBUG)
|
math=ieee \
|
||||||
|
define=VERBOSE
|
||||||
|
|
||||||
AFLAGS = \
|
AFLAGS = \
|
||||||
-d -m2
|
-d -m2
|
||||||
@ -68,19 +72,23 @@ all: \
|
|||||||
test fgets_test iotest sscanf_test printf_test sprintf_test \
|
test fgets_test iotest sscanf_test printf_test sprintf_test \
|
||||||
stack_size_test translate_test strtok_test uname simple \
|
stack_size_test translate_test strtok_test uname simple \
|
||||||
fstat_stdout_test simple_sprintf date_test factorial \
|
fstat_stdout_test simple_sprintf date_test factorial \
|
||||||
|
execvp_test setlocale rand fstat_test base_dir_nametest \
|
||||||
|
malloc-test slab-test \
|
||||||
cleanup
|
cleanup
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
-delete \#?.o \#?.map \
|
-delete \#?.o \#?.mo \#?.map \
|
||||||
test fgets_test iotest sscanf_test printf_test sprintf_test \
|
test fgets_test iotest sscanf_test printf_test sprintf_test \
|
||||||
stack_size_test translate_test strtok_test uname simple \
|
stack_size_test translate_test strtok_test uname simple \
|
||||||
simple_sprintf date_test factorial
|
fstat_stdout_test simple_sprintf date_test factorial \
|
||||||
|
execvp_test setlocale rand fstat_test base_dir_nametest \
|
||||||
|
malloc-test slab-test
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
setup:
|
setup:
|
||||||
@echo "Setting up include: assignment"
|
@echo "Setting up include: assignment"
|
||||||
@assign include: $(LIB)include V:include
|
@assign include: $(LIB)/include $(INCLUDE_DIR)
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
@echo "Cleaning up include: assignment"
|
@echo "Cleaning up include: assignment"
|
||||||
@ -90,77 +98,112 @@ cleanup:
|
|||||||
|
|
||||||
test: test.o
|
test: test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
date_test: date_test.o
|
date_test: date_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o date_test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
fgets_test: fgets_test.o
|
fgets_test: fgets_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o fgets_test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
strtok_test: strtok_test.o
|
strtok_test: strtok_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o strtok_test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
iotest: iotest.o
|
iotest: iotest.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o iotest.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
sscanf_test: sscanf_test.o
|
sscanf_test: sscanf_test.mo
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o sscanf_test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.mo to $@ lib $(MATH_LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
printf_test: printf_test.o
|
printf_test: printf_test.mo
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o printf_test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.mo to $@ lib $(MATH_LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
sprintf_test: sprintf_test.o
|
sprintf_test: sprintf_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o sprintf_test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
stack_size_test: stack_size_test.o
|
stack_size_test: stack_size_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o stack_size_test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
translate_test: translate_test.o
|
translate_test: translate_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o translate_test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIB)/unix.lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
uname: uname.o
|
uname: uname.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o uname.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
simple: simple.o
|
simple: simple.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o simple.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
fstat_stdout_test: fstat_stdout_test.o
|
fstat_stdout_test: fstat_stdout_test.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o fstat_stdout_test.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
simple_sprintf: simple_sprintf.o
|
simple_sprintf: simple_sprintf.o
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink simple_sprintf.o to $@ lib $(LIB)c.lib addsym \
|
@slink $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
factorial: factorial.o
|
factorial: factorial.mo
|
||||||
@echo "Linking $@"
|
@echo "Linking $@"
|
||||||
@slink $(LIB)startup.o factorial.o to $@ lib $(LIB)c.lib addsym \
|
@slink $(STARTUP) $*.mo to $@ lib $(MATH_LIBS) addsym \
|
||||||
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
|
execvp_test: execvp_test.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
@slink $(STARTUP) $*.o to $@ lib $(LIB)/unix.lib $(LIBS) addsym \
|
||||||
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
|
setlocale: setlocale.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
|
rand: rand.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
|
fstat_test: fstat_test.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
|
base_dir_nametest: base_dir_nametest.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
|
malloc-test: malloc-test.mo
|
||||||
|
@echo "Linking $@"
|
||||||
|
@slink $(STARTUP) $*.mo to $@ lib $(MATH_LIBS) addsym \
|
||||||
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
|
slab-test: slab-test.o
|
||||||
|
@echo "Linking $@"
|
||||||
|
@slink $(STARTUP) $*.o to $@ lib $(LIBS) addsym \
|
||||||
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
map $@.map,fhx fwidth 32 pwidth 32 swidth 32
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|||||||
@ -77,6 +77,8 @@ main(int argc,char ** argv)
|
|||||||
long n,r;
|
long n,r;
|
||||||
char time_buffer[100];
|
char time_buffer[100];
|
||||||
|
|
||||||
|
free(malloc(4));
|
||||||
|
|
||||||
for(i = 0 ; i < argc ; i++)
|
for(i = 0 ; i < argc ; i++)
|
||||||
printf("%2d) \"%s\"\n",i,argv[i]);
|
printf("%2d) \"%s\"\n",i,argv[i]);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user