1
0
Fork 0
forked from len0rd/rockbox

This commit was manufactured by cvs2svn to create tag 'v2_1'.

git-svn-id: svn://svn.rockbox.org/rockbox/tags/v2_1@4102 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Björn Stenberg 2003-12-03 22:34:06 +00:00
parent 66d165819a
commit 2a1b031d62
34 changed files with 0 additions and 3981 deletions

View file

@ -1,14 +0,0 @@
# The "checkoutlist" file is used to support additional version controlled
# administrative files in $CVSROOT/CVSROOT, such as template files.
#
# The first entry on a line is a filename which will be checked out from
# the corresponding RCS file in the $CVSROOT/CVSROOT directory.
# The remainder of the line is an error message to use if the file cannot
# be checked out.
#
# File format:
#
# [<whitespace>]<filename><whitespace><error message><end-of-line>
#
# comment lines begin with '#'
syncmail

View file

@ -1,15 +0,0 @@
# The "commitinfo" file is used to control pre-commit checks.
# The filter on the right is invoked with the repository and a list
# of files to check. A non-zero exit of the filter program will
# cause the commit to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

View file

@ -1,11 +0,0 @@
# Set this to "no" if pserver shouldn't check system users/passwords
#SystemAuth=no
# Set `PreservePermissions' to `yes' to save file status information
# in the repository.
#PreservePermissions=no
# Set `TopLevelAdmin' to `yes' to create a CVS directory at the top
# level of the new working directory when using the `cvs checkout'
# command.
#TopLevelAdmin=no

View file

@ -1,23 +0,0 @@
# This file affects handling of files based on their names.
#
# The -t/-f options allow one to treat directories of files
# as a single file, or to transform a file in other ways on
# its way in and out of CVS.
#
# The -m option specifies whether CVS attempts to merge files.
#
# The -k option specifies keyword expansion (e.g. -kb for binary).
#
# Format of wrapper file ($CVSROOT/CVSROOT/cvswrappers or .cvswrappers)
#
# wildcard [option value][option value]...
#
# where option is one of
# -f from cvs filter value: path to filter
# -t to cvs filter value: path to filter
# -m update methodology value: MERGE or COPY
# -k expansion mode value: b, o, kkv, &c
#
# and value is a single-quote delimited value.
# For example:
#*.gif -k 'b'

View file

@ -1,21 +0,0 @@
# The "editinfo" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.

View file

@ -1,34 +0,0 @@
# The "loginfo" file controls where "cvs commit" log information
# is sent. The first entry on a line is a regular expression which must match
# the directory that the change is being made to, relative to the
# $CVSROOT. If a match is found, then the remainder of the line is a filter
# program that should expect log information on its standard input.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name ALL appears as a regular expression it is always used
# in addition to the first matching regex or DEFAULT.
#
# You may specify a format string as part of the
# filter. The string is composed of a `%' followed
# by a single format character, or followed by a set of format
# characters surrounded by `{' and `}' as separators. The format
# characters are:
#
# s = file name
# V = old version number (pre-checkin)
# v = new version number (post-checkin)
#
# For example:
#DEFAULT (echo ""; id; echo %s; date; cat) >> $CVSROOT/CVSROOT/commitlog
# or
#DEFAULT (echo ""; id; echo %{sVv}; date; cat) >> $CVSROOT/CVSROOT/commitlog
CVSROOT $CVSROOT/CVSROOT/syncmail -C4 -u %{sVv} zagor@users.sourceforge.net
^apps $CVSROOT/CVSROOT/syncmail -C4 -u %{sVv} rockbox-cvs@cool.haxx.se
^flash $CVSROOT/CVSROOT/syncmail -C4 -u %{sVv} rockbox-cvs@cool.haxx.se
^firmware $CVSROOT/CVSROOT/syncmail -C4 -u %{sVv} rockbox-cvs@cool.haxx.se
^docs $CVSROOT/CVSROOT/syncmail -C4 -u %{sVv} rockbox-cvs@cool.haxx.se
^uisimulator $CVSROOT/CVSROOT/syncmail -C4 -u %{sVv} rockbox-cvs@cool.haxx.se
^tools $CVSROOT/CVSROOT/syncmail -C4 -u %{sVv} rockbox-cvs@cool.haxx.se
^gdb $CVSROOT/CVSROOT/syncmail -C4 -u %{sVv} rockbox-cvs@cool.haxx.se

View file

@ -1,31 +0,0 @@
# Three different line formats are valid:
# key -a aliases...
# key [options] directory
# key [options] directory files...
#
# Where "options" are composed of:
# -i prog Run "prog" on "cvs commit" from top-level of module.
# -o prog Run "prog" on "cvs checkout" of module.
# -e prog Run "prog" on "cvs export" of module.
# -t prog Run "prog" on "cvs rtag" of module.
# -u prog Run "prog" on "cvs update" of module.
# -d dir Place module in directory "dir" instead of module name.
# -l Top-level directory only -- do not recurse.
#
# NOTE: If you change any of the "Run" options above, you'll have to
# release and re-checkout any working directories of these modules.
#
# And "directory" is a path to a directory relative to $CVSROOT.
#
# The "-a" option specifies an alias. An alias is interpreted as if
# everything on the right of the "-a" had been typed on the command line.
#
# You can encode a module within a module by using the special '&'
# character to interpose another module into the current module. This
# can be useful for creating a module that consists of many directories
# spread out over the entire source repository.
rockbox &apps &firmware &docs &tools
rockbox-devel &apps &flash &firmware &docs &tools &uisimulator &gdb
rockbox-all &apps &flash &firmware &docs &tools &uisimulator &gdb &www
website &www &docs

View file

@ -1,12 +0,0 @@
# The "notify" file controls where notifications from watches set by
# "cvs watch add" or "cvs edit" are sent. The first entry on a line is
# a regular expression which is tested against the directory that the
# change is being made to, relative to the $CVSROOT. If it matches,
# then the remainder of the line is a filter program that should contain
# one occurrence of %s for the user to notify, and information on its
# standard input.
#
# "ALL" or "DEFAULT" can be used in place of the regular expression.
#
# For example:
#ALL mail %s -s "CVS notification"

View file

@ -1,13 +0,0 @@
# The "rcsinfo" file is used to control templates with which the editor
# is invoked on commit and import.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being made to, relative to the
# $CVSROOT. For the first match that is found, then the remainder of the
# line is the name of the file that contains the template.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

View file

@ -1,210 +0,0 @@
#! /usr/bin/python
# -*- Python -*-
"""Complicated notification for CVS checkins.
This script is used to provide email notifications of changes to the CVS
repository. These email changes will include context diffs of the changes.
Really big diffs will be trimmed.
This script is run from a CVS loginfo file (see $CVSROOT/CVSROOT/loginfo). To
set this up, create a loginfo entry that looks something like this:
mymodule /path/to/this/script %%s some-email-addr@your.domain
In this example, whenever a checkin that matches `mymodule' is made, this
script is invoked, which will generate the diff containing email, and send it
to some-email-addr@your.domain.
Note: This module used to also do repository synchronizations via
rsync-over-ssh, but since the repository has been moved to SourceForge,
this is no longer necessary. The syncing functionality has been ripped
out in the 3.0, which simplifies it considerably. Access the 2.x versions
to refer to this functionality. Because of this, the script is misnamed.
It no longer makes sense to run this script from the command line. Doing so
will only print out this usage information.
Usage:
%(PROGRAM)s [options] <%%S> email-addr [email-addr ...]
Where options is:
--cvsroot=<path>
Use <path> as the environment variable CVSROOT. Otherwise this
variable must exist in the environment.
--help
-h
Print this text.
--context=#
-C #
Include # lines of context around lines that differ (default: 2).
-c
Produce a context diff (default).
-u
Produce a unified diff (smaller, but harder to read).
<%%S>
CVS %%s loginfo expansion. When invoked by CVS, this will be a single
string containing the directory the checkin is being made in, relative
to $CVSROOT, followed by the list of files that are changing. If the
%%s in the loginfo file is %%{sVv}, context diffs for each of the
modified files are included in any email messages that are generated.
email-addrs
At least one email address.
"""
import os
import sys
import string
import time
import getopt
# Notification command
MAILCMD = '/bin/mail -s "cvs: %(SUBJECT)s" %(PEOPLE)s 2>&1 > /dev/null'
# Diff trimming stuff
DIFF_HEAD_LINES = 20
DIFF_TAIL_LINES = 20
DIFF_TRUNCATE_IF_LARGER = 1000
PROGRAM = sys.argv[0]
def usage(code, msg=''):
print __doc__ % globals()
if msg:
print msg
sys.exit(code)
def calculate_diff(filespec, contextlines):
try:
file, oldrev, newrev = string.split(filespec, ',')
except ValueError:
# No diff to report
return '***** Bogus filespec: %s' % filespec
if oldrev == 'NONE':
try:
if os.path.exists(file):
fp = open(file)
else:
update_cmd = 'cvs -fn update -r %s -p %s' % (newrev, file)
fp = os.popen(update_cmd)
lines = fp.readlines()
fp.close()
lines.insert(0, '--- NEW FILE: %s ---\n' % file)
except IOError, e:
lines = ['***** Error reading new file: ',
str(e), '\n***** file: ', file, ' cwd: ', os.getcwd()]
elif newrev == 'NONE':
lines = ['--- %s DELETED ---\n' % file]
else:
# This /has/ to happen in the background, otherwise we'll run into CVS
# lock contention. What a crock.
if contextlines > 0:
difftype = "-C " + str(contextlines)
else:
difftype = "-uN"
diffcmd = '/usr/bin/cvs -f diff -kk %s -b -r %s -r %s %s' % (
difftype, oldrev, newrev, file)
fp = os.popen(diffcmd)
lines = fp.readlines()
sts = fp.close()
# ignore the error code, it always seems to be 1 :(
## if sts:
## return 'Error code %d occurred during diff\n' % (sts >> 8)
if len(lines) > DIFF_TRUNCATE_IF_LARGER:
removedlines = len(lines) - DIFF_HEAD_LINES - DIFF_TAIL_LINES
del lines[DIFF_HEAD_LINES:-DIFF_TAIL_LINES]
lines.insert(DIFF_HEAD_LINES,
'[...%d lines suppressed...]\n' % removedlines)
return string.join(lines, '')
def blast_mail(mailcmd, filestodiff, contextlines):
# cannot wait for child process or that will cause parent to retain cvs
# lock for too long. Urg!
if not os.fork():
# in the child
# give up the lock you cvs thang!
time.sleep(2)
fp = os.popen(mailcmd, 'w')
fp.write(sys.stdin.read())
fp.write('\n')
# append the diffs if available
for file in filestodiff:
fp.write(calculate_diff(file, contextlines))
fp.write('\n')
fp.close()
# doesn't matter what code we return, it isn't waited on
os._exit(0)
# scan args for options
def main():
contextlines = 2
try:
opts, args = getopt.getopt(sys.argv[1:], 'hC:cu',
['context=', 'cvsroot=', 'help'])
except getopt.error, msg:
usage(1, msg)
# parse the options
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt == '--cvsroot':
os.environ['CVSROOT'] = arg
elif opt in ('-C', '--context'):
contextlines = int(arg)
elif opt == '-c':
if contextlines <= 0:
contextlines = 2
elif opt == '-u':
contextlines = 0
# What follows is the specification containing the files that were
# modified. The argument actually must be split, with the first component
# containing the directory the checkin is being made in, relative to
# $CVSROOT, followed by the list of files that are changing.
if not args:
usage(1, 'No CVS module specified')
SUBJECT = args[0]
specs = string.split(args[0])
del args[0]
# The remaining args should be the email addresses
if not args:
usage(1, 'No recipients specified')
# Now do the mail command
PEOPLE = string.join(args)
mailcmd = MAILCMD % vars()
print 'Mailing %s...' % PEOPLE
if specs == ['-', 'Imported', 'sources']:
return
if specs[-3:] == ['-', 'New', 'directory']:
del specs[-3:]
print 'Generating notification message...'
blast_mail(mailcmd, specs[1:], contextlines)
print 'Generating notification message... done.'
if __name__ == '__main__':
main()
sys.exit(0)

View file

@ -1,20 +0,0 @@
# The "taginfo" file is used to control pre-tag checks.
# The filter on the right is invoked with the following arguments:
#
# $1 -- tagname
# $2 -- operation "add" for tag, "mov" for tag -F, and "del" for tag -d
# $3 -- repository
# $4-> file revision [file revision ...]
#
# A non-zero exit of the filter program will cause the tag to be aborted.
#
# The first entry on a line is a regular expression which is tested
# against the directory that the change is being committed to, relative
# to the $CVSROOT. For the first match that is found, then the remainder
# of the line is the name of the filter to run.
#
# If the repository name does not match any of the regular expressions in this
# file, the "DEFAULT" line is used, if it is specified.
#
# If the name "ALL" appears as a regular expression it is always used
# in addition to the first matching regex or "DEFAULT".

View file

@ -1,21 +0,0 @@
# The "verifymsg" file is used to allow verification of logging
# information. It works best when a template (as specified in the
# rcsinfo file) is provided for the logging procedure. Given a
# template with locations for, a bug-id number, a list of people who
# reviewed the code before it can be checked in, and an external
# process to catalog the differences that were code reviewed, the
# following test can be applied to the code:
#
# Making sure that the entered bug-id number is correct.
# Validating that the code that was reviewed is indeed the code being
# checked in (using the bug-id number or a seperate review
# number to identify this particular code set.).
#
# If any of the above test failed, then the commit would be aborted.
#
# Actions such as mailing a copy of the report to each reviewer are
# better handled by an entry in the loginfo file.
#
# One thing that should be noted is the the ALL keyword is not
# supported. There can be only one entry that matches a given
# repository.

View file

@ -1,40 +0,0 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
# Copyright (C) 2002 by Daniel Stenberg
#
# All files in this archive are subject to the GNU General Public License.
# See the file COPYING in the source tree root for full license agreement.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
TARGET = libdmalloc.a
LIBOBJS = dmalloc.o bmalloc.o bysize.o
# define this to talk a lot in runtime
# -DDEBUG_VERBOSE
CFLAGS = -g -W -Wall -DDEBUG_MALLOC
CC = gcc
AR = ar
LDFLAGS = -L. -ldmalloc
all: $(TARGET)
clean:
rm -f core *~ $(TARGET) $(LIBOBJS)
$(TARGET): $(LIBOBJS)
$(AR) ruv $(TARGET) $(LIBOBJS)
bmalloc.o: bmalloc.c bysize.h
bysize.o: bysize.c
dmalloc.o: dmalloc.c

View file

@ -1,21 +0,0 @@
Package: dbestfit - a dynamic best-fit memory allocator
Date: 1996 - 2002
Version: 3.3
Author: Daniel Stenberg <daniel@haxx.se>
License: MIT originally, files in the Rockbox project are GPL licensed.
I wrote the dmalloc part for small allocation sizes to improve the behavior
of the built-in (first-fit) allocator found in pSOS, during late 1996 and
spring 1997.
I wrote the bmalloc part (best-fit with optional splay-tree sorting) just for
the fun of it and to see how good malloc() implementation I could make. The
quality of my implementation is still left to be judged in real-world tests.
TODO:
* Remove the final not-so-very-nice loop in dmalloc.c that checks for a block
with free fragments (when the list gets longer too much time might be spent
in that loop).
* Make a separate application that samples the memory usage of a program
and is capable of replaying it (in order to test properly).

View file

@ -1,170 +0,0 @@
====================================
Memory Allocation Algorithm Theories
====================================
GOAL
It is intended to be a 100% working memory allocation system. It should be
capable of replacing an ordinary Operating System's own routines. It should
work good in a multitasking, shared memory, non-virtual memory environment
without clogging the memory. Primary aimed for small machines, CPUs and
memory amounts.
I use a best-fit algorithm with a slight overhead in order to increase speed
a lot. It should remain scalable and work good with very large amount of
memory and free/used memory blocks too.
TERMINOLOGY
FRAGMENT - small identically sized parts of a larger BLOCK, they are _not_
allocated when traversed in lists etc
BLOCK - large memory area, if used for FRAGMENTS, they are linked in a
lists. One list for each FRAGMENT size supported.
TOP - head struct that holds information about and points to a chain
of BLOCKS for a particular FRAGMENT size.
CHUNK - a contiguous area of free memory
MEMORY SYSTEM
We split the system in two parts. One part allocates small memory amounts
and one part allocates large memory amounts, but all allocations are done
"through" the small-part-system. There is an option to use only the small
system (and thus use the OS for large blocks) or the complete package.
##############################################################################
SMALL SIZE ALLOCATIONS
##############################################################################
Keywords for this system is 'Deferred Coalescing' and 'quick lists'.
ALLOC
* Small allocations are "aligned" upwards to a set of preset sizes. In the
current implementation I use 20, 28, 52, 116, 312, 580, 1016, 2032 bytes.
Memory allocations of these sizes are referred to as FRAGMENTS.
(The reason for these specific sizes is the requirement that they must be
32-bit aligned and fit as good as possible within 4064 bytes.)
* Allocations larger than 2032 will get a BLOCK for that allocation only.
* Each of these sizes has it's own TOP. When a FRAGMENT is requested, a
larger BLOCK will be allocated and divided into many FRAGMENTS (all of the
same size). TOP points to a list with BLOCKS that contains FRAGMENTS of
the same size. Each BLOCK has a 'number of free FRAGMENTS' counter and so
has each TOP (for the entire chain).
* A BLOCK is around 4064 bytes plus the size of the information header. This
size is adjusted to make the allocation of the big block not require more
than 4096 bytes. (This might not be so easy to be sure of, if you don't
know how the big-block system works, but the BMALLOC system uses an
extra header of 12 bytes and the header for the FRAGMENT BLOCK is 20 bytes
in a general 32-bit environment.)
* In case the allocation of a BLOCK fails when a FRAGMENT is required, the
next size of FRAGMENTS will be checked for a free FRAGMENT. First when the
larger size lists have been tested without success it will fail for real.
FREE
* When FRAGMENTS are freed so that a BLOCK becomes non-used, it is returned
to the system.
* FREEing a fragment adds the buffer in a LIFO-order. That means that the
next request for a fragment from the same list, the last freed buffer will
be returned first.
REALLOC
* REALLOCATION of a FRAGMENT does first check if the new size would fit
within the same FRAGMENT and if it would use the same FRAGMENT size. If it
does and would, the same pointer is returned.
OVERHEAD
Yes, there is an overhead on small allocations (internal fragmentation).
Yet, I do believe that small allocations more often than larger ones are
used dynamically. I believe that a large overhead is not a big problem if it
remains only for a while. The big gain is with the extreme speed we can GET
and RETURN small allocations. This has yet to be proven. I am open to other
systems of dealing with the small ones, but I don`t believe in using the
same system for all sizes of allocations.
IMPROVEMENT
An addition to the above described algorithm is the `save-empty-BLOCKS-a-
while-afterwards`. It will be used when the last used FRAGMENT within a
BLOCK is freed. The BLOCK will then not get returned to the system until "a
few more" FRAGMENTS have been freed in case the last [few] freed FRAGMENTS
are allocated yet again (and thus prevent the huge overhead of making
FRAGMENTS in a BLOCK). The "only" drawback of such a SEBAWA concept is
that it would mean an even bigger overhead...
HEADERS (in allocated data)
FRAGMENTS - 32-bit pointer to its parent BLOCK (lowest bit must be 0)
BLOCK - 32-bit size (lowest bit must be 1 to separate this from
FRAGMENTS)
##############################################################################
LARGER ALLOCATIONS
##############################################################################
If the requested size is larger than the largest FRAGMENT size supported,
the allocation will be made for this memory area alone, or if a BLOCK is
allocated to fit lots of FRAGMENTS a large block is also desired.
* We add memory to the "system" with the add_pool() function call. It
specifies the start and size of the new block of memory that will be
used in this memory allocation system. Several add_pool() calls are
supported and they may or may not add contiguous memory.
* Make all blocks get allocated aligned to BLOCKSIZE (sometimes referred to
as 'grain size'), 64 bytes in my implementation. Reports tell us there is
no real gain in increasing the size of the align.
* We link *all* pieces of memory (AREAS), free or not free. We keep the list
in address order and thus when a FREE() occurs we know instantly if there
are FREE CHUNKS wall-to-wall. No list "travels" needed. Requires some
extra space in every allocated BLOCK. Still needs to put the new CHUNK in
the right place in size-sorted list/tree. All memory areas, allocated or
not, contain the following header:
- size of this memory area (31 bits)
- FREE status (1 bit)
- pointer to the next AREA closest in memory (32 bits)
- pointer to the prev AREA closest in memory (32 bits)
(Totally 12 bytes)
* Sort all FREE CHUNKS in size-order. We use a SPLAY TREE algorithm for
maximum speed. Data/structs used for the size-sorting functions are kept
in an abstraction layer away from this since it is really not changing
anything (except executing speed).
ALLOC (RSIZE - requested size, aligned properly)
* Fetch a CHUNK that RSIZE fits within. If the found CHUNK is larger than
RSIZE, split it and return the RSIZE to the caller. Link the new CHUNK
into the list/tree.
FREE (AREA - piece of memory that is returned to the system)
* Since the allocated BLOCK has kept its link-pointers, we can without
checking any list instantly see if there are any FREE CHUNKS that are
wall-to-wall with the AREA (both sides). If the AREA *is* wall-to-wall
with one or two CHUNKS that or they are unlinked from the lists, enlarged
and re-linked into the lists.
REALLOC
* There IS NO realloc() of large blocks, they are performed in the previous
layer (dmalloc).
##############################################################################
FURTHER READING
##############################################################################
* "Dynamic Storage Allocation: A Survey and Critical Review" (Paul R. Wilson,
Mark S. Johnstone, Michael Neely, David Boles)
ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps
* "A Memory Allocator" (Doug Lea)
http://g.oswego.edu/dl/html/malloc.html

View file

@ -1,386 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Daniel Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/*****************************************************************************
*
* Big (best-fit) Memory Allocation
*
* Author: Daniel Stenberg <daniel@haxx.se>
*
* Read THOUGHTS for theories and details on implementation.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include "bysize.h"
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* #define DEBUG_MALLOC */
#define BMEM_ALIGN 64 /* resolution */
#define BMEMERR_TOOSMALL -1
/* this struct will be stored in all CHUNKS and AREAS */
struct BlockInfo {
struct BlockInfo *lower; /* previous block in memory (lower address) */
struct BlockInfo *higher; /* next block in memory (higher address) */
unsigned long info; /* 31 bits size: 1 bit free boolean */
#define INFO_FREE 1
#define INFO_SIZE (~ INFO_FREE) /* inverted FREE bit pattern */
/* FREE+SIZE Could be written to use ordinary bitfields if using a smart
(like gcc) compiler in a manner like:
int size:31;
int free:1;
The 'higher' pointer COULD be removed completely if the size is used as
an index to the higher one. This would then REQUIRE the entire memory
pool to be contiguous and it needs a 'terminating' "node" or an extra
flag that informs about the end of the list.
*/
};
/* the BLOCK list should be sorted in a lower to higher address order */
struct BlockInfo *blockHead=NULL; /* nothing from the start */
void bmalloc_status(void);
/***********************************************************************
*
* remove_block()
*
* Remove the block from the address-sorted list.
*
***********************************************************************/
static
void remove_block(struct BlockInfo *block)
{
if(block->lower)
block->lower->higher = block->higher;
else
blockHead = block->higher;
if(block->higher)
block->higher->lower = block->lower;
}
/****************************************************************************
*
* add_blocktolists()
*
* Adds the specified block at the specified place in the address-sorted
* list and at the appropriate place in the size-sorted.
*
***************************************************************************/
static
void add_blocktolists(struct BlockInfo *block,
struct BlockInfo *newblock,
size_t newsize)
{
struct BlockInfo *temp; /* temporary storage variable */
if(block) {
/* `block' is now a lower address than 'newblock' */
/*
* Check if the new CHUNK is wall-to-wall with the lower addressed
* one (if *that* is free)
*/
if(block->info&INFO_FREE) {
if((char *)block + (block->info&INFO_SIZE) == (char *)newblock) {
/* yes sir, this is our lower address neighbour, enlarge that one
pick it out from the list and recursively add that chunk and
then we escape */
/* remove from size-sorted list: */
bmalloc_remove_chunksize((char*)block+sizeof(struct BlockInfo));
block->info += newsize; /* newsize is an even number and thus the FREE
bit is untouched */
remove_block(block); /* unlink the block address-wise */
/* recursively check our lower friend(s) */
add_blocktolists(block->lower, block, block->info&INFO_SIZE);
return;
}
}
temp = block->higher;
block->higher = newblock;
newblock->lower = block;
newblock->higher = temp;
}
else {
/* this block should preceed the heading one */
temp = blockHead;
/* check if this is our higher addressed neighbour */
if((char *)newblock + newsize == (char *)temp) {
/* yes, we are wall-to-wall with the higher CHUNK */
if(temp->info&INFO_FREE) {
/* and the neighbour is even free, remove that one and enlarge
ourselves, call add_blocktolists() recursively and then escape */
remove_block(temp); /* unlink 'temp' from list */
/* remove from size-sorted list: */
bmalloc_remove_chunksize((char*)temp+sizeof(struct BlockInfo) );
/* add the upper block's size on ourselves */
newsize += temp->info&INFO_SIZE;
/* add the new, bigger block */
add_blocktolists(block, newblock, newsize);
return;
}
}
blockHead = newblock;
newblock->higher = temp;
newblock->lower = NULL; /* there is no lower one */
}
newblock->info = newsize | INFO_FREE; /* we do assume size isn't using the
FREE bit */
bmalloc_insert_bysize((char *)newblock+sizeof(struct BlockInfo), newsize);
}
/***********************************************************************
*
* findblockbyaddr()
*
* Find the block that is just before the input block in memory. Returns NULL
* if none is.
*
***********************************************************************/
static
struct BlockInfo *findblockbyaddr(struct BlockInfo *block)
{
struct BlockInfo *test = blockHead;
struct BlockInfo *lower = NULL;
while(test && (test < block)) {
lower = test;
test = test->higher;
}
return lower;
}
/***********************************************************************
*
* bmalloc_add_pool()
*
* This function should be the absolutely first function to call. It sets up
* the memory bounds of the [first] CHUNK(s). It is possible to call this
* function several times to add more CHUNKs to the pool of free memory. This
* allows the bmalloc system to deal with non-contigous memory areas.
*
* Returns non-zero if an error occured. The memory was not added then.
*
***********************************************************************/
int bmalloc_add_pool(void *start,
size_t size)
{
struct BlockInfo *newblock = (struct BlockInfo *)start;
struct BlockInfo *block;
if(size < BMEM_ALIGN)
return BMEMERR_TOOSMALL;
block = findblockbyaddr( newblock );
/* `block' is now a lower address than 'newblock' or NULL */
if(size&1)
size--; /* only add even sizes */
add_blocktolists(block, newblock, size);
return 0;
}
#ifdef DEBUG_VERBOSE
static void bmalloc_failed(size_t size)
{
printf("*** " __FILE__ " Couldn't allocate %d bytes\n", size);
bmalloc_status();
}
#else
#define bmalloc_failed(x)
#endif
void bmalloc_status(void)
{
#ifdef DEBUG_MALLOC
struct BlockInfo *block = blockHead;
long mem_free = 0;
long mem_used = 0;
printf("List of BLOCKS (in address order):\n");
while(block) {
printf(" START %p END %p SIZE %ld FLAG %s\n",
block,
(char *)block+(block->info&INFO_SIZE),
block->info&INFO_SIZE,
(block->info&INFO_FREE)?"free":"used");
if(block->info&INFO_FREE)
mem_free += block->info&INFO_SIZE;
else
mem_used += block->info&INFO_SIZE;
block = block->higher;
}
printf(" Used mem: %ld , free mem: %ld (total %ld)\n",
mem_used, mem_free, mem_used + mem_free);
bmalloc_print_sizes();
#endif
}
void *bmalloc(size_t size)
{
void *mem;
#ifdef DEBUG_VERBOSE
{
static int count=0;
int realsize = size + sizeof(struct BlockInfo);
if(realsize%4096)
realsize = ((size / BMEM_ALIGN)+1) * BMEM_ALIGN;
printf("%d bmalloc(%d) [%d]\n", count++, size, realsize);
}
#endif
size += sizeof(struct BlockInfo); /* add memory for our header */
if(size&(BMEM_ALIGN-1)) /* a lot faster than %BMEM_ALIGN but this MUST be
changed if the BLOCKSIZE is not 2^X ! */
size = ((size / BMEM_ALIGN)+1) * BMEM_ALIGN; /* align like this */
/* get a CHUNK from the list with this size */
mem = bmalloc_obtainbysize ( size );
if(mem) {
/* the memory block we have got is the "best-fit" and it is already
un-linked from the free list */
/* now do the math to get the proper block pointer */
struct BlockInfo *block= (struct BlockInfo *)
((char *)mem - sizeof(struct BlockInfo));
block->info &= ~INFO_FREE;
/* not free anymore */
if( size != (block->info&INFO_SIZE)) {
/* split this chunk into two pieces and return the one that fits us */
size_t othersize = (block->info&INFO_SIZE) - size;
if(othersize > BMEM_ALIGN) {
/* prevent losing small pieces of memory due to weird alignments
of the memory pool */
block->info = size; /* set new size (leave FREE bit cleared) */
/* Add the new chunk to the lists: */
add_blocktolists(block->lower,
(struct BlockInfo *)((char *)block + size),
othersize );
}
}
/* Return the memory our parent may use: */
return (char *)block+sizeof(struct BlockInfo);
}
else {
bmalloc_failed(size);
return NULL; /* can't find any memory, fail hard */
}
#ifdef DEBUG_VERBOSE
bmalloc_status();
#endif
return mem;
}
void bfree(void *ptr)
{
struct BlockInfo *block = (struct BlockInfo *)
((char *)ptr - sizeof(struct BlockInfo));
size_t size;
/* setup our initial higher and lower pointers */
struct BlockInfo *lower = block->lower;
struct BlockInfo *higher = block->higher;
#ifdef DEBUG_VERBOSE
static int freecount=0;
printf("%d bfree(%p)\n", freecount++, ptr);
#endif
/* bind together lower addressed FREE CHUNKS */
if(lower && (lower->info&INFO_FREE) &&
((char *)lower + (lower->info&INFO_SIZE) == (char *)block)) {
size = block->info&INFO_SIZE; /* original size */
/* remove from size-link: */
bmalloc_remove_chunksize((char *)lower+sizeof(struct BlockInfo));
remove_block(block); /* unlink from address list */
block = lower; /* new base area pointer */
block->info += size; /* append the new size (the FREE bit
will remain untouched) */
lower = lower->lower; /* new lower pointer */
}
/* bind together higher addressed FREE CHUNKS */
if(higher && (higher->info&INFO_FREE) &&
((char *)block + (block->info&INFO_SIZE) == (char *)higher)) {
/* append higher size, the FREE bit won't be affected */
block->info += (higher->info&INFO_SIZE);
/* unlink from size list: */
bmalloc_remove_chunksize(higher+sizeof(struct BlockInfo));
remove_block(higher); /* unlink from address list */
higher = higher->higher; /* the new higher link */
block->higher = higher; /* new higher link */
}
block->info &= ~INFO_FREE; /* consider this FREE! */
block->lower = lower;
block->higher = higher;
bmalloc_insert_bysize((char *)block+sizeof(struct BlockInfo),
block->info&INFO_SIZE);
#ifdef DEBUG_VERBOSE
bmalloc_status();
#endif
}

View file

@ -1,30 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Daniel Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _BMALLOC_H_
#define _BMALLOC_H_
#include <stdlib.h>
int bmalloc_add_pool(void *start, size_t size);
void bmalloc_status(void);
void *bmalloc(size_t size);
void bfree(void *ptr);
#endif

View file

@ -1,451 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Daniel Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/*****************************************************************************
*
* Size-sorted list/tree functions.
*
* Author: Daniel Stenberg
* Date: March 7, 1997
* Version: 2.0
* Email: daniel@haxx.se
*
* v2.0
* - Added SPLAY TREE functionality.
*
* Adds and removes CHUNKS from a list or tree.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#define SPLAY /* we use the splay version as that is much faster when the
amount of blocks grow */
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef SPLAY /* these routines are for the non-splay version */
struct ChunkInfo {
struct ChunkInfo *larger;
struct ChunkInfo *smaller;
size_t size;
};
/* the CHUNK list anchor */
struct ChunkInfo *chunkHead=NULL;
/***********************************************************************
findchunkbysize()
Find the chunk that is smaller than the input size. Returns
NULL if none is.
**********************************************************************/
static struct ChunkInfo *findchunkbysize(size_t size)
{
struct ChunkInfo *test = chunkHead;
struct ChunkInfo *smaller = NULL;
while(test && (test->size < size)) {
smaller = test;
test = test->larger;
}
return smaller;
}
/***********************************************************************
remove_chunksize()
Remove the chunk from the size-sorted list.
***********************************************************************/
void bmalloc_remove_chunksize(void *data)
{
struct ChunkInfo *chunk = (struct ChunkInfo *)data;
if(chunk->smaller)
chunk->smaller->larger = chunk->larger;
else {
/* if this has no smaller, this is the head */
chunkHead = chunk->larger; /* new head */
}
if(chunk->larger)
chunk->larger->smaller = chunk->smaller;
}
void bmalloc_insert_bysize(char *data, size_t size)
{
struct ChunkInfo *newchunk = (struct ChunkInfo *)data;
struct ChunkInfo *chunk = findchunkbysize ( size );
newchunk->size = size;
if(chunk) {
/* 'chunk' is smaller than size, append the new chunk ahead of this */
newchunk->smaller = chunk;
newchunk->larger = chunk->larger;
if(chunk->larger)
chunk->larger->smaller = newchunk;
chunk->larger = newchunk;
}
else {
/* smallest CHUNK around, append first in the list */
newchunk->larger = chunkHead;
newchunk->smaller = NULL;
if(chunkHead)
chunkHead->smaller = newchunk;
chunkHead = newchunk;
}
}
char *bmalloc_obtainbysize( size_t size)
{
struct ChunkInfo *chunk = findchunkbysize( size );
if(!chunk) {
if(size <= (chunkHead->size))
/* there is no smaller CHUNK, use the first one (if we fit within that)
*/
chunk = chunkHead;
}
else
/* we're on the last CHUNK that is smaller than requested, step onto
the bigger one */
chunk = chunk->larger;
if(chunk) {
bmalloc_remove_chunksize( chunk ); /* unlink size-wise */
return (char *)chunk;
}
else
return NULL;
}
void bmalloc_print_sizes(void)
{
struct ChunkInfo *chunk = chunkHead;
printf("List of CHUNKS (in size order):\n");
#if 1
while(chunk) {
printf(" START %p END %p SIZE %d\n",
chunk, (char *)chunk+chunk->size, chunk->size);
chunk = chunk->larger;
}
#endif
printf("End of CHUNKS:\n");
}
#else /* Here follows all routines dealing with the SPLAY TREES */
typedef struct tree_node Tree;
struct tree_node {
Tree *smaller; /* smaller node */
Tree *larger; /* larger node */
Tree *same; /* points to a node with identical key */
int key; /* the "sort" key */
};
Tree *chunkHead = NULL; /* the root */
#define compare(i,j) ((i)-(j))
/* Set this to a key value that will *NEVER* appear otherwise */
#define KEY_NOTUSED -1
/*
* Splay using the key i (which may or may not be in the tree.) The starting
* root is t. Weight fields are maintained.
*/
static
Tree * splay (int i, Tree *t)
{
Tree N, *l, *r, *y;
int comp;
if (t == NULL)
return t;
N.smaller = N.larger = NULL;
l = r = &N;
for (;;) {
comp = compare(i, t->key);
if (comp < 0) {
if (t->smaller == NULL)
break;
if (compare(i, t->smaller->key) < 0) {
y = t->smaller; /* rotate smaller */
t->smaller = y->larger;
y->larger = t;
t = y;
if (t->smaller == NULL)
break;
}
r->smaller = t; /* link smaller */
r = t;
t = t->smaller;
}
else if (comp > 0) {
if (t->larger == NULL)
break;
if (compare(i, t->larger->key) > 0) {
y = t->larger; /* rotate larger */
t->larger = y->smaller;
y->smaller = t;
t = y;
if (t->larger == NULL)
break;
}
l->larger = t; /* link larger */
l = t;
t = t->larger;
}
else {
break;
}
}
l->larger = r->smaller = NULL;
l->larger = t->smaller; /* assemble */
r->smaller = t->larger;
t->smaller = N.larger;
t->larger = N.smaller;
return t;
}
/* Insert key i into the tree t. Return a pointer to the resulting tree or
NULL if something went wrong. */
static
Tree *insert(int i, Tree *t, Tree *new)
{
if (new == NULL) {
return t;
}
if (t != NULL) {
t = splay(i,t);
if (compare(i, t->key)==0) {
/* it already exists one of this size */
new->same = t;
new->key = i;
new->smaller = t->smaller;
new->larger = t->larger;
t->smaller = new;
t->key = KEY_NOTUSED;
return new; /* new root node */
}
}
if (t == NULL) {
new->smaller = new->larger = NULL;
}
else if (compare(i, t->key) < 0) {
new->smaller = t->smaller;
new->larger = t;
t->smaller = NULL;
}
else {
new->larger = t->larger;
new->smaller = t;
t->larger = NULL;
}
new->key = i;
new->same = NULL; /* no identical node (yet) */
return new;
}
/* Finds and deletes the best-fit node from the tree. Return a pointer to the
resulting tree. best-fit means the smallest node that fits the requested
size. */
static
Tree *removebestfit(int i, Tree *t, Tree **removed)
{
Tree *x;
if (t==NULL)
return NULL;
t = splay(i,t);
if(compare(i, t->key) > 0) {
/* too small node, try the larger chain */
if(t->larger)
t=splay(t->larger->key, t);
else {
/* fail */
*removed = NULL;
return t;
}
}
if (compare(i, t->key) <= 0) { /* found it */
/* FIRST! Check if there is a list with identical sizes */
x = t->same;
if(x) {
/* there is, pick one from the list */
/* 'x' is the new root node */
x->key = t->key;
x->larger = t->larger;
x->smaller = t->smaller;
*removed = t;
return x; /* new root */
}
if (t->smaller == NULL) {
x = t->larger;
}
else {
x = splay(i, t->smaller);
x->larger = t->larger;
}
*removed = t;
return x;
}
else {
*removed = NULL; /* no match */
return t; /* It wasn't there */
}
}
/* Deletes the node we point out from the tree if it's there. Return a pointer
to the resulting tree. */
static
Tree *removebyaddr(Tree *t, Tree *remove)
{
Tree *x;
if (!t || !remove)
return NULL;
if(KEY_NOTUSED == remove->key) {
/* just unlink ourselves nice and quickly: */
remove->smaller->same = remove->same;
if(remove->same)
remove->same->smaller = remove->smaller;
/* voila, we're done! */
return t;
}
t = splay(remove->key,t);
/* Check if there is a list with identical sizes */
x = t->same;
if(x) {
/* 'x' is the new root node */
x->key = t->key;
x->larger = t->larger;
x->smaller = t->smaller;
return x; /* new root */
}
/* Remove the actualy root node: */
if (t->smaller == NULL) {
x = t->larger;
}
else {
x = splay(remove->key, t->smaller);
x->larger = t->larger;
}
return x;
}
#ifdef DEBUG_MALLOC
static
int printtree(Tree * t, int d, char output)
{
int distance=0;
Tree *node;
int i;
if (t == NULL)
return 0;
distance += printtree(t->larger, d+1, output);
for (i=0; i<d; i++)
if(output)
printf(" ");
if(output) {
printf("%d[%d]", t->key, i);
}
for(node = t->same; node; node = node->same) {
distance += i; /* this has the same "virtual" distance */
if(output)
printf(" [+]");
}
if(output)
puts("");
distance += i;
distance += printtree(t->smaller, d+1, output);
return distance;
}
#endif
/* Here follow the look-alike interface so that the tree-function names are
the same as the list-ones to enable easy interchange */
void bmalloc_remove_chunksize(void *data)
{
chunkHead = removebyaddr(chunkHead, data);
}
void bmalloc_insert_bysize(char *data, size_t size)
{
chunkHead = insert(size, chunkHead, (Tree *)data);
}
char *bmalloc_obtainbysize( size_t size)
{
Tree *receive;
chunkHead = removebestfit(size, chunkHead, &receive);
return (char *)receive;
}
#ifdef DEBUG_MALLOC
void bmalloc_print_sizes(void)
{
printtree(chunkHead, 0, 1);
}
#endif
#endif

View file

@ -1,24 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Daniel Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
void bmalloc_remove_chunksize(void *data);
void bmalloc_insert_bysize(char *data, size_t size);
char *bmalloc_obtainbysize( size_t size);
#ifdef DEBUG_MALLOC
void bmalloc_print_sizes(void);
#endif

View file

@ -1,634 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Daniel Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/*****************************************************************************
*
* Dynamic small-blocks Memory Allocation
*
* Author: Daniel Stenberg <daniel@haxx.se>
*
* Read THOUGHTS for theories and details on the implementation.
*
*****************************************************************************/
#include <stdio.h>
#include <string.h> /* memcpy */
#ifdef DEBUG_MALLOC
#include <stdarg.h>
#endif
#ifdef PSOS
#include <psos.h>
#define SEMAPHORE /* the PSOS routines use semaphore protection */
#else
#endif
#define BMALLOC /* we use our own big-malloc system */
#ifdef BMALLOC
#include "bmalloc.h"
#endif
/* Each TOP takes care of a chain of BLOCKS */
struct MemTop {
struct MemBlock *chain; /* pointer to the BLOCK chain */
long nfree; /* total number of free FRAGMENTS in the chain */
short nmax; /* total number of FRAGMENTS in this kind of BLOCK */
size_t fragsize; /* the size of each FRAGMENT */
#ifdef SEMAPHORE /* if we're protecting the list with SEMAPHORES */
long semaphore_id; /* semaphore used to lock this particular list */
#endif
};
/* Each BLOCK takes care of an amount of FRAGMENTS */
struct MemBlock {
struct MemTop *top; /* our TOP struct */
struct MemBlock *next; /* next BLOCK */
struct MemBlock *prev; /* prev BLOCK */
struct MemFrag *first; /* the first free FRAGMENT in this block */
short nfree; /* number of free FRAGMENTS in this BLOCK */
};
/* This is the data kept in all _free_ FRAGMENTS */
struct MemFrag {
struct MemFrag *next; /* next free FRAGMENT */
struct MemFrag *prev; /* prev free FRAGMENT */
};
/* This is the data kept in all _allocated_ FRAGMENTS and BLOCKS. We add this
to the allocation size first thing in the ALLOC function to make room for
this smoothly. */
struct MemInfo {
void *block;
/* which BLOCK is our father, if BLOCK_BIT is set it means this is a
stand-alone, large allocation and then the rest of the bits should be
treated as the size of the block */
#define BLOCK_BIT 1
};
/* ---------------------------------------------------------------------- */
/* Defines */
/* ---------------------------------------------------------------------- */
#ifdef DEBUG_VERBOSE
#define MEMINCR(addr,x) memchange(addr, x)
#define MEMDECR(addr,x) memchange(addr,-(x))
#else
#define MEMINCR(a,x)
#define MEMDECR(a,x)
#endif
/* The low level functions used to get memory from the OS and to return memory
to the OS, we may also define a stub that does the actual allocation and
free, these are the defined function names used in the dmalloc system
anyway: */
#ifdef PSOS
#ifdef DEBUG_MALLOC
#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
#define DMEM_OSFREEMEM(x) dbgfree(x)
#else
#define DMEM_OSALLOCMEM(size,pointer,type) rn_getseg(0,size,RN_NOWAIT,0,(void **)&pointer)
/* Similar, but this returns the memory */
#define DMEM_OSFREEMEM(x) rn_retseg(0, x)
#endif
/* Argument: <id> */
#define SEMAPHOREOBTAIN(x) sm_p(x, SM_WAIT, 0)
/* Argument: <id> */
#define SEMAPHORERETURN(x) sm_v(x)
/* Argument: <name> <id-variable name> */
#define SEMAPHORECREATE(x,y) sm_create(x, 1, SM_FIFO, (ULONG *)&(y))
#else
#ifdef BMALLOC /* use our own big-memory-allocation system */
#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)bmalloc(size)
#define DMEM_OSFREEMEM(x) bfree(x)
#elif DEBUG_MALLOC
#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)dbgmalloc(size)
#define DMEM_OSFREEMEM(x) dbgfree(x)
#else
#define DMEM_OSALLOCMEM(size,pointer,type) pointer=(type)malloc(size)
#define DMEM_OSFREEMEM(x) free(x)
#endif
#endif
/* the largest memory allocation that is made a FRAGMENT: (grab the highest
number from the list below) */
#define DMEM_LARGESTSIZE 2032
/* The total size of a BLOCK used for FRAGMENTS
In order to make this use only *1* even alignment from the big-block-
allocation-system (possible the bmalloc() system also written by me)
we need to subtract the [maximum] struct sizes that could get added all
the way through to the grab from the memory. */
#define DMEM_BLOCKSIZE 4064 /* (4096 - sizeof(struct MemBlock) - 12) */
/* Since the blocksize isn't an even 2^X story anymore, we make a table with
the FRAGMENT sizes and amounts that fills up a BLOCK nicely */
/* a little 'bc' script that helps us maximize the usage:
- for 32-bit aligned addresses (SPARC crashes otherwise):
for(i=20; i<2040; i+=4) { a=4064/i; if(a*i >= 4060) { {i;} } }
I try to approximate a double of each size, starting with ~20. We don't do
ODD sizes since several CPU flavours dump core when accessing such
addresses. We try to do 32-bit aligned to make ALL kinds of CPUs to remain
happy with us.
*/
static const unsigned short qinfo[]= {
20, 28, 52, 116, 312, 580, 1016, 2032
};
#define MIN(x,y) ((x)<(y)?(x):(y))
/* ---------------------------------------------------------------------- */
/* Globals */
/* ---------------------------------------------------------------------- */
/* keeper of the chain of BLOCKS */
static struct MemTop top[ sizeof(qinfo)/sizeof(qinfo[0]) ];
/* ---------------------------------------------------------------------- */
/* Start of the real code */
/* ---------------------------------------------------------------------- */
#ifdef DEBUG_MALLOC
/************
* A few functions that are verbose and tells us about the current status
* of the dmalloc system
***********/
void dmalloc_status(void)
{
unsigned int i;
int used;
int num;
int totalfree=0;
struct MemBlock *block;
for(i=0; i<sizeof(qinfo)/sizeof(qinfo[0]);i++) {
block = top[i].chain;
used = 0;
num = 0;
while(block) {
used += top[i].nmax-block->nfree;
num++;
block = block->next;
}
printf("Q %d (FRAG %4d), USED %4d FREE %4ld (SIZE %4ld) BLOCKS %d\n",
i, top[i].fragsize, used, top[i].nfree,
top[i].nfree*top[i].fragsize, num);
totalfree += top[i].nfree*top[i].fragsize;
}
printf("Total unused memory stolen by dmalloc: %d\n", totalfree);
}
#endif
#ifdef DEBUG_VERBOSE
static void dmalloc_failed(size_t size)
{
printf("*** " __FILE__ " Couldn't allocate %d bytes\n", size);
dmalloc_status();
}
#else
#define dmalloc_failed(x)
#endif
#ifdef DEBUG_VERBOSE
#define DBG(x) syslog x
void syslog(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stdout, fmt, ap);
va_end(ap);
}
void memchange(void *a, int x)
{
static int memory=0;
static int count=0;
static int max=0;
if(memory > max)
max = memory;
memory += x;
DBG(("%d. PTR %p / %d TOTAL %d MAX %d\n", ++count, a, x, memory, max));
}
#else
#define DBG(x)
#endif
/****************************************************************************
*
* FragBlock()
*
* This function makes FRAGMENTS of the BLOCK sent as argument.
*
***************************************************************************/
static void FragBlock(char *memp, int size)
{
struct MemFrag *frag=(struct MemFrag *)memp;
struct MemFrag *prev=NULL; /* no previous in the first round */
int count=0;
while((count+size) <= DMEM_BLOCKSIZE) {
frag->next = (struct MemFrag *)((char *)frag + size);
frag->prev = prev;
prev = frag;
(char *)frag += size;
count += size;
}
prev->next = NULL; /* the last one has no next struct */
}
/***************************************************************************
*
* dmalloc_initialize();
*
* Call before the first dmalloc(). Inits a few memory things.
*
**************************************************************************/
void dmalloc_initialize(void)
{
unsigned int i;
/* Setup the nmax and fragsize fields of the top structs */
for(i=0; i< sizeof(qinfo)/sizeof(qinfo[0]); i++) {
top[i].fragsize = qinfo[i];
top[i].nmax = DMEM_BLOCKSIZE/qinfo[i];
#ifdef PSOS
/* for some reason, these aren't nulled from start: */
top[i].chain = NULL; /* no BLOCKS */
top[i].nfree = 0; /* no FRAGMENTS */
#endif
#ifdef SEMAPHORE
{
char name[7];
snprintf(name, 7, "MEM%d", i);
SEMAPHORECREATE(name, top[i].semaphore_id);
/* doesn't matter if it failed, we continue anyway ;-( */
}
#endif
}
}
/****************************************************************************
*
* fragfromblock()
*
* This should return a fragment from the block and mark it as used
* accordingly.
*
***************************************************************************/
static void *fragfromblock(struct MemBlock *block)
{
/* make frag point to the first free FRAGMENT */
struct MemFrag *frag = block->first;
struct MemInfo *mem = (struct MemInfo *)frag;
/*
* Remove the FRAGMENT from the list and decrease the free counters.
*/
block->first = frag->next; /* new first free FRAGMENT */
block->nfree--; /* BLOCK counter */
block->top->nfree--; /* TOP counter */
/* heal the FRAGMENT list */
if(frag->prev) {
frag->prev->next = frag->next;
}
if(frag->next) {
frag->next->prev = frag->prev;
}
mem->block = block; /* no block bit set here */
return ((char *)mem)+sizeof(struct MemInfo);
}
/***************************************************************************
*
* dmalloc()
*
* This needs no explanation. A malloc() look-alike.
*
**************************************************************************/
void *malloc(size_t size)
{
void *mem;
DBG(("malloc(%d)\n", size));
/* First, we make room for the space needed in every allocation */
size += sizeof(struct MemInfo);
if(size < DMEM_LARGESTSIZE) {
/* get a FRAGMENT */
struct MemBlock *block=NULL; /* SAFE */
struct MemBlock *newblock=NULL; /* SAFE */
struct MemTop *memtop=NULL; /* SAFE */
/* Determine which queue to use */
unsigned int queue;
for(queue=0; size > qinfo[queue]; queue++)
;
do {
/* This is the head master of our chain: */
memtop = &top[queue];
DBG(("Top info: CHAIN %p FREE %d MAX %d FRAGSIZE %d\n",
memtop->chain,
memtop->nfree,
memtop->nmax,
memtop->fragsize));
#ifdef SEMAPHORE
if(SEMAPHOREOBTAIN(memtop->semaphore_id))
return NULL; /* failed somehow */
#endif
/* get the first BLOCK in the chain */
block = memtop->chain;
/* check if we have a free FRAGMENT */
if(memtop->nfree) {
/* there exists a free FRAGMENT in this chain */
/**** We'd prefer to not have this loop here! ****/
/* search for the free FRAGMENT */
while(!block->nfree)
block = block->next; /* check next BLOCK */
/*
* Now 'block' is the first BLOCK with a free FRAGMENT
*/
mem = fragfromblock(block);
}
else {
/* we do *not* have a free FRAGMENT but need to get us a new
* BLOCK */
DMEM_OSALLOCMEM(DMEM_BLOCKSIZE + sizeof(struct MemBlock),
newblock,
struct MemBlock *);
if(!newblock) {
if(++queue < sizeof(qinfo)/sizeof(qinfo[0])) {
/* There are queues for bigger FRAGMENTS that we
* should check before we fail this for real */
#ifdef DEBUG_VERBOSE
printf("*** " __FILE__ " Trying a bigger Q: %d\n",
queue);
#endif
mem = NULL;
}
else {
dmalloc_failed(size- sizeof(struct MemInfo));
return NULL; /* not enough memory */
}
}
else {
/* allocation of big BLOCK was successful */
MEMINCR(newblock, DMEM_BLOCKSIZE +
sizeof(struct MemBlock));
memtop->chain = newblock; /* attach this BLOCK to the
chain */
newblock->next = block; /* point to the previous first
BLOCK */
if(block)
block->prev = newblock; /* point back on this new
BLOCK */
newblock->prev = NULL; /* no previous */
newblock->top = memtop; /* our head master */
/* point to the new first FRAGMENT */
newblock->first = (struct MemFrag *)
((char *)newblock+sizeof(struct MemBlock));
/* create FRAGMENTS of the BLOCK: */
FragBlock((char *)newblock->first, memtop->fragsize);
/* fix the nfree counters */
newblock->nfree = memtop->nmax;
memtop->nfree += memtop->nmax;
/* get a FRAGMENT from the BLOCK */
mem = fragfromblock(newblock);
}
}
#ifdef SEMAPHORE
SEMAPHORERETURN(memtop->semaphore_id); /* let it go */
#endif
} while(NULL == mem); /* if we should retry a larger FRAGMENT */
}
else {
/* get a stand-alone BLOCK */
struct MemInfo *meminfo;
if(size&1)
/* don't leave this with an odd size since we'll use that bit for
information */
size++;
DMEM_OSALLOCMEM(size, meminfo, struct MemInfo *);
if(meminfo) {
MEMINCR(meminfo, size);
meminfo->block = (void *)(size|BLOCK_BIT);
mem = (char *)meminfo + sizeof(struct MemInfo);
}
else {
dmalloc_failed(size);
mem = NULL;
}
}
return (void *)mem;
}
/***************************************************************************
*
* dfree()
*
* This needs no explanation. A free() look-alike.
*
**************************************************************************/
void free(void *memp)
{
struct MemInfo *meminfo = (struct MemInfo *)
((char *)memp- sizeof(struct MemInfo));
DBG(("free(%p)\n", memp));
if(!((size_t)meminfo->block&BLOCK_BIT)) {
/* this is a FRAGMENT we have to deal with */
struct MemBlock *block=meminfo->block;
struct MemTop *memtop = block->top;
#ifdef SEMAPHORE
SEMAPHOREOBTAIN(memtop->semaphore_id);
#endif
/* increase counters */
block->nfree++;
memtop->nfree++;
/* is this BLOCK completely empty now? */
if(block->nfree == memtop->nmax) {
/* yes, return the BLOCK to the system */
if(block->prev)
block->prev->next = block->next;
else
memtop->chain = block->next;
if(block->next)
block->next->prev = block->prev;
memtop->nfree -= memtop->nmax; /* total counter subtraction */
MEMDECR(block, DMEM_BLOCKSIZE + sizeof(struct MemBlock));
DMEM_OSFREEMEM((void *)block); /* return the whole block */
}
else {
/* there are still used FRAGMENTS in the BLOCK, link this one
into the chain of free ones */
struct MemFrag *frag = (struct MemFrag *)meminfo;
frag->prev = NULL;
frag->next = block->first;
if(block->first)
block->first->prev = frag;
block->first = frag;
}
#ifdef SEMAPHORE
SEMAPHORERETURN(memtop->semaphore_id);
#endif
}
else {
/* big stand-alone block, just give it back to the OS: */
/* clean BLOCK_BIT */
MEMDECR(meminfo->block, (size_t)meminfo->block&~BLOCK_BIT);
DMEM_OSFREEMEM((void *)meminfo);
}
}
/***************************************************************************
*
* drealloc()
*
* This needs no explanation. A realloc() look-alike.
*
**************************************************************************/
void *realloc(void *ptr, size_t size)
{
struct MemInfo *meminfo = (struct MemInfo *)
((char *)ptr- sizeof(struct MemInfo));
/*
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* NOTE: the ->size field of the meminfo will now contain the MemInfo
* struct size too!
* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*/
void *mem=NULL; /* SAFE */
size_t prevsize;
/* NOTE that this is only valid if BLOCK_BIT isn't set: */
struct MemBlock *block;
DBG(("realloc(%p, %d)\n", ptr, size));
if(NULL == ptr)
return malloc( size );
block = meminfo->block;
/* Here we check if this is a FRAGMENT and if the new size is
still smaller than the fragsize for this block. */
if(!((size_t)block&BLOCK_BIT) &&
(size + sizeof(struct MemInfo) < block->top->fragsize )) {
prevsize = block->top->fragsize;
/* This is a FRAGMENT and new size is possible to retain within the
same FRAGMENT */
if((prevsize > qinfo[0]) &&
/* this is not the smallest memory Q */
(size < (block->top-1)->fragsize))
/* This fits in a smaller fragment, so we will make a realloc
here */
;
else
mem = ptr; /* Just return the same pointer as we got in. */
}
if(!mem) {
if((size_t)meminfo->block&BLOCK_BIT) {
/* This is a stand-alone BLOCK */
prevsize = ((size_t)meminfo->block&~BLOCK_BIT) -
sizeof(struct MemInfo);
}
else
/* a FRAGMENT realloc that no longer fits within the same FRAGMENT
* or one that fits in a smaller */
prevsize = block->top->fragsize;
/* No tricks involved here, just grab a new bite of memory, copy the
* data from the old place and free the old memory again. */
mem = malloc(size);
if(mem) {
memcpy(mem, ptr, MIN(size, prevsize) );
free(ptr);
}
}
return mem;
}
/***************************************************************************
*
* dcalloc()
*
* This needs no explanation. A calloc() look-alike.
*
**************************************************************************/
/* Allocate an array of NMEMB elements each SIZE bytes long.
The entire array is initialized to zeros. */
void *
calloc (size_t nmemb, size_t size)
{
void *result = malloc (nmemb * size);
if (result != NULL)
memset (result, 0, nmemb * size);
return result;
}

View file

@ -1,36 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by Daniel Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _DMALLOC_H_
#define _DMALLOC_H_
#include <stdlib.h>
void *malloc(size_t);
void *calloc (size_t nmemb, size_t size);
void free(void *);
void *realloc(void *, size_t);
/* use this to intialize the internals of the dmalloc engine */
void dmalloc_initialize(void);
#ifdef DEBUG
void dmalloc_status(void);
#endif
#endif

View file

@ -1,844 +0,0 @@
/*
//////////////////////////////////////////////////////////////////////////////////
// __________ __ ___. //
// Open \______ \ ____ ____ | | _\_ |__ _______ ___ //
// Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / //
// Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < //
// Software |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ //
// \/ \/ \/ \/ \/ //
//////////////////////////////////////////////////////////////////////////////////
//
// $Id$
//
/////////////////////////////////////
// Copyright (C) 2002 by Alan Korr //
/////////////////////////////////////
//
// All files in this archive are subject to the GNU General Public License.
// See the file COPYING in the source tree root for full license agreement.
//
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
// either express or implied.
//
//////////////////////////////////////////////////////////////////////////////////
*/
#include "memory.h"
#define MEMORY_PAGE_USE_SPLAY_TREE
/*
/////////////////////////////////////////////////////////////////////
// MEMORY PAGE //
/////////////////
//
//
*/
struct __memory_free_page
{
struct __memory_free_page *less,*more;
char reserved[MEMORY_PAGE_MINIMAL_SIZE - 2*sizeof (struct memory_free_page *)];
};
#define LESS -1
#define MORE +1
extern struct __memory_free_page __memory_free_page[MEMORY_TOTAL_PAGES] asm("dram");
char __memory_free_page_order[MEMORY_TOTAL_PAGES];
struct __memory_free_page *__memory_free_page_bin[MEMORY_TOTAL_ORDERS];
static inline unsigned int __memory_get_size (int order)
/*
SH1 has very poor shift instructions (only <<1,>>1,<<2,>>2,<<8,
>>8,<<16 and >>16), so we should use a lookup table to speedup.
*/
{
return
(
(unsigned short [MEMORY_TOTAL_ORDERS])
{
1<<MEMORY_PAGE_MINIMAL_ORDER,
2<<MEMORY_PAGE_MINIMAL_ORDER,
4<<MEMORY_PAGE_MINIMAL_ORDER,
8<<MEMORY_PAGE_MINIMAL_ORDER,
16<<MEMORY_PAGE_MINIMAL_ORDER,
32<<MEMORY_PAGE_MINIMAL_ORDER,
64<<MEMORY_PAGE_MINIMAL_ORDER,
128<<MEMORY_PAGE_MINIMAL_ORDER,
256<<MEMORY_PAGE_MINIMAL_ORDER,
512<<MEMORY_PAGE_MINIMAL_ORDER,
1024<<MEMORY_PAGE_MINIMAL_ORDER,
2048<<MEMORY_PAGE_MINIMAL_ORDER,
4096<<MEMORY_PAGE_MINIMAL_ORDER
}
)[order];
}
static inline struct __memory_free_page *__memory_get_neighbour (struct __memory_free_page *node,unsigned int size)
{
return ((struct __memory_free_page *)((unsigned)node ^ size));
}
static inline int __memory_get_order (struct __memory_free_page *node)
{
return __memory_free_page_order[node - __memory_free_page];
}
static inline void __memory_set_order (struct __memory_free_page *node,int order)
{
__memory_free_page_order[node - __memory_free_page] = order;
}
#ifdef MEMORY_PAGE_USE_SPLAY_TREE
static struct __memory_free_page *__memory_splay_page (struct __memory_free_page *root,struct __memory_free_page *node)
{
struct __memory_free_page *down;
struct __memory_free_page *less;
struct __memory_free_page *more;
struct __memory_free_page *head[2];
((struct __memory_free_page *)head)->less =
((struct __memory_free_page *)head)->more = 0;
less =
more = &head;
while (1)
{
if (node < root)
{
if ((down = root->less))
{
if (node < down)
{
root->less = down->more;
down->more = root;
root = down;
if (!root->less)
break;
}
more->less = root;
more = root;
root = root->less;
continue;
}
break;
}
if (root < node)
{
if ((down = root->more))
{
if (root < node)
{
root->more = down->less;
down->less = root;
root = down;
if (!root->more)
break;
}
less->more = root;
less = root;
root = root->more;
continue;
}
}
break;
}
less->more = root->less;
more->less = root->more;
root->less = ((struct __memory_free_page *)head)->more;
root->more = ((struct __memory_free_page *)head)->less;
return root;
}
static inline void __memory_insert_page (int order,struct __memory_free_page *node)
{
struct __memory_free_page *root = __memory_free_page_bin[order];
if (!root)
{
node->less =
node->more = 0;
}
else if (node < (root = __memory_splay_page (root,node)))
{
node->less = root->less;
node->more = root;
root->less = 0;
}
else if (node > root)
{
node->less = root;
node->more = root->more;
node->more = 0;
}
__memory_free_page_bin[order] = node;
__memory_set_order (node,order);
return;
}
static inline struct __memory_free_page *__memory_pop_page (int order,int want)
{
struct __memory_free_page *root = __memory_free_page_bin[order];
if (root)
{
root = __memory_splay_page (root,__memory_free_page);
__memory_free_page_bin[order] = root->more;
__memory_set_order (root,~want);
}
return root;
}
static inline void __memory_remove_page (int order,struct __memory_free_page *node)
{
struct __memory_free_page *root = __memory_free_page_bin[order];
root = __memory_splay_page (root,node);
if (root->less)
{
node = __memory_splay_page (root->less,node);
node->more = root->more;
}
else
node = root->more;
__memory_free_page_bin[order] = node;
}
#else
static inline void __memory_insert_page (int order,struct __memory_free_page *node)
{
struct __memory_free_page *head = __memory_free_page_bin[order];
node->less = 0;
node->more = head;
if (head)
head->less = node;
__memory_free_page_bin[order] = node;
__memory_set_order (node,order);
}
static inline struct __memory_free_page *pop_page (int order,int want)
{
struct __memory_free_page *node = __memory_free_page_bin[order];
if (node)
{
__memory_free_page_bin[order] = node->more;
if (node->more)
node->more->less = 0;
__memory_set_order (node,~want);
}
return node;
}
static inline void __memory_remove_page (int order,struct __memory_free_page *node)
{
if (node->less)
node->less->more = node->more;
else
__memory_free_page_bin[order] = node->more;
if (node->more)
node->more->less = node->less;
}
#endif
static inline void __memory_push_page (int order,struct __memory_free_page *node)
{
node->less = 0;
node->more = 0;
__memory_free_page_bin[order] = node;
__memory_set_order (node,order);
}
static struct __memory_free_page *__memory_allocate_page (unsigned int size,int order)
{
struct __memory_free_page *node;
int min = order;
while ((unsigned)order <= (MEMORY_TOTAL_ORDERS - 1))
/* order is valid ? */
{
if (!(node = __memory_pop_page (order,min)))
/* no free page of this order ? */
{
++order; size <<= 1;
continue;
}
while (order > min)
/* split our larger page in smaller pages */
{
--order; size >>= 1;
__memory_push_page (order,(struct __memory_free_page *)((unsigned int)node + size));
}
return node;
}
return MEMORY_RETURN_FAILURE;
}
static inline void __memory_release_page (struct __memory_free_page *node,unsigned int size,int order)
{
struct __memory_free_page *neighbour;
while ((order <= (MEMORY_TOTAL_ORDERS - 1)) &&
((neighbour = __memory_get_neighbour (node,size)),
(__memory_get_order (neighbour) == order)))
/* merge our released page with its contiguous page into a larger page */
{
__memory_remove_page (order,neighbour);
++order; size <<= 1;
if (neighbour < node)
node = neighbour;
}
__memory_insert_page (order,node);
}
void *memory_page_allocate (int order)
{
if ((unsigned)order < MEMORY_TOTAL_ORDERS)
return MEMORY_RETURN_FAILURE;
return __memory_allocate_page (__memory_get_size (order),order);
}
int memory_page_release (void *address)
{
struct __memory_free_page *node = (struct __memory_free_page *)address;
int order = ~__memory_get_order (node);
if ((unsigned)order < MEMORY_TOTAL_ORDERS)
return MEMORY_RETURN_FAILURE;
__memory_release_page (node,__memory_get_size (order),order);
return MEMORY_RETURN_SUCCESS;
}
void memory_page_release_range (unsigned int start,unsigned int end)
{
start = ((start + MEMORY_PAGE_MINIMAL_SIZE - 1) & -MEMORY_PAGE_MINIMAL_SIZE;
end = ((end ) & -MEMORY_PAGE_MINIMAL_SIZE;
/* release pages between _start_ and _end_ (each must be 512 bytes long) */
for (; start < end; start += MEMORY_PAGE_MINIMAL_SIZE)
memory_page_release (start);
}
static inline void __memory_page_setup (void)
{
#if 0
memory_set (__memory_free_page_bin,0,MEMORY_TOTAL_ORDERS *sizeof (struct memory_free_page *));
#endif
/* all pages are marked as used (no free page) */
memory_set (__memory_free_page_order,~0,MEMORY_TOTAL_PAGES);
}
/*
//
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// MEMORY CACHE //
//////////////////
//
//
*/
#if 0
#define MEMORY_MAX_PAGE_ORDER_PER_SLAB (5)
#define MEMORY_MAX_PAGE_SIZE_PER_SLAB (MEMORY_PAGE_MINIMAL_SIZE << MEMORY_MAX_PAGE_ORDER_PER_SLAB)
#define MEMORY_MIN_BLOCKS_PER_SLAB (4)
struct __memory_free_block
{
struct __memory_free_block *link;
};
struct __memory_slab
{
struct __memory_slab *less,*more;
unsigned int free_blocks_left;
struct __memory_free_block *free_block_list;
};
#define WITH_NO_FREE_BLOCK 0
#define WITH_SOME_FREE_BLOCKS 1
#define WITH_ONLY_FREE_BLOCKS 2
struct memory_cache
{
struct memory_cache *less;
struct memory_cache *more;
struct memory_cache *prev;
struct memory_cache *next;
struct __memory_slab *slab_list[3];
unsigned int page_size;
unsigned int free_slabs_left;
unsigned short size;
unsigned short original_size;
int page_order;
unsigned int blocks_per_slab;
struct __memory_slab cache_slab; /* only used for __memory_cache_cache ! */
};
static inline struct __memory_slab *__memory_push_slab (struct __memory_slab *head,struct __memory_slab *node)
{
node->less = head;
if (head)
{
node->more = head->more;
head->more = node;
}
else
node->more = 0;
return node;
}
static inline struct __memory_slab *__memory_pop_slab (struct __memory_slab *head,struct __memory_slab *node)
{
if (head)
head->more = node->more;
return node->more;
}
static inline struct __memory_slab *__memory_move_slab (struct memory_cache *cache,int from,int to)
{
struct __memory_slab *head = cache->slab_list[from];
cache->slab_list[from] = head->more;
if (head->more)
head->more->less = 0;
head->more = cache->slab_list[to];
if (head->more)
head->more->prev = head;
cache->slab_list[to] = head;
return head;
}
static struct memory_cache *__memory_cache_tree;
static struct memory_cache *__memory_cache_cache;
static inline int __memory_get_order (unsigned size)
{
int order = 0;
size = (size + MEMORY_PAGE_MINIMAL_SIZE - 1) & -MEMORY_PAGE_MINIMAL_SIZE;
while (size > MEMORY_PAGE_MINIMAL_SIZE)
{
++order; size <<= 1;
}
return order;
}
static inline struct __memory_slab *__memory_get_slab (struct memory_cache *cache,void *address)
{
return (struct __memory_slab *)((((unsigned)address + cache->page_size) & -cache->page_size) - sizeof (struct __memory_slab));
}
static struct memory_cache *__memory_splay_cache (struct memory_cache *root,unsigned int left)
{
struct memory_cache *down;
struct memory_cache *less;
struct memory_cache *more;
struct memory_cache *head[2];
((struct memory_cache *)head->less =
((struct memory_cache *)head->more = 0;
less =
more = &head;
while (1)
{
if (left < root->free_slabs_left)
{
if ((down = root->less))
{
if (left < down->free_slabs_left)
{
root->less = down->more;
down->more = root;
root = down;
if (!root->less)
break;
}
more->less = root;
more = root;
root = root->less;
continue;
}
break;
}
if (root->free_slabs_left < left)
{
if ((down = root->more))
{
if (root->free_slabs_left < left)
{
root->more = down->less;
down->less = root;
root = down;
if (!root->more)
break;
}
less->more = root;
less = root;
root = root->more;
continue;
}
}
break;
}
less->more = root->less;
more->less = root->more;
root->less = ((struct memory_cache *)head->more;
root->more = ((struct memory_cache *)head->less;
return root;
}
static inline struct memory_cache *__memory_insert_cache (struct memory_cache *root,struct memory_cache *node)
{
node->less =
node->more =
node->prev = 0;
node->next = 0;
if (root)
{
if (node->free_slabs_left == ((root = __memory_splay_cache (root,node))->free_slabs_left))
{
node->less = root.less;
node->more = root.more;
node->next = root;
root->prev = node;
}
else if (node < root)
{
node->less = root->less;
node->more = root;
root->less = 0;
}
else
{
node->less = root;
node->more = root->more;
node->more = 0;
}
}
return node;
}
static inline struct memory_cache *__memory_remove_cache (struct memory_cache *root,struct memory_cache *node)
{
if (root)
{
if (node->prev)
{
node->prev->next = node->next;
if (node->next)
node->next->prev = node->prev;
return node->prev;
}
root = __memory_splay_cache (root,node);
if (root->less)
{
node = __memory_splay_page (root->less,node);
node->more = root->more;
}
else
node = root->more;
}
return node;
}
static inline struct memory_cache *__memory_move_cache (struct memory_cache *root,struct memory_cache *node,int delta)
{
if ((root = __memory_remove_cache (root,node)))
{
node->free_slabs_left += delta;
root = __memory_insert_cache (root,node);
}
return root;
}
static struct __memory_slab *__memory_grow_cache (struct memory_cache *cache)
{
struct __memory_slab *slab;
unsigned int page;
if (cache)
{
page = (unsigned int)memory_allocate_page (cache->page_order);
if (page)
{
struct __memory_free_block *block,**link;
slab = (struct __memory_slab *)(page + cache->page_size - sizeof (struct __memory_slab));
slab->free_blocks_left = 0;
link = &slab->free_block_list;
for ((unsigned int)block = page;
(unsigned int)block + cache->size < (unsigned int)slab;
(unsigned int)block += cache->size)
{
*link = block;
link = &block->link;
++slab->free_blocks_left;
}
*link = 0;
cache->blocks_per_slab = slab->free_blocks_left;
cache->slab_list[WITH_ONLY_FREE_BLOCKS] =
__memory_push_slab (cache->slab_list[WITH_ONLY_FREE_BLOCKS],slab);
__memory_cache_tree = __memory_move_cache (__memory_cache_tree,cache,+1);
return slab;
}
}
return MEMORY_RETURN_FAILURE;
}
static int __memory_shrink_cache (struct memory_cache *cache,int all,int move)
{
struct __memory_slab *slab;
unsigned int slabs = 0;
if (cache)
{
while ((slab = cache->slab_list[WITH_ONLY_FREE_BLOCKS]))
{
++slabs;
cache->slab_list[WITH_ONLY_FREE_BLOCKS] =
__memory_pop_slab (cache->slab_list[WITH_ONLY_FREE_BLOCKS],slab);
memory_release_page ((void *)((unsigned int)slab & -cache->page_size));
if (all)
continue;
if (move)
__memory_cache_tree = __memory_move_cache (__memory_cache_tree,cache,-slabs);
return MEMORY_RETURN_SUCCESS;
}
}
return MEMORY_RETURN_FAILURE;
}
struct memory_cache *memory_cache_create (unsigned int size,int align)
{
struct memory_cache *cache;
unsigned int waste = 0,blocks_per_page;
int page_order;
unsigned int page_size;
unsigned int original_size = size;
size = (align > 4) ? ((size + align - 1) & -align) : ((size + sizeof (int) - 1) & -sizeof (int));
if ((size >= MEMORY_MAX_PAGE_SIZE_PER_SLAB) ||
(!(cache = memory_cache_allocate (__memory_cache_cache)))
return MEMORY_RETURN_FAILURE;
cache->free_slabs_left = 0;
cache->slab_list[ WITH_NO_FREE_BLOCK ] =
cache->slab_list[WITH_SOME_FREE_BLOCKS] =
cache->slab_list[WITH_ONLY_FREE_BLOCKS] = 0;
cache->original_size = original_size;
cache->size = size;
page_size = 0;
page_order = MEMORY_PAGE_MINIMAL_SIZE;
for (;; ++order,(page_size <<= 1))
{
if (page_order >= MEMORY_MAX_PAGE_ORDER_PER_SLAB)
break;
waste = page_size;
waste -= sizeof (struct __memory_slab);
blocks_per_slab = waste / size;
waste -= block_per_slab * size;
if (blocks_per_slab < MEMORY_MIN_BLOCKS_PER_SLAB)
{
++page_order; page_size <<= 1;
continue;
}
/* below 5% of lost space is correct */
if ((waste << 16) / page_size) < 3276)
break;
++page_order; page_size <<= 1;
}
cache->page_size = page_size;
cache->page_order = page_order;
cache_tree = __memory_insert_cache (cache_tree,cache);
return cache;
}
int memory_cache_destroy (struct memory_cache *cache)
{
/* this function shouldn't be called if there are still used blocks */
if (cache && !cache->slab_list[WITH_NO_FREE_BLOCK] && !cache->slab_list[WITH_SOME_FREE_BLOCKS])
{
__memory_cache_tree = __memory_remove_cache (__memory_cache_tree,cache);
if (__memory_shrink_cache (cache,1 /* release all free slabs */,0 /* don't move in cache_tree */))
return memory_cache_release (__memory_cache_cache,cache);
}
return MEMORY_RETURN_FAILURE;
}
void *memory_cache_allocate (struct memory_cache *cache)
{
if (cache)
{
do
{
struct __memory_slab *slab;
if ((slab = cache->slab_list[WITH_SOME_FREE_BLOCKS]))
{
if (slab->free_blocks_left > 0)
{
ok: struct __memory_free_block *block = slab->free_block_list;
slab->free_block_list = block->link;
if (--slab->free_blocks_left == 0)
__memory_move_slab (WITH_SOME_FREE_BLOCKS,WITH_NO_FREE_BLOCK);
return block;
}
}
if (cache->slab_list[WITH_FULL_FREE_BLOCKS])
{
slab = __memory_move_slab (WITH_ONLY_FREE_BLOCKS,WITH_SOME_FREE_BLOCKS);
__memory_cache_tree = __memory_move_cache (__memory_cache_tree,cache,-1);
goto ok;
}
}
while (__memory_grow_cache (cache));
}
return MEMORY_RETURN_FAILURE;
}
int memory_cache_release (struct memory_cache *cache,void *address)
{
struct __memory_slab *slab = __memory_get_slab (cache,address);
((struct __memory_free_block *)address)->link = slab->free_block_list;
slab->free_block_list = (struct __memory_free_block *)address;
if (slab->free_blocks_left++ == 0)
__memory_move_slab (WITH_NO_FREE_BLOCK,WITH_SOME_FREE_BLOCKS);
else if (slab->free_blocks_left == cache->blocks_per_slab)
{
__memory_move_slab (WITH_SOME_FREE_BLOCKS,WITH_ONLY_FREE_BLOCKS);
__memory_cache_tree = __memory_move_cache (__memory_cache_tree,cache,+1);
}
return MEMORY_RETURN_SUCCESS;
}
static inline void __memory_cache_setup (void)
{
struct memory_cache *cache;
struct __memory_slab *slab;
struct __memory_free_block *block,**link;
cache = (struct memory_cache *)__memory_free_page;
cache->original_size = sizeof (*cache);
cache->size = sizeof (*cache);
cache->page_size = MEMORY_PAGE_MINIMAL_SIZE;
cache->page_order = MEMORY_PAGE_MINIMAL_ORDER;
cache->free_slabs_left = 0;
slab = __memory_get_slab (cache,(void *)cache);
cache->slab_list[ WITH_NO_FREE_BLOCK ] =
cache->slab_list[WITH_SOME_FREE_BLOCKS] =
cache->slab_list[WITH_ONLY_FREE_BLOCKS] = 0;
link = &slab->free_block_list;
for ((unsigned int)block = (unsigned int)cache;
(unsigned int)block + sizeof (*cache) < (unsigned int)slab;
(unsigned int)block += sizeof (*cache))
{
*link = block;
link = &block->link;
++slab->free_blocks_left;
}
*link = 0;
cache->blocks_per_slab = slab->free_blocks_left + 1;
cache->slab_list[WITH_SOME_FREE_BLOCKS] =
__memory_push_slab (cache->slab_list[WITH_SOME_FREE_BLOCKS],slab);
__memory_cache_tree = __memory_insert_cache (__memory_cache_tree,cache);
}
/*
//
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// MEMORY BLOCK //
//////////////////
//
//
*/
static struct memory_cache *__memory_free_block_cache[MEMORY_PAGE_MINIMAL_ORDER - 2];
static inline void *__memory_allocate_block (int order)
{
struct memory_cache *cache = __memory_free_block_cache[order - 2];
do
{
if (cache)
return memory_cache_allocate (cache);
}
while ((__memory_free_block_cache[order] = cache = memory_create_cache (size,0,0)));
return MEMORY_RETURN_FAILURE;
}
static inline int __memory_release_block (int order,void *address)
{
struct memory_cache *cache = __memory_free_block_cache[order - 2];
if (cache)
return memory_cache_release (cache,address);
return MEMORY_RETURN_FAILURE;
}
void *memory_block_allocate (int order)
{
if (order < 2) /* minimal size is 4 bytes */
order = 2;
if (order < MEMORY_PAGE_MINIMAL_ORDER)
return __memory_allocate_block (order);
return MEMORY_RETURN_FAILURE;
}
int memory_block_release (int order,void *address)
{
if (order < 2) /* minimal size is 4 bytes */
order = 2;
if (order < MEMORY_PAGE_MINIMAL_ORDER)
return __memory_release_block (order,address);
return MEMORY_RETURN_FAILURE;
}
/*
//
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// MEMORY //
////////////
//
//
*/
#endif
#if 0
/* NOT VERY OPTIMIZED AT ALL BUT WE WILL DO IT WHEN PRIORITY COMES */
void memory_copy (void *target,void const *source,unsigned int count)
{
while (count--)
*((char *)target)++ = *((char const *)source)++;
}
/* NOT VERY OPTIMIZED AT ALL BUT WE WILL DO IT WHEN PRIORITY COMES */
void memory_set (void *target,int byte,unsigned int count)
{
while (count--)
*((char *)target)++ = (char)byte;
}
#endif
void memory_setup (void)
{
__memory_page_setup ();
#if 0
__memory_cache_setup ();
#endif
}

View file

@ -1,113 +0,0 @@
/*
//////////////////////////////////////////////////////////////////////////////////
// __________ __ ___. //
// Open \______ \ ____ ____ | | _\_ |__ _______ ___ //
// Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / //
// Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < //
// Software |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ //
// \/ \/ \/ \/ \/ //
//////////////////////////////////////////////////////////////////////////////////
//
// $Id$
//
/////////////////////////////////////
// Copyright (C) 2002 by Alan Korr //
/////////////////////////////////////
//
// All files in this archive are subject to the GNU General Public License.
// See the file COPYING in the source tree root for full license agreement.
//
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
// either express or implied.
//
//////////////////////////////////////////////////////////////////////////////////
*/
#ifndef __MEMORY_H__
#define __MEMORY_H__
enum
{
MEMORY_RETURN_SUCCESS = 1,
MEMORY_RETURN_FAILURE = 0
};
/*
/////////////////////////////////////////////////////////////////////
// MEMORY PAGE //
/////////////////
//
//
*/
#define MEMORY_PAGE_MINIMAL_ORDER ( 9) /* 512 bytes by default */
#define MEMORY_PAGE_MAXIMAL_ORDER (21) /* 2 Mbytes by default */
#define MEMORY_PAGE_MINIMAL_SIZE (1 << MEMORY_PAGE_MINIMAL_ORDER)
#define MEMORY_PAGE_MAXIMAL_SIZE (1 << MEMORY_PAGE_MAXIMAL_ORDER)
#define MEMORY_TOTAL_PAGES (MEMORY_PAGE_MAXIMAL_SIZE / MEMORY_PAGE_MINIMAL_SIZE)
#define MEMORY_TOTAL_ORDERS (1 + MEMORY_PAGE_MAXIMAL_ORDER - MEMORY_PAGE_MINIMAL_ORDER)
extern void *memory_page_allocate (int order);
extern int memory_page_release (void *address);
extern void memory_page_release_range (unsigned int start,unsigned int end);
/*
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// MEMORY CACHE //
//////////////////
//
//
*/
struct memory_cache;
extern struct memory_cache *memory_cache_create (unsigned int size,int align);
extern int memory_cache_destroy (struct memory_cache *cache);
extern void *memory_cache_allocate (struct memory_cache *cache);
extern int memory_cache_release (struct memory_cache *cache,void *address);
/*
//
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// MEMORY BLOCK //
//////////////////
//
//
*/
extern void *memory_block_allocate (int order);
extern int memory_block_release (int order,void *address);
/*
//
//
/////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
// MEMORY //
////////////
//
//
*/
#define MEMORY_TOTAL_BYTES (MEMORY_PAGE_MAXIMAL_SIZE)
extern void memory_copy (void *target,void const *source,unsigned int count);
extern void memory_set (void *target,int byte,unsigned int count);
extern void memory_setup (void);
/*
//
//
/////////////////////////////////////////////////////////////////////
*/
#endif

View file

@ -1,36 +0,0 @@
OBJS1 = mytest.o
TARGET1 = mytest
OBJS2 = Malloc.o
TARGET2 = mtest
OBJS3 = dmytest.o
TARGET3 = dmytest
# define this to talk a lot in runtime
# -DDEBUG_VERBOSE
CFLAGS = -g -Wall -DDEBUG -I../../malloc
CC = gcc
AR = ar
LDFLAGS = -L../../malloc -ldmalloc
all: $(TARGET1) $(TARGET2) $(TARGET3)
clean:
rm -f core *~ $(TARGET1) $(TARGET2) $(TARGET3) \
$(OBJS1) $(OBJS2) $(OBJS3)
$(TARGET1): $(OBJS1)
$(CC) -g -o $(TARGET1) $(OBJS1) $(LDFLAGS)
$(TARGET2): $(OBJS2)
$(CC) -g -o $(TARGET2) $(OBJS2) $(LDFLAGS)
$(TARGET3): $(OBJS3)
$(CC) -g -o $(TARGET3) $(OBJS3) $(LDFLAGS)
dmytest.o: dmytest.c
Malloc.o: Malloc.c
mytest.o: mytest.c

View file

@ -1,196 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Storleken på allokeringen bestäms genom att först slumpas en position i
"size_table" ut, sedan slumpas en storlek mellan den postionen och nästa värde
i tabellen. Genom att ha tabellen koncentrerad med låga värden, skapas
flest såna. Rutinen håller tills minnet en allokeringen nekas. Den kommer
aldrig att ha mer än MAXIMAL_MEMORY_TO_ALLOCATE allokerat samtidigt. Maximalt
har den MAX_ALLOCATIONS allokeringar samtidigt.
Statistiskt sätt kommer efter ett tag MAX_ALLOCATIONS/2 allokeringar finnas
samtidigt, med varje allokering i median med värdet av halva "size_table".
När minnet är slut (malloc()=NULL), frågas användaren om han ska fortsätta.
Med jämna mellanrum skrivs statisktik ut skärmen. (DISPLAY_WHEN)
För att stressa systemet med fler små allokeringar, kan man öka
MAX_ALLOCATIONS. AMOUNT_OF_MEMORY bör den att slå i taket fortare om man
minskar det.
Ingen initiering görs av slumptalen, allt är upprepbart (men plocka bort
kommentaren srand() och det löser sig.
*/
#define BMALLOC /* go go go */
#ifdef BMALLOC
#include "dmalloc.h"
#include "bmalloc.h"
#endif
#define MAX_ALLOCATIONS 100000
#define AMOUNT_OF_MEMORY 100000 /* bytes */
#define MAXIMAL_MEMORY_TO_ALLOCATE 49000 /* Sätt den här högre än
AMOUNT_OF_MEMORY, och malloc() bör
returnera NULL förr eller senare */
#define DISPLAY_WHEN (10000) /* When to display statistic */
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define BOOL char
#define TRUE 1
#define FALSE 0
typedef struct {
char *memory;
long size;
char filled_with;
long table_position;
} MallocStruct;
/*
Skapar en lista med MAX_ALLOCATIONS storlek där det slumpvis allokeras
eller reallokeras i.
*/
MallocStruct my_mallocs[MAX_ALLOCATIONS];
long size_table[]={5,8,10,11,12,14,16,18,20,26,33,50,70,90,120,150,200,400,800,1000,2000,4000,8000};
#define TABLESIZE ((sizeof(size_table)-1)/sizeof(long))
long size_allocs[TABLESIZE];
int main(void)
{
long count=-1;
long count_free=0, count_malloc=0, count_realloc=0;
long total_memory=0;
long out_of_memory=FALSE;
dmalloc_initialize();
#ifdef BMALLOC
void *thisisourheap;
thisisourheap = (malloc)(AMOUNT_OF_MEMORY);
if(!thisisourheap)
return -1; /* can't get memory */
bmalloc_add_pool(thisisourheap, AMOUNT_OF_MEMORY);
#endif
srand( 0 ); /* Initialize to a fixed random */
while (!out_of_memory) {
long number=rand()%MAX_ALLOCATIONS;
long size;
long table_position=rand()%TABLESIZE;
char fill_with=rand()&255;
count++;
size=rand()%(size_table[table_position+1]-
size_table[table_position])+
size_table[table_position];
/* fprintf(stderr, "number %d size %d\n", number, size); */
if (my_mallocs[number].size) { /* Om allokering redan finns på den här
positionen, reallokerar vi eller
friar. */
long old_size=my_mallocs[number].size;
if (my_mallocs[number].size && fill_with<40) {
free(my_mallocs[number].memory);
total_memory -= my_mallocs[number].size;
count_free++;
size_allocs[my_mallocs[number].table_position]--;
size=0;
} else {
/*
* realloc() part
*
*/
char *temp;
#if 0
if(my_mallocs[number].size > size) {
printf("*** %d is realloc()ed to %d\n",
my_mallocs[number].size, size);
}
#endif
if (total_memory-old_size+size>MAXIMAL_MEMORY_TO_ALLOCATE)
goto output; /* for-loop */
temp = (char *)realloc(my_mallocs[number].memory, size);
if (!temp)
out_of_memory=size;
else {
my_mallocs[number].memory = temp;
my_mallocs[number].size=size;
size_allocs[my_mallocs[number].table_position]--;
size_allocs[table_position]++;
total_memory -= old_size;
total_memory += size;
old_size=min(old_size, size);
while (--old_size>0) {
if (my_mallocs[number].memory[old_size]!=my_mallocs[number].filled_with)
fprintf(stderr, "Wrong filling!\n");
}
count_realloc++;
}
}
} else {
if (total_memory+size>MAXIMAL_MEMORY_TO_ALLOCATE) {
goto output; /* for-loop */
}
my_mallocs[number].memory=(char *)malloc(size); /* Allokera! */
if (!my_mallocs[number].memory)
out_of_memory=size;
else {
size_allocs[table_position]++;
count_malloc++;
total_memory += size;
}
}
if(!out_of_memory) {
my_mallocs[number].table_position=table_position;
my_mallocs[number].size=size;
my_mallocs[number].filled_with=fill_with;
memset(my_mallocs[number].memory, fill_with, size);
}
output:
if (out_of_memory || !(count%DISPLAY_WHEN)) {
printf("(%ld) malloc %ld, realloc %ld, free %ld, total size %ld\n",
count, count_malloc, count_realloc, count_free, total_memory);
{
int count;
printf("[size bytes]=[number of allocations]\n");
for (count=0; count<TABLESIZE; count++) {
printf(" %ld=%ld\n", size_table[count], size_allocs[count]);
}
printf("\n\n");
}
}
if (out_of_memory) {
if(out_of_memory)
printf("Couldn't get %ld bytes\n", out_of_memory);
dmalloc_status();
bmalloc_status();
fprintf(stderr, "Memory is out! Continue (y/n)");
switch (getchar()) {
case 'y':
case 'Y':
out_of_memory=FALSE;
break;
}
fprintf(stderr, "\n");
}
}
printf("\n");
return 0;
}

View file

@ -1,173 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include "dmalloc.h"
#include "bmalloc.h"
#define MAX 500
#define MAX2 1000
#define MAXC 2
#define TESTA
#define TESTB
#define TESTC
#define TESTD
int test1(void)
{
#define MAXK 100
int i;
void *wow[MAXK];
for(i=0; i<MAXK; i++)
if(!(wow[i]=malloc(412))) {
printf("*** Couldn't allocate memory, exiting\n");
return -2;
}
for(i=MAXK-1; i>=0; i-=2)
free(wow[i]);
return 0;
}
int test2(void)
{
#define MAXS 10
#define MAXS1 0
int i;
void *ptr[MAXS];
for(i=MAXS1; i< MAXS; i++) {
printf("%d malloc(%d)\n", i, i*55);
ptr[i] = malloc (i*55);
}
for(i=MAXS1; i< MAXS; i++) {
void *tmp;
printf("%d realloc(%d)\n", i, i*155);
tmp=realloc(ptr[i], i*155);
if(tmp)
ptr[i] = tmp;
}
for(i=MAXS1; i< MAXS; i++) {
if(ptr[i]) {
printf("%d free(%d)\n", i, i*155);
free(ptr[i]);
}
}
return 0;
}
int test3(void)
{
int i;
void *ptr[MAXC];
printf("This is test C:\n");
for(i=0; i< MAXC; i++) {
printf("%d malloc(100)\n", i+1);
ptr[i] = malloc(100);
printf(" ...returned %p\n", ptr[i]);
}
for(i=0; i< MAXC; i++) {
printf("%d free()\n", i+1);
if(ptr[i])
free(ptr[i]);
}
printf("End of test C:\n");
return 0;
}
int test4(void)
{
int i;
int memory = 0;
void *pointers[MAX];
printf("This is test I:\n");
for(i=0; i<MAX; i++) {
printf("%d attempts malloc(%d)\n", i, i*6);
pointers[i]=malloc(i*6);
if(!pointers[i]) {
printf("cant get more memory!");
return(0);
}
memory += (i*6);
}
printf("\namount: %d\n", memory);
memory = 0;
for(i=0; i<MAX; i++) {
printf("%d attempts realloc(%d)\n", i, i*7);
pointers[i]=realloc(pointers[i], i*7);
memory += i*7;
}
printf("\namount: %d\n", memory);
for(i=0; i<MAX; i++) {
printf("%d attempts free(%d)\n", i, i*7);
free(pointers[i]);
}
printf("\nend of test 1\n");
return 0;
}
int test5(void)
{
int memory = 0;
int i;
void *pointers2[MAX2];
memory = 0;
printf("\nTest II\n");
for(i=0; i< MAX2; i++) {
printf("%d attempts malloc(%d)\n", i, 7);
pointers2[i] = malloc(7);
memory += 7;
}
printf("\namount: %d\n", memory);
for(i=0; i< MAX2; i++) {
if(pointers2[i])
free(pointers2[i]);
}
printf("\nend of test II\n");
return 0;
}
#define HEAPSIZE 10000
void smallblocks(void)
{
void *ptr;
int i=0;
do {
ptr = malloc(16);
i++;
} while(ptr);
printf("I: %d\n", i);
}
int main(int argc, char **argv)
{
void *heap = (malloc)(HEAPSIZE);
if(!heap)
return -1;
dmalloc_initialize();
bmalloc_add_pool(heap, HEAPSIZE);
smallblocks();
bmalloc_status();
dmalloc_status();
return 0;
test1();
test2();
test3();
test4();
test5();
return 0;
}

View file

@ -1,70 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include "bmalloc.h"
int main(int argc, char **argv)
{
void *pointers[5];
int i;
void *area;
for(i=0; i<5; i++)
pointers[i] = malloc(8000);
if(argc>1) {
switch(argv[1][0]) {
case '1':
for(i=0; i<5; i++) {
bmalloc_add_pool(pointers[i], 4000);
bmalloc_add_pool((char *)pointers[i]+4000, 4000);
}
break;
case '2':
area = malloc(20000);
bmalloc_add_pool(area, 3000);
bmalloc_add_pool((char *)area+6000, 3000);
bmalloc_add_pool((char *)area+3000, 3000);
bmalloc_add_pool((char *)area+12000, 3000);
bmalloc_add_pool((char *)area+9000, 3000);
break;
case '3':
{
void *ptr[10];
area = malloc(20000);
bmalloc_add_pool(area, 20000);
printf(" ** TEST USAGE\n");
for(i=0; i<9; i++)
ptr[i]=bmalloc(200);
bmalloc_status();
for(i=0; i<9; i++)
bfree(ptr[i]);
printf(" ** END OF TEST USAGE\n");
}
break;
case '4':
{
void *ptr[10];
area = malloc(20000);
bmalloc_add_pool(area, 20000);
ptr[0]=bmalloc(4080);
bmalloc_status();
bfree(ptr[0]);
printf(" ** END OF TEST USAGE\n");
}
break;
}
}
else
for(i=4; i>=0; i--)
bmalloc_add_pool(pointers[i], 8000-i*100);
bmalloc_status();
return 0;
}

View file

@ -1,56 +0,0 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
FIRMWARE = ../..
COMMON = $(FIRMWARE)/common
DRIVERS = $(FIRMWARE)/drivers
CC = gcc
LD = ld
AR = ar
AS = as
OC = objcopy
scramble = scramble-win32
DEFINES = -DCRT_DISPLAY -DDEBUG -DSIMULATOR
INCLUDES=-I. -I$(FIRMWARE) -I$(COMMON) -I$(DRIVERS)
TARGET_OPTIONS =
CFLAGS = -g -Wall ${TARGET_OPTIONS} -Wstrict-prototypes $(INCLUDES) $(DEFINES)
SRC := playlist.c settings.c panic.c disk.c debug.c harness.c
OBJS := $(SRC:%.c=%.o)
%.o: %.s
$(CC) -o $@ $(CFLAGS) $(INCLUDES) $(DEFS) -c $<
all : rockbox
rockbox: $(OBJS)
$(CC) -o $@ ${OBJS}
playlist.o:$(FIRMWARE)/playlist.c
$(CC) $(CFLAGS) -c $< -o $@
settings.o:$(FIRMWARE)/settings.c
$(CC) $(CFLAGS) -c $< -o $@
panic.o:$(FIRMWARE)/panic.c
$(CC) $(CFLAGS) -c $< -o $@
disk.o:$(FIRMWARE)/disk.c
$(CC) $(CFLAGS) -c $< -o $@
debug.o:$(FIRMWARE)/debug.c
$(CC) $(CFLAGS) -c $< -o $@
dist:
tar czvf dist.tar.gz Makefile main.c start.s app.lds
clean:
-rm -f *.x *.i *.o *.elf *.bin *.map *.mod *.bak *~

View file

@ -1,43 +0,0 @@
# __________ __ ___.
# Open \______ \ ____ ____ | | _\_ |__ _______ ___
# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
# \/ \/ \/ \/ \/
# $Id$
#
# Pick a target to build for
TARGET = -DARCHOS_PLAYER=1
#TARGET = -DARCHOS_PLAYER_OLD=1
#TARGET = -DARCHOS_RECORDER=1
CC = gcc
LD = ld
AR = ar
AS = as
OC = objcopy
scramble = scramble-win32
DEFINES = -DCRT_DISPLAY
INCLUDES=-I. -Icommon -Idrivers
TARGET_OPTIONS =
CFLAGS = -Os -Wall ${TARGET_OPTIONS} -nostdlib -Wstrict-prototypes -fomit-frame-pointer -fschedule-insns $(INCLUDES) $(DEFINES) $(TARGET)
AFLAGS += -small -relax
SRC := playlist.c settings.c panic.c disk.c debug.c harness.c
OBJS := $(SRC:%.c=%.o)
%.o: %.s
$(CC) -o $@ $(CFLAGS) $(INCLUDES) $(DEFS) -c $<
all : rockbox-win32.exe
rockbox-win32.exe: $(OBJS)
$(CC) -o rockbox-win32.exe ${OBJS}
dist:
tar czvf dist.tar.gz Makefile main.c start.s app.lds
clean:
-rm -f *.x *.i *.o *.elf *.bin *.map *.mod *.bak *~

View file

@ -1,84 +0,0 @@
Playlists on the Rockbox
1. Demand-loading of Playlist Filenames from Disk
A playlist is simply a list of track names. These lists can either be
created dynamically by the user, or they can be predefined and placed
into a text file with an .m3u extension.
The 2048 KB of RAM is the reason we need to get this right. If an average
track name (i.e. \music\cure\disintegration\01-pictures_of_you.mp3)
is assumed to be 50 characters long, then:
A playlist of 15 tracks is 15 * 50 ~= 750 bytes
A playlist of 100 tracks is 100 * 50 ~= 5 kilobytes
A playlist of 3500 tracks is 3500 * 50 ~= 175 kilobytes
A playlist of 10000 tracks is 10000 * 50 ~= 1/4 megabyte
From these figures, it can be seen that for large playlists, storing
the entire list of track names in memory significantly reduces the
capacity available to the audio data buffer, which in turn has a negative
impact on the performance of the system.
One method of reducing the total memory consumption of a playlist is
to delay bringing the actual filenames into memory until needed. Instead,
the playlist text file can be scanned, and an in-memory array constructed
with one element for each track present in the text file. Progressing
through the playlist entails getting the appropriate entry from the array,
and using that to perform a lookup of the corresponding filename entry
from the playlist text file.
With this method, and given that an integer on the Rockbox's CPU is 4 bytes:
A playlist of 15 tracks is 15 * 4 ~= 60 bytes
A playlist of 100 tracks is 100 * 4 ~= 400 bytes
A playlist of 3500 tracks is 3500 * 4 ~= 13 kilobytes
A playlist of 10000 tracks is 10000 * 4 ~= 39 kilobytes
It is clear that these are substantial savings, albeit at the cost of
increased complexity and disk i/o. Prefetch strategies could improve
performance compared to demand-loading a single entry.
2. Implementation Options
Keeping the track names in a file on disk is easy enough for a predefined
m3u playlist, but for dynamically created playlists, where the user
browses the filesystem and adds tracks or entire directory hierarchies
at will, we will need to store the playlist track names in a dedicated
file. This will be called the Anonymous Playlist, the location of which
can be set by the user, but will default to \anonymous.m3u or somesuch.
The current contents of the Anonymous Playlist can be named and saved at
any time.
The data structure to support playlists would therefore be:
typedef struct
{
char filename[256] ; /* path name of m3u playlist on disk */
int *indices; /* array of indices into the playlist */
int index; /* index of current track within playlist */
} playlist_info_t;
So far, so good: we read from an existing m3u file, or we create an
anonymous one. But what do we do if we start with an existing m3u file,
and then the user wants to dynamically add tracks to it? A few options
exist:
a) we disallow playlist modification of existing m3u files, offering
instead to replace the current playlist with the new one.
b) we give the user the option of appending the new tracks to the
existing m3u file.
c) we copy the contents of the existing m3u playlist to the anonymous one,
and then append the new tracks to that. If the m3u playlist is large,
this could be wasteful and potentially time-consuming. However, choosing
this option would provide the facility to insert or append entire
existing m3u playlists 'into' one another, a feature missng from the
commercial firmware.

View file

@ -1,112 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by wavey@wavey.org
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdio.h>
#include <common/track.h>
#include "settings.h"
#include "playlist.h"
#include "panic.h"
#include "disk.h"
#include "debug.h"
#include "config.h"
#include "harness.h"
/* global string for panic display */
char panic_message[128];
/*
* entrypoint
*/
int main( int argc, char **args )
{
/* allocate runtime data structures */
user_settings_t settings;
playlist_info_t playlist;
debugf( "\nrockbox test harness started.\n" );
/* populate runtime data structures */
initialise( &settings, &playlist );
/* begin tests */
start( &settings, &playlist );
return 1;
}
/*
* populate runtime data structures
*/
void initialise( user_settings_t *settings, playlist_info_t *playlist )
{
debugf( "init()\n" );
reload_all_settings( settings );
reload_playlist_info( playlist );
}
/*
* start tests
*/
void start( user_settings_t *settings, playlist_info_t *playlist )
{
track_t track;
debugf( "start()\n" );
/* show current values */
display_current_settings( settings );
display_current_playlist( playlist );
/* wipe playlist contents */
empty_playlist( playlist );
display_current_playlist( playlist );
/* user selects a new playlist */
load_playlist( playlist, "test2.m3u" );
display_current_playlist( playlist );
/* randomise playlist */
randomise_playlist( playlist, 45678 );
display_current_playlist( playlist );
/* get next track in playlist */
track = next_playlist_track( playlist );
display_playlist_track( &track );
/* get next track in playlist */
track = next_playlist_track( playlist );
display_playlist_track( &track );
}
#ifdef SIMULATOR
void app_main ()
{
main (0, NULL);
}
#endif

View file

@ -1,24 +0,0 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2002 by wavey@wavey.org
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "settings.h"
#include "playlist.h"
void initialise( user_settings_t *settings, playlist_info_t *playlist );
void start( user_settings_t *settings, playlist_info_t *playlist );

View file

@ -1,4 +0,0 @@
testing
testing ssh keys
2
3

View file

@ -1,9 +0,0 @@
#define _PAGE_ Rockbox on FM Recorder - Status
#include "head.t"
Known bugs (April 7, 2003):
<ul>
<li> No radio support at all
</ul>
#include "foot.t"