summaryrefslogtreecommitdiffstats
path: root/libbanshee/libcompat
diff options
context:
space:
mode:
authordnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>2004-05-13 06:41:07 +0000
committerdnovillo <dnovillo@138bc75d-0d04-0410-961f-82ee72b054a4>2004-05-13 06:41:07 +0000
commit4ee9c6840ad3fc92a9034343278a1e476ad6872a (patch)
treea2568888a519c077427b133de9ece5879a8484a5 /libbanshee/libcompat
parentebb338380ab170c91e64d38038e6b5ce930d69a1 (diff)
downloadppe42-gcc-4ee9c6840ad3fc92a9034343278a1e476ad6872a.tar.gz
ppe42-gcc-4ee9c6840ad3fc92a9034343278a1e476ad6872a.zip
Merge tree-ssa-20020619-branch into mainline.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@81764 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libbanshee/libcompat')
-rw-r--r--libbanshee/libcompat/Makefile.am4
-rw-r--r--libbanshee/libcompat/Makefile.in365
-rw-r--r--libbanshee/libcompat/alloc.c133
-rw-r--r--libbanshee/libcompat/pages.c459
-rw-r--r--libbanshee/libcompat/profile.c521
-rw-r--r--libbanshee/libcompat/profile.h59
-rw-r--r--libbanshee/libcompat/radix-tree.c364
-rw-r--r--libbanshee/libcompat/radix-tree.h51
-rw-r--r--libbanshee/libcompat/regions.c387
-rw-r--r--libbanshee/libcompat/regions.h86
10 files changed, 2429 insertions, 0 deletions
diff --git a/libbanshee/libcompat/Makefile.am b/libbanshee/libcompat/Makefile.am
new file mode 100644
index 00000000000..dae6ac0052f
--- /dev/null
+++ b/libbanshee/libcompat/Makefile.am
@@ -0,0 +1,4 @@
+AM_CFLAGS = -I$(srcdir)/../engine -I$(srcdir)/../include -I. -Ddeletes= -Dtraditional= -Dsameregion= -Dparentptr= @ac_libbanshee_warn_cflags@
+noinst_LIBRARIES = libbansheecompat.a
+libbansheecompat_a_SOURCES = regions.c radix-tree.c
+
diff --git a/libbanshee/libcompat/Makefile.in b/libbanshee/libcompat/Makefile.in
new file mode 100644
index 00000000000..48e4249ee3d
--- /dev/null
+++ b/libbanshee/libcompat/Makefile.in
@@ -0,0 +1,365 @@
+# Makefile.in generated by automake 1.7.6 from Makefile.am.
+# @configure_input@
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_RANLIB = @ac_ct_RANLIB@
+ac_ct_STRIP = @ac_ct_STRIP@
+ac_libbanshee_warn_cflags = @ac_libbanshee_warn_cflags@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+bindir = @bindir@
+build_alias = @build_alias@
+datadir = @datadir@
+exec_prefix = @exec_prefix@
+host_alias = @host_alias@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+oldincludedir = @oldincludedir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+AM_CFLAGS = -I$(srcdir)/../engine -I$(srcdir)/../include -I. -Ddeletes= -Dtraditional= -Dsameregion= -Dparentptr= @ac_libbanshee_warn_cflags@
+noinst_LIBRARIES = libbansheecompat.a
+libbansheecompat_a_SOURCES = regions.c radix-tree.c
+subdir = libcompat
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LIBRARIES = $(noinst_LIBRARIES)
+
+libbansheecompat_a_AR = $(AR) cru
+libbansheecompat_a_LIBADD =
+am_libbansheecompat_a_OBJECTS = regions.$(OBJEXT) radix-tree.$(OBJEXT)
+libbansheecompat_a_OBJECTS = $(am_libbansheecompat_a_OBJECTS)
+
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/../depcomp
+am__depfiles_maybe = depfiles
+@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/radix-tree.Po ./$(DEPDIR)/regions.Po
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+DIST_SOURCES = $(libbansheecompat_a_SOURCES)
+DIST_COMMON = Makefile.am Makefile.in
+SOURCES = $(libbansheecompat_a_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libcompat/Makefile
+Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
+
+AR = ar
+
+clean-noinstLIBRARIES:
+ -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
+libbansheecompat.a: $(libbansheecompat_a_OBJECTS) $(libbansheecompat_a_DEPENDENCIES)
+ -rm -f libbansheecompat.a
+ $(libbansheecompat_a_AR) libbansheecompat.a $(libbansheecompat_a_OBJECTS) $(libbansheecompat_a_LIBADD)
+ $(RANLIB) libbansheecompat.a
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/radix-tree.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regions.Po@am__quote@
+
+distclean-depend:
+ -rm -rf ./$(DEPDIR)
+
+.c.o:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@ fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
+
+.c.obj:
+@am__fastdepCC_TRUE@ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \
+@am__fastdepCC_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \
+@am__fastdepCC_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \
+@am__fastdepCC_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \
+@am__fastdepCC_TRUE@ fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`
+uninstall-info-am:
+
+ETAGS = etags
+ETAGSFLAGS =
+
+CTAGS = ctags
+CTAGSFLAGS =
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(ETAGS_ARGS)$$tags$$unique" \
+ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique
+
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkinstalldirs) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LIBRARIES)
+
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -rm -f Makefile $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+ distclean-generic distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-noinstLIBRARIES ctags distclean distclean-compile \
+ distclean-depend distclean-generic distclean-tags distdir dvi \
+ dvi-am info info-am install install-am install-data \
+ install-data-am install-exec install-exec-am install-info \
+ install-info-am install-man install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-info-am
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libbanshee/libcompat/alloc.c b/libbanshee/libcompat/alloc.c
new file mode 100644
index 00000000000..7f2cfd369b2
--- /dev/null
+++ b/libbanshee/libcompat/alloc.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1999-2001
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/* TBD: recover unusued portions of pages for use as individual pages */
+
+#include <stddef.h>
+#include "regions.h"
+
+static void alloc_block(region r, struct allocator *a, struct ablock *blk,
+ void **p1, int s1, int a1, void **p2, int s2, int a2,
+ size_t blksize, int needsclear)
+{
+ struct page *newp;
+ char *mem1, *mem2;
+
+ mem1 = PALIGN(blk->allocfrom, a1);
+ mem2 = PALIGN(mem1 + s1, a2);
+
+ /* Can't use last byte of page (pointers to the byte after an object are
+ valid) */
+ if (mem2 + s2 >= blk->base + blksize)
+ {
+ if (blksize == RPAGESIZE)
+ {
+ newp = alloc_single_page(a->pages);
+ a->pages = newp;
+ blk->allocfrom = (char *)newp + offsetof(struct page, previous);
+ set_region(newp, 1, r);
+ }
+ else
+ {
+ newp = alloc_pages(blksize >> RPAGELOG, a->bigpages);
+ a->bigpages = newp;
+ blk->allocfrom = (char *)newp + offsetof(struct page, previous);
+ set_region(newp, blksize >> RPAGELOG, r);
+ }
+ blk->base = (char *)newp;
+
+ if (needsclear)
+ preclear(blk->allocfrom, blksize - (blk->allocfrom - (char *)newp));
+ mem1 = PALIGN(blk->allocfrom, a1);
+ mem2 = PALIGN(mem1 + s1, a2);
+ }
+
+ ASSERT_INUSE(blk->base, r);
+ blk->allocfrom = mem2 + s2;
+
+ *p1 = mem1;
+ *p2 = mem2;
+}
+
+void qalloc(region r, struct allocator *a, void **p1, int s1, int a1,
+ void **p2, int s2, int a2, int needsclear)
+{
+ struct page *p;
+ char *mem;
+ int npages;
+ int n = ALIGN(s1, a2) + s2; /* Yes, this is correct (see alloc_block) */
+
+ if (n <= RPAGESIZE / K)
+ {
+ alloc_block(r, a, &a->page, p1, s1, a1, p2, s2, a2, RPAGESIZE,
+ needsclear);
+ return;
+ }
+ if (n <= RPAGESIZE)
+ {
+ alloc_block(r, a, &a->superpage, p1, s1, a1, p2, s2, a2,
+ K * RPAGESIZE, needsclear);
+ return;
+ }
+ if (n <= RPAGESIZE * K)
+ {
+ alloc_block(r, a, &a->hyperpage, p1, s1, a1, p2, s2, a2,
+ K * K * RPAGESIZE, needsclear);
+ return;
+ }
+
+ npages = (n + ALIGN(offsetof(struct page, previous), a1) + RPAGESIZE - 1)
+ >> RPAGELOG;
+ p = alloc_pages(npages, a->bigpages);
+ a->bigpages = p;
+ set_region(p, npages, r);
+
+ mem = (char *)p + offsetof(struct page, previous);
+ *p1 = PALIGN(mem, a1);
+ *p2 = PALIGN((char *) *p1 + s1, a2);
+ if (needsclear)
+ preclear(*p2, s2);
+}
+
+void free_all_pages(region r, struct allocator *a)
+/* Assumes freepages_lock held */
+{
+ struct page *p, *next;
+
+ for (p = a->pages; p; p = next)
+ {
+ next = p->next;
+ free_single_page(r, p);
+ }
+ for (p = a->bigpages; p; p = next)
+ {
+ next = p->next;
+ free_pages(r, p);
+ }
+}
diff --git a/libbanshee/libcompat/pages.c b/libbanshee/libcompat/pages.c
new file mode 100644
index 00000000000..9e85e9baef0
--- /dev/null
+++ b/libbanshee/libcompat/pages.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright (c) 1999-2001
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <limits.h>
+
+typedef __rcintptr pageid;
+
+#if 0
+#define FREEPAGE ((region)-1) /* Id of a free page */
+#else
+#define FREEPAGE (&zeroregion)
+#endif
+#ifdef NMEMDEBUG
+#define ASSERT_FREE(p)
+#define ASSERT_INUSE(p, r)
+#else
+#define ASSERT_FREE(p) assert(regionof(p) == FREEPAGE)
+#ifdef DUPLICATES
+#define ASSERT_INUSE(p, r) assert(regionof(p) == r->base)
+#else
+#define ASSERT_INUSE(p, r) assert(regionof(p) == r)
+#endif
+#endif
+
+/* Page allocator for region-based memory management */
+/* TBD: special free list for size == K ?? */
+
+#define PAGECOUNTBITS (CHAR_BIT * sizeof(pageid) - 1)
+
+struct page
+{
+ /* Next page in region or in free list */
+ struct page *next;
+
+ /* Doubly linked list of pages sorted by address */
+ struct page *next_address, *prev_address;
+
+ /* number of pages in this allocation unit. Negative for free pages. */
+ pageid pagecount : PAGECOUNTBITS;
+
+ unsigned int free : 1;
+
+ /* Only in free pages not in the single_pages list */
+ struct page *previous;
+};
+
+/* The pages are kept in a single list sorted by address via the
+ next_address and prev_address fields. The first page's prev_address and
+ the last page's next_address fields points to pages_byaddress.
+ page_byaddress.next_address is the first page
+ page_byaddress.prev_address is the last page
+
+ This list is used for coalescing operations.
+*/
+static struct page pages_byaddress;
+
+struct page *alloc_single_page(struct page *next);
+void free_single_page(region r, struct page *p);
+
+struct page *alloc_pages(int n, struct page *next);
+void free_pages(region r, struct page *p);
+
+
+/* a list of free individual pages */
+struct page *single_pages;
+
+/* free pages (not including those in single_pages) */
+struct page *unused_pages;
+
+static void init_pages(void)
+{
+ pages_byaddress.next_address = &pages_byaddress;
+ pages_byaddress.prev_address = &pages_byaddress;
+}
+
+static void insertbefore_address(struct page *p, struct page *before)
+{
+ p->prev_address = before->prev_address;
+ p->next_address = before;
+ before->prev_address = p;
+ p->prev_address->next_address = p;
+}
+
+static void unlink_address(struct page *p)
+{
+ p->prev_address->next_address = p->next_address;
+ p->next_address->prev_address = p->prev_address;
+}
+
+static void addbyaddress(struct page *p)
+{
+ struct page *address_scan;
+
+ /* Warning: this is slow. Calls to it should not be frequent (once app
+ reaches a steady state of memory usage). */
+
+ for (address_scan = pages_byaddress.next_address; ;
+ address_scan = address_scan->next_address)
+ if (p < address_scan || address_scan == &pages_byaddress)
+ {
+ insertbefore_address(p, address_scan);
+ return;
+ }
+}
+
+/* Doubly linked page list management */
+void addfront(struct page **list, struct page *p)
+/* Effects: Adds p to the front of doubly-linked list list */
+{
+ p->previous = NULL;
+ p->next = *list;
+ if (*list) (*list)->previous = p;
+ *list = p;
+}
+
+void unlink_page(struct page **list, struct page *p)
+/* Effects: Remove p from its doubly linked list */
+{
+ if (p->previous)
+ p->previous->next = p->next;
+ else
+ *list = p->next;
+ if (p->next)
+ p->next->previous = p->previous;
+}
+
+void *region_get_mem(size_t s)
+{
+ void *mem = malloc(s + RPAGESIZE - 1);
+
+ return (void *)ALIGN((__rcintptr)mem, RPAGESIZE);
+}
+
+/* Page to region map management */
+/* ----------------------------- */
+
+RADIX_TREE(__rcregionmap);
+
+static void set_page_region(pageid pagenb, region r)
+{
+ radix_tree_delete (&__rcregionmap, pagenb);
+ radix_tree_insert (&__rcregionmap, pagenb, r);
+}
+
+#define page_region(pagenb) (radix_tree_lookup (&__rcregionmap, (pagenb)))
+
+void set_region(struct page *p, int npages, region r)
+{
+ pageid pnb = PAGENB(p);
+
+ while (npages-- > 0)
+ set_page_region(pnb++, r);
+}
+
+/* Mark the memory range from 'from' (inclusive) to 'to' (exclusive)
+ as belonging to region with id 'rid' */
+void set_region_range(void *from, void *to, region r)
+{
+ pageid first = PAGENB(from), last = PAGENB((pageid)to - 1);
+
+ while (first <= last)
+ set_page_region(first++, r);
+}
+
+/* Multi-page allocation management */
+/* -------------------------------- */
+
+struct page *alloc_new(int n, struct page *next)
+/* Assumes freepages_lock held */
+{
+ struct page *newp = region_get_mem(n << RPAGELOG);
+
+ if (!newp)
+ {
+ if (nomem_h)
+ nomem_h();
+ abort();
+ }
+ assert(!((long)newp & (RPAGESIZE - 1)));
+
+ newp->next = next;
+ newp->pagecount = n;
+ newp->free = 0;
+ addbyaddress(newp);
+#ifndef NMEMDEBUG
+ {
+ pageid i, pnb = PAGENB(newp);
+
+ for (i = pnb; i < pnb + n; i++)
+ set_page_region(i, FREEPAGE);
+ }
+#endif
+
+ return newp;
+}
+
+struct page *alloc_split(struct page *split, int n, struct page *next)
+/* Assumes freepages_lock held */
+{
+#ifndef NMEMDEBUG
+ /* These pages had better be free */
+ pageid i, pnb = PAGENB(split);
+
+ assert(split->pagecount >= n);
+ for (i = pnb; i < pnb + split->pagecount; i++)
+ assert(page_region(i) == FREEPAGE);
+#endif
+ if (split->pagecount > n)
+ {
+ struct page *splitoff;
+
+ /* Keep first part of block */
+ split->pagecount -= n;
+ /* Return latter part of block */
+ splitoff = split;
+ split = (struct page *)((char *)split + (split->pagecount << RPAGELOG));
+
+ /* Update the by adress list */
+ insertbefore_address(split, splitoff->next_address);
+ }
+ else
+ {
+ /* remove split from list */
+ unlink_page(&unused_pages, split);
+ }
+ split->next = next;
+ split->pagecount = n;
+ split->free = 0;
+
+ return split;
+}
+
+struct page *alloc_pages(int n, struct page *next)
+{
+ struct page *best;
+ int bestn;
+ struct page *scan;
+
+ assert(n >= K);
+
+ scan = unused_pages;
+ /* Find first fit */
+ for (;;)
+ {
+ if (!scan)
+ return alloc_new(n, next);
+
+ if (scan->pagecount >= n) break;
+ scan = scan->next;
+ }
+
+ /* Now find best fit */
+ best = scan;
+ bestn = scan->pagecount;
+ for (;;)
+ {
+ scan = scan->next;
+ if (!scan)
+ return alloc_split(best, n, next);
+
+ if (scan->pagecount >=n && scan->pagecount < bestn)
+ {
+ best = scan;
+ bestn = scan->pagecount;
+ }
+ }
+}
+
+static void coalesce(struct page *p)
+{
+ struct page *prev = p->prev_address, *next;
+
+ p->free = 1;
+
+ /* Coalesce with predecessor ? */
+ if (prev->free && (char *)prev + (prev->pagecount << RPAGELOG) == (char *)p)
+ {
+ prev->pagecount += p->pagecount;
+ unlink_address(p);
+ p = prev;
+ }
+ else /* No, add to free pages list */
+ addfront(&unused_pages, p);
+
+ next = p->next_address;
+ /* Coalesce with successor ? */
+ if (next->free && (char *)p + (p->pagecount << RPAGELOG) == (char *)next)
+ {
+ unlink_page(&unused_pages, next);
+ p->pagecount += next->pagecount;
+ unlink_address(next);
+ }
+}
+
+void free_pages(region r, struct page *p)
+/* Assumes freepages_lock held */
+{
+#ifndef NMEMDEBUG
+ pageid i, pnb = PAGENB(p);
+
+ for (i = pnb; i < pnb + p->pagecount; i++)
+ {
+ assert(page_region(i) == r);
+ set_page_region(i, FREEPAGE);
+ }
+#endif
+
+ coalesce(p);
+}
+
+
+/* Single page management */
+/* ---------------------- */
+
+static int single_page_count;
+
+static void add_single_pages(struct page *base)
+/* Effects: Adds pages at base to the single_pages list */
+{
+ pageid n = base->pagecount;
+ struct page *prev = base->prev_address, *basenext = base->next_address,
+ *next;
+
+ single_page_count += n;
+
+ for (;;)
+ {
+ ASSERT_FREE(base);
+ base->free = 0; /* Not free so that coalesce won't steal these back */
+ base->prev_address = prev;
+ prev = base;
+ base->next = single_pages;
+ single_pages = base;
+ if (--n == 0)
+ break;
+ next = (struct page *)((char *)base + RPAGESIZE);
+ base->next_address = next;
+ base = next;
+ }
+ base->next_address = basenext;
+ basenext->prev_address = base;
+}
+
+void scavenge_single_pages(int n)
+{
+ /* Add n pages to the single_pages list */
+ struct page *scan, *best;
+ __rcintptr bestn;
+
+ /* Take any group in unused_pages that is <= n or < K.
+ Remember smallest entry > n too. This is sortof equivalent to
+ a best fit where we allow partial allocations to make up a whole */
+ best = NULL;
+ bestn = (__rcintptr)1 << (sizeof(__rcintptr) * CHAR_BIT - 2);
+ scan = unused_pages;
+ while (scan)
+ {
+ /* The pages < K can't be used for anything but single pages so we
+ might as well grab them even if they are a little too big */
+ if (scan->pagecount <= n || scan->pagecount < K)
+ {
+ struct page *adding = scan;
+
+ scan = scan->next;
+ n -= adding->pagecount;
+ unlink_page(&unused_pages, adding);
+ add_single_pages(adding);
+ if (n <= 0) return;
+ }
+ else
+ {
+ if (scan->pagecount < bestn)
+ {
+ bestn = scan->pagecount;
+ best = scan;
+ }
+ scan = scan->next;
+ }
+ }
+ /* Still not enough. Split the best block if there is one, allocate
+ new pages otherwise */
+ if (!best)
+ add_single_pages(alloc_new(n, NULL));
+ else if (best->pagecount - n < K)
+ {
+ unlink_page(&unused_pages, best);
+ add_single_pages(best);
+ }
+ else
+ add_single_pages(alloc_split(best, n, NULL));
+}
+
+struct page *alloc_single_page(struct page *next)
+{
+ struct page *p;
+
+ if (!single_pages)
+ {
+ scavenge_single_pages(PAGE_GROUP_SIZE);
+ }
+ ASSERT_FREE(single_pages);
+ p = single_pages;
+ single_pages = p->next;
+ p->next = next;
+
+ single_page_count--;
+
+ return p;
+}
+
+void free_single_page(region r, struct page *p)
+/* Assumes freepages_lock held */
+{
+#ifndef NMEMDEBUG
+ ASSERT_INUSE(p, r);
+ set_page_region(PAGENB(p), FREEPAGE);
+#endif
+
+ /* Once free list is big enough just coalesce the pages.
+ The actual threshold to use might merit further study (something
+ adaptive ? e.g., proportional to allocated single pages) */
+ if (single_page_count > PAGE_GROUP_SIZE * 2)
+ {
+ p->pagecount = 1;
+ coalesce(p);
+ }
+ else
+ {
+ p->next = single_pages;
+ single_pages = p;
+ single_page_count++;
+ }
+}
diff --git a/libbanshee/libcompat/profile.c b/libbanshee/libcompat/profile.c
new file mode 100644
index 00000000000..0a30a55e41e
--- /dev/null
+++ b/libbanshee/libcompat/profile.c
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 1999-2001
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <signal.h>
+#undef REGION_PROFILE
+#include "regions.h"
+#include "profile.h"
+
+typedef struct Alloc_info
+{
+ struct Alloc_info *next;
+ char *file;
+ int line;
+ unsigned long size;
+ unsigned long calls;
+} *ainfo;
+
+static ainfo ainfos = NULL;
+static region profile_region = NULL;
+
+/* perror(s) then exit */
+void pfail(const char *s)
+{
+ perror(s);
+ exit(EXIT_FAILURE);
+}
+
+/**************************************************************************
+ * *
+ * Log information about an allocation -- generic *
+ * *
+ **************************************************************************/
+
+static int registered_exit = 0;
+
+static ainfo find_ainfo(char *file, int line)
+{
+ ainfo ai;
+
+ for (ai = ainfos; ai; ai = ai->next)
+ if (line == ai->line && !strcmp(file, ai->file))
+ return ai;
+
+ if (!registered_exit)
+ {
+ if (atexit(profile))
+ fprintf(stderr, "Registration of profile at exit failed\n");
+ registered_exit = 1;
+ }
+
+ if (!profile_region)
+ profile_region = newregion();
+ ai = ralloc(profile_region, struct Alloc_info);
+ ai->file = file;
+ ai->line = line;
+ ai->size = 0;
+ ai->calls = 0;
+ ai->next = ainfos;
+ ainfos = ai;
+ return ai;
+}
+
+/**************************************************************************
+ * *
+ * Log information about an allocation -- GCC *
+ * *
+ * WARNING: This code uses __builtin_return_address, a non-portable *
+ * feature of gcc, to trace the call chain back. You'll also get ugly *
+ * output unless the addr2line (in GNU binutils) is installed. *
+ * *
+ * ANOTHER WARNING: The depths hard-coded in find_cinfo are only correct *
+ * if find_cinfo is inlined. Ack! *
+ * *
+ **************************************************************************/
+
+#define REGION_PROFILE_DEPTH 2
+#undef TRACE_STACK
+#if defined(__GNUC__) && defined(__OPTIMIZE__) && REGION_PROFILE_DEPTH > 1
+#define TRACE_STACK
+#endif
+
+#ifdef TRACE_STACK
+
+#if REGION_PROFILE_DEPTH > 6
+#error "REGION_PROFILE_DEPTH must be less than 6. See find_cinfo()."
+#endif
+
+typedef struct Call_info
+{
+ struct Call_info *next;
+ void **stack; /* Array holding the call chain */
+ unsigned long size;
+ unsigned long calls;
+} *cinfo;
+
+static cinfo cinfos = NULL;
+
+/* Find the current call chain and return a pointer to our status for
+ it, or allocate a new entry if there is none. */
+static cinfo find_cinfo(void)
+{
+ void *calls[REGION_PROFILE_DEPTH];
+ int i;
+ cinfo ci;
+
+ /* Compute the call chain. This is an awful hack. */
+ i = 0;
+ if (i < REGION_PROFILE_DEPTH)
+ calls[i++] = __builtin_return_address(1);
+ if (i < REGION_PROFILE_DEPTH)
+ calls[i++] = __builtin_return_address(2);
+ if (i < REGION_PROFILE_DEPTH)
+ calls[i++] = __builtin_return_address(3);
+ if (i < REGION_PROFILE_DEPTH)
+ calls[i++] = __builtin_return_address(4);
+ if (i < REGION_PROFILE_DEPTH)
+ calls[i++] = __builtin_return_address(5);
+ if (i < REGION_PROFILE_DEPTH)
+ calls[i++] = __builtin_return_address(6);
+ /* Add more if you want a higher call-depth (why would you?) */
+
+ /* Find it */
+ for (ci = cinfos; ci; ci = ci->next)
+ if (!memcmp(calls, ci->stack, REGION_PROFILE_DEPTH*sizeof(void *)))
+ return ci;
+
+ if (!profile_region)
+ profile_region = newregion();
+ ci = ralloc(profile_region, struct Call_info);
+ ci->stack = rarrayalloc(profile_region, REGION_PROFILE_DEPTH, void *);
+ memcpy(ci->stack, calls, REGION_PROFILE_DEPTH*sizeof(void *));
+ ci->size = 0;
+ ci->calls = 0;
+ ci->next = cinfos;
+ cinfos = ci;
+ return ci;
+
+}
+#endif
+
+static void add_alloc(char *file, int line, int size)
+{
+ ainfo ai = find_ainfo(file, line);
+ ai->calls++;
+ ai->size += size;
+#ifdef TRACE_STACK
+ {
+ cinfo ci;
+
+ ci = find_cinfo();
+ ci->calls++;
+ ci->size += size;
+ }
+#endif
+}
+
+/**************************************************************************
+ * *
+ * Intercept and log calls to region library *
+ * *
+ **************************************************************************/
+
+void *profile_typed_ralloc(region r, size_t size, type_t type, char *file,
+ int line)
+{
+ add_alloc(file, line, size);
+ return typed_ralloc(r, size, type);
+}
+
+void *profile_typed_rarrayalloc(region r, size_t n, size_t size, type_t type,
+ char *file, int line)
+{
+ add_alloc(file, line, n*size);
+ return typed_rarrayalloc(r, n, size, type);
+}
+
+void *profile_typed_rarrayextend(region r, void *old, size_t n, size_t size,
+ type_t type, char *file, int line)
+{
+ add_alloc(file, line, n*size); /* XXX: Fix */
+ return typed_rarrayextend(r, old, n, size, type);
+}
+
+char *profile_rstralloc(region r, size_t size, char *file, int line)
+{
+ add_alloc(file, line, size);
+ return rstralloc(r, size);
+}
+
+char *profile_rstralloc0(region r, size_t size, char *file, int line)
+{
+ add_alloc(file, line, size);
+ return rstralloc0(r, size);
+}
+
+char *profile_rstrdup(region r, const char *s, char *file, int line)
+{
+ add_alloc(file, line, strlen(s));
+ return rstrdup(r, s);
+}
+
+char *profile_rstrextend(region r, const char *old, size_t newsize,
+ char *file, int line)
+{
+ add_alloc(file, line, newsize); /* XXX: Fix */
+ return rstrextend(r, old, newsize);
+}
+
+char *profile_rstrextend0(region r, const char *old, size_t newsize,
+ char *file, int line)
+{
+ add_alloc(file, line, newsize); /* XXX: Fix */
+ return rstrextend0(r, old, newsize);
+}
+
+/**************************************************************************
+ * *
+ * Display results -- generic *
+ * *
+ **************************************************************************/
+
+static FILE *out = NULL;
+
+/* Generic list -- used for generic sorting. Note that next field is
+ at the top. */
+typedef struct List
+{
+ struct List *next;
+} *list;
+
+/* Sort a list. cmp should sort in reverse order. */
+static list sort_list(list l, int (*cmp)(const void *, const void *))
+{
+ list cur, result;
+ list *sorted;
+ int i, length;
+ region temp_region;
+
+ /* Compute length of list */
+ for (cur = l, length = 0; cur; cur = cur->next, length++);
+
+ temp_region = newregion();
+ sorted = rarrayalloc(temp_region, length, list *);
+ for (cur = l, i = 0; cur; cur = cur->next)
+ sorted[i++] = cur;
+ qsort(sorted, length, sizeof(list *), cmp);
+
+ result = NULL;
+ for (i = 0; i < length; i++)
+ {
+ cur = result;
+ result = sorted[i];
+ result->next = cur;
+ }
+ deleteregion(temp_region);
+ return result;
+}
+
+
+typedef struct File_info
+{
+ struct File_info *next;
+ char *file;
+ unsigned long size;
+ unsigned long calls;
+ unsigned long sites;
+} *finfo;
+
+static finfo finfos = NULL;
+
+static int finfo_cmp(const void *a, const void *b)
+{
+ finfo *afi = (finfo *) a;
+ finfo *bfi = (finfo *) b;
+ return (*afi)->size - (*bfi)->size; /* Reverse order */
+}
+
+static void print_finfos(void)
+{
+ finfo fi;
+ unsigned long size, sites, calls;
+
+ finfos = (finfo) sort_list((list) finfos, finfo_cmp);
+ size = sites = calls = 0;
+ fprintf(out, " Bytes | Sites | Calls | File\n");
+ fprintf(out, " ------------+-------+----------+---------------------\n");
+ for (fi = finfos; fi; fi = fi->next)
+ {
+ size += fi->size;
+ sites += fi->sites;
+ calls += fi->calls;
+ fprintf(out, " %12lu | %5lu | %8lu | %s\n",
+ fi->size, fi->sites, fi->calls, fi->file);
+ }
+ fprintf(out, " ------------+-------+----------+---------------------\n");
+ fprintf(out, " %12lu | %5lu | %8lu | Total\n",
+ size, sites, calls);
+
+}
+
+static int ainfo_cmp(const void *a, const void *b)
+{
+ ainfo *afi = (ainfo *) a;
+ ainfo *bfi = (ainfo *) b;
+ return (*afi)->size - (*bfi)->size; /* Reverse order */
+}
+
+static void print_ainfos(void)
+{
+ ainfo ai;
+
+ unsigned long size, calls;
+
+ ainfos = (ainfo) sort_list((list) ainfos, ainfo_cmp);
+ size = calls = 0;
+ fprintf(out, " Bytes | Calls | Site\n");
+ fprintf(out, " ------------+----------+---------------------\n");
+ for (ai = ainfos; ai; ai = ai->next)
+ {
+ size += ai->size;
+ calls += ai->calls;
+ fprintf(out, " %12lu | %8lu | %s:%d\n",
+ ai->size, ai->calls, ai->file, ai->line);
+ }
+ fprintf(out, " ------------+----------+---------------------\n");
+ fprintf(out, " %12lu | %8lu | Total\n",
+ size, calls);
+}
+
+static finfo find_finfo(char *file)
+{
+ finfo fi;
+
+ for (fi = finfos; fi; fi = fi->next)
+ if (!strcmp(file, fi->file))
+ return fi;
+
+ fi = ralloc(profile_region, struct File_info);
+ fi->file = file;
+ fi->size = 0;
+ fi->calls = 0;
+ fi->sites = 0;
+ fi->next = finfos;
+ finfos = fi;
+ return fi;
+}
+
+static void gather_finfo(void)
+{
+ ainfo ai;
+
+ for (ai = ainfos; ai; ai = ai->next)
+ {
+ finfo fi = find_finfo(ai->file);
+ fi->size += ai->size;
+ fi->calls += ai->calls;
+ fi->sites++;
+ }
+}
+
+/**************************************************************************
+ * *
+ * Display results -- GCC *
+ * *
+ **************************************************************************/
+
+#ifdef TRACE_STACK
+
+pid_t child_pid = 0;
+int child_in[2], child_out[2]; /* pipes to child process */
+
+static void start_prettiness(void)
+{
+ if (pipe(child_in) || pipe(child_out))
+ pfail("Unable to open pipe to child process");
+ if (!(child_pid = fork()))
+ {
+ /* Child process */
+ pid_t parent_pid;
+ char filename[64];
+
+ if (dup2(child_in[0], STDIN_FILENO) == -1)
+ pfail("Unable to open pipe from parent");
+ close(child_in[0]);
+ close(child_in[1]);
+ if (dup2(child_out[1], STDOUT_FILENO) == -1)
+ pfail("Unable to open pipe to parent");
+ close(child_out[0]);
+ close(child_out[1]);
+
+ parent_pid = getppid();
+ snprintf(filename, 64, "/proc/%d/exe", parent_pid);
+ filename[63] = '\0';
+ execlp("addr2line", "addr2line", "-s", "-e", filename, 0);
+ fprintf(stderr, "Unable to fork addr2line\n");
+ exit(EXIT_FAILURE);
+ }
+ else
+ {
+ close(child_in[0]);
+ close(child_out[1]);
+ }
+}
+
+/* Turn p into a file:line string */
+static char *prettify(void *p)
+{
+#define BUFSIZE 1024
+ static char buf[BUFSIZE];
+ int size;
+
+ /*printf("To child: %p\n", p);*/
+ size = snprintf(buf, BUFSIZE, "%p\n", p);
+ write(child_in[1], buf, size);
+ size = read(child_out[0], buf, BUFSIZE - 1);
+ if (!size)
+ pfail("Unable to read from child process");
+ buf[size-1] = '\0'; /* Kill \n */
+ /*printf("Read: [%s]\n", buf);*/
+ return buf;
+}
+
+static void end_prettiness(void)
+{
+ if (child_pid)
+ kill(child_pid, SIGHUP);
+}
+
+static int cinfo_cmp(const void *a, const void *b)
+{
+ cinfo *aci = (cinfo *) a;
+ cinfo *bci = (cinfo *) b;
+ return (*aci)->size - (*bci)->size; /* Reverse order */
+}
+
+/* Print the call chain information out to a file. */
+static void print_cinfos(void)
+{
+ cinfo ci;
+ unsigned long size, calls;
+ int i;
+
+ cinfos = (cinfo) sort_list((list) cinfos, cinfo_cmp);
+ size = calls = 0;
+ start_prettiness();
+ fprintf(out, " Bytes | Calls | Call Stack\n");
+ fprintf(out, " ------------+----------+---------------------\n");
+ for (ci = cinfos; ci; ci = ci->next)
+ {
+ size += ci->size;
+ calls += ci->calls;
+ fprintf(out, " %12lu | %8lu | ", ci->size, ci->calls);
+ for (i = 0; i < REGION_PROFILE_DEPTH; i++)
+ fprintf(out, "%s ", prettify(ci->stack[i]));
+ fprintf(out, "\n");
+ }
+ fprintf(out, " ------------+----------+---------------------\n");
+ fprintf(out, " %12lu | %8lu | Total\n",
+ size, calls);
+ end_prettiness();
+}
+#endif
+
+
+void profile(void)
+{
+ if (profile_region == NULL)
+ return;
+
+ gather_finfo();
+
+ if (!(out = fopen("profile.out", "w")))
+ pfail("Unable to open profile.out");
+
+ fprintf(out, "---------------------------\n");
+ fprintf(out, "Region Library Memory Usage\n");
+ fprintf(out, "---------------------------\n\n");
+
+ print_finfos();
+ fprintf(out, "\n");
+ print_ainfos();
+#ifdef TRACE_STACK
+ fprintf(out, "\n");
+ print_cinfos();
+#endif
+
+ fclose(out);
+}
diff --git a/libbanshee/libcompat/profile.h b/libbanshee/libcompat/profile.h
new file mode 100644
index 00000000000..b07034e2191
--- /dev/null
+++ b/libbanshee/libcompat/profile.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1999-2001
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef PROFILE_H
+#define PROFILE_H
+
+/* Should only be included in regions.h and profile.c */
+
+void *profile_typed_ralloc(region r, size_t size, type_t type, char *file, int line);
+void *profile_typed_rarrayalloc(region r, size_t n, size_t size, type_t type, char *file, int line);
+void *profile_typed_rarrayextend(region r, void *old, size_t n, size_t size, type_t type, char *file, int line);
+char *profile_rstralloc(region r, size_t size, char *file, int line);
+char *profile_rstralloc0(region r, size_t size, char *file, int line);
+char *profile_rstrdup(region r, const char *s, char *file, int line);
+char *profile_rstrextend(region r, const char *old, size_t newsize, char *file, int line);
+char *profile_rstrextend0(region r, const char *old, size_t newsize, char *file, int line);
+
+#ifdef REGION_PROFILE
+#define typed_ralloc(r, size, type) profile_typed_ralloc(r, size, type, __FILE__, __LINE__)
+#define typed_rarrayalloc(r, n, size, type) profile_typed_rarrayalloc(r, n, size, type, __FILE__, __LINE__)
+#define typed_rarrayextend(r, old, n, size, type) profile_typed_rarrayextend(r, old, n, size, type, __FILE__, __LINE__)
+
+#define rstralloc(r, size) profile_rstralloc(r, size, __FILE__, __LINE__)
+#define rstralloc0(r, size) profile_rstralloc0(r, size, __FILE__, __LINE__)
+#define rstrdup(r, s) profile_rstrdup(r, s, __FILE__, __LINE__)
+
+#define rstrextend(r, old, newsize) profile_rstrextend(r, old, newsize, __FILE__, __LINE__)
+#define rstrextend0(r, old, newsize) profile_rstrextend0(r, old, newsize, __FILE__, __LINE__)
+#endif
+
+void profile(void);
+
+#endif
diff --git a/libbanshee/libcompat/radix-tree.c b/libbanshee/libcompat/radix-tree.c
new file mode 100644
index 00000000000..18f8929ad2d
--- /dev/null
+++ b/libbanshee/libcompat/radix-tree.c
@@ -0,0 +1,364 @@
+/*
+ * Modified to work in GCC in 2003 by Daniel Berlin
+ * Copyright (C) 2001 Momchil Velikov
+ * Portions Copyright (C) 2001 Christoph Hellwig
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include "radix-tree.h"
+#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
+/*
+ * Radix tree node definition.
+ */
+#define RADIX_TREE_MAP_SHIFT 6
+#define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT)
+#define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1)
+
+struct radix_tree_node {
+ unsigned int count;
+ void *slots[RADIX_TREE_MAP_SIZE];
+};
+
+struct radix_tree_path {
+ struct radix_tree_node *node, **slot;
+};
+
+#define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long))
+#define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2)
+
+static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH];
+
+
+/*
+ * This assumes that the caller has performed appropriate preallocation, and
+ * that the caller has pinned this thread of control to the current CPU.
+ */
+static struct radix_tree_node *
+radix_tree_node_alloc(struct radix_tree_root *root)
+{
+ struct radix_tree_node *ret;
+
+ ret = (struct radix_tree_node *)
+ calloc (1, sizeof (struct radix_tree_node));
+ if (!ret)
+ abort ();
+ return ret;
+}
+
+static inline void
+radix_tree_node_free(struct radix_tree_node *node)
+{
+ free (node);
+}
+
+
+/*
+ * Return the maximum key which can be store into a
+ * radix tree with height HEIGHT.
+ */
+static inline unsigned long radix_tree_maxindex(unsigned int height)
+{
+ return height_to_maxindex[height];
+}
+
+/*
+ * Extend a radix tree so it can store key @index.
+ */
+static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
+{
+ struct radix_tree_node *node;
+ unsigned int height;
+
+ /* Figure out what the height should be. */
+ height = root->height + 1;
+ while (index > radix_tree_maxindex(height))
+ height++;
+
+ if (root->rnode) {
+ do {
+ if (!(node = radix_tree_node_alloc(root)))
+ return -ENOMEM;
+
+ /* Increase the height. */
+ node->slots[0] = root->rnode;
+ node->count = 1;
+ root->rnode = node;
+ root->height++;
+ } while (height > root->height);
+ } else
+ root->height = height;
+
+ return 0;
+}
+
+/**
+ * radix_tree_insert - insert into a radix tree
+ * @root: radix tree root
+ * @index: index key
+ * @item: item to insert
+ *
+ * Insert an item into the radix tree at position @index.
+ */
+int radix_tree_insert(struct radix_tree_root *root, unsigned long index,
+ void *item)
+{
+ struct radix_tree_node *node = NULL, *tmp, **slot;
+ unsigned int height, shift;
+ int error;
+
+ /* Make sure the tree is high enough. */
+ if (index > radix_tree_maxindex(root->height)) {
+ error = radix_tree_extend(root, index);
+ if (error)
+ return error;
+ }
+
+ slot = &root->rnode;
+ height = root->height;
+ shift = (height-1) * RADIX_TREE_MAP_SHIFT;
+
+ while (height > 0) {
+ if (*slot == NULL) {
+ /* Have to add a child node. */
+ if (!(tmp = radix_tree_node_alloc(root)))
+ return -ENOMEM;
+ *slot = tmp;
+ if (node)
+ node->count++;
+ }
+
+ /* Go a level down. */
+ node = *slot;
+ slot = (struct radix_tree_node **)
+ (node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
+ shift -= RADIX_TREE_MAP_SHIFT;
+ height--;
+ }
+
+ if (*slot != NULL)
+ return -EEXIST;
+ if (node)
+ node->count++;
+
+ *slot = item;
+ return 0;
+}
+
+/**
+ * radix_tree_lookup - perform lookup operation on a radix tree
+ * @root: radix tree root
+ * @index: index key
+ *
+ * Lookup them item at the position @index in the radix tree @root.
+ */
+void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
+{
+ unsigned int height, shift;
+ struct radix_tree_node **slot;
+
+ height = root->height;
+ if (index > radix_tree_maxindex(height))
+ return NULL;
+
+ shift = (height-1) * RADIX_TREE_MAP_SHIFT;
+ slot = &root->rnode;
+
+ while (height > 0) {
+ if (*slot == NULL)
+ return NULL;
+
+ slot = (struct radix_tree_node **)
+ ((*slot)->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
+ shift -= RADIX_TREE_MAP_SHIFT;
+ height--;
+ }
+
+ return (void *) *slot;
+}
+
+static /* inline */ unsigned int
+__lookup(struct radix_tree_root *root, void **results, unsigned long index,
+ unsigned int max_items, unsigned long *next_index)
+{
+ unsigned int nr_found = 0;
+ unsigned int shift;
+ unsigned int height = root->height;
+ struct radix_tree_node *slot;
+
+ shift = (height-1) * RADIX_TREE_MAP_SHIFT;
+ slot = root->rnode;
+
+ while (height > 0) {
+ unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
+
+ for ( ; i < RADIX_TREE_MAP_SIZE; i++) {
+ if (slot->slots[i] != NULL)
+ break;
+ index &= ~((1 << shift) - 1);
+ index += 1 << shift;
+ if (index == 0)
+ goto out; /* 32-bit wraparound */
+ }
+ if (i == RADIX_TREE_MAP_SIZE)
+ goto out;
+ height--;
+ if (height == 0) { /* Bottom level: grab some items */
+ unsigned long j = index & RADIX_TREE_MAP_MASK;
+
+ for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
+ index++;
+ if (slot->slots[j]) {
+ results[nr_found++] = slot->slots[j];
+ if (nr_found == max_items)
+ goto out;
+ }
+ }
+ }
+ shift -= RADIX_TREE_MAP_SHIFT;
+ slot = slot->slots[i];
+ }
+ out:
+ *next_index = index;
+ return nr_found;
+}
+
+/**
+ * radix_tree_gang_lookup - perform multiple lookup on a radix tree
+ * @root: radix tree root
+ * @results: where the results of the lookup are placed
+ * @first_index: start the lookup from this key
+ * @max_items: place up to this many items at *results
+ *
+ * Performs an index-ascending scan of the tree for present items. Places
+ * them at *@results and returns the number of items which were placed at
+ * *@results.
+ *
+ * The implementation is naive.
+ */
+unsigned int
+radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
+ unsigned long first_index, unsigned int max_items)
+{
+ const unsigned long max_index = radix_tree_maxindex(root->height);
+ unsigned long cur_index = first_index;
+ unsigned int ret = 0;
+
+ if (root->rnode == NULL)
+ goto out;
+ if (max_index == 0) { /* Bah. Special case */
+ if (first_index == 0) {
+ if (max_items > 0) {
+ *results = root->rnode;
+ ret = 1;
+ }
+ }
+ goto out;
+ }
+ while (ret < max_items) {
+ unsigned int nr_found;
+ unsigned long next_index; /* Index of next search */
+
+ if (cur_index > max_index)
+ break;
+ nr_found = __lookup(root, results + ret, cur_index,
+ max_items - ret, &next_index);
+ ret += nr_found;
+ if (next_index == 0)
+ break;
+ cur_index = next_index;
+ }
+ out:
+ return ret;
+}
+
+/**
+ * radix_tree_delete - delete an item from a radix tree
+ * @root: radix tree root
+ * @index: index key
+ *
+ * Remove the item at @index from the radix tree rooted at @root.
+ *
+ * Returns the address of the deleted item, or NULL if it was not present.
+ */
+void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
+{
+ struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
+ unsigned int height, shift;
+ void *ret = NULL;
+
+ height = root->height;
+ if (index > radix_tree_maxindex(height))
+ goto out;
+
+ shift = (height-1) * RADIX_TREE_MAP_SHIFT;
+ pathp->node = NULL;
+ pathp->slot = &root->rnode;
+
+ while (height > 0) {
+ if (*pathp->slot == NULL)
+ goto out;
+
+ pathp[1].node = *pathp[0].slot;
+ pathp[1].slot = (struct radix_tree_node **)
+ (pathp[1].node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
+ pathp++;
+ shift -= RADIX_TREE_MAP_SHIFT;
+ height--;
+ }
+
+ ret = *pathp[0].slot;
+ if (ret == NULL)
+ goto out;
+
+ *pathp[0].slot = NULL;
+ while (pathp[0].node && --pathp[0].node->count == 0) {
+ pathp--;
+ *pathp[0].slot = NULL;
+ radix_tree_node_free(pathp[1].node);
+ }
+
+ if (root->rnode == NULL)
+ root->height = 0; /* Empty tree, we can reset the height */
+ out:
+ return ret;
+}
+
+
+static unsigned long __maxindex(unsigned int height)
+{
+ unsigned int tmp = height * RADIX_TREE_MAP_SHIFT;
+ unsigned long index = (~0UL >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1;
+
+ if (tmp >= RADIX_TREE_INDEX_BITS)
+ index = ~0UL;
+ return index;
+}
+
+static void radix_tree_init_maxindex(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++)
+ height_to_maxindex[i] = __maxindex(i);
+}
+
+void radix_tree_init(void)
+{
+ radix_tree_init_maxindex();
+}
diff --git a/libbanshee/libcompat/radix-tree.h b/libbanshee/libcompat/radix-tree.h
new file mode 100644
index 00000000000..a6b6dc185a3
--- /dev/null
+++ b/libbanshee/libcompat/radix-tree.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2001 Momchil Velikov
+ * Portions Copyright (C) 2001 Christoph Hellwig
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef _LINUX_RADIX_TREE_H
+#define _LINUX_RADIX_TREE_H
+
+
+struct radix_tree_node;
+
+struct radix_tree_root {
+ unsigned int height;
+ struct radix_tree_node *rnode;
+};
+
+#define RADIX_TREE_INIT() {0, NULL}
+
+#define RADIX_TREE(name) \
+ struct radix_tree_root name = RADIX_TREE_INIT()
+
+#define INIT_RADIX_TREE(root) \
+do { \
+ (root)->height = 0; \
+ (root)->rnode = NULL; \
+} while (0)
+
+extern int radix_tree_insert(struct radix_tree_root *, unsigned long, void *);
+extern void *radix_tree_lookup(struct radix_tree_root *, unsigned long);
+extern void *radix_tree_delete(struct radix_tree_root *, unsigned long);
+extern unsigned int radix_tree_gang_lookup(struct radix_tree_root *root,
+ void **results,
+ unsigned long first_index,
+ unsigned int max_items);
+extern void radix_tree_init(void);
+
+
+#endif /* _LINUX_RADIX_TREE_H */
diff --git a/libbanshee/libcompat/regions.c b/libbanshee/libcompat/regions.c
new file mode 100644
index 00000000000..6426fd68d1e
--- /dev/null
+++ b/libbanshee/libcompat/regions.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 1999-2001
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+/* Idea: clear on page alloc rather than individual alloc
+ Turns out not so good (on lcc at least, seems a wash on mudlle):
+ logically should be bad for small regions (less than a few pages)
+*/
+#undef PRECLEAR
+#undef REGION_PROFILE
+#include "regions.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include "radix-tree.h"
+#define RPAGESIZE (1 << RPAGELOG)
+#define PAGE_GROUP_SIZE 32
+#define K 4
+#define MAXPAGE (1 << (32 - RPAGELOG))
+
+#define PAGENB(x) ((__rcintptr)(x) >> RPAGELOG)
+
+#define ALIGN(x, n) (((x) + ((n) - 1)) & ~((n) - 1))
+#define PALIGN(x, n) ((void *)ALIGN((__rcintptr)(x), n))
+#ifdef __GNUC__
+#define RALIGNMENT __alignof(double)
+#define PTRALIGNMENT __alignof(void *)
+#define ALIGNMENT_LONG __alignof(unsigned long)
+#else
+#define RALIGNMENT 8
+#define PTRALIGNMENT 4
+#define ALIGNMENT_LONG 4
+#endif
+
+typedef unsigned long __rcintptr;
+
+struct ablock {
+ char *base, *allocfrom;
+};
+
+struct allocator {
+ struct ablock page;
+ struct ablock superpage;
+ struct ablock hyperpage;
+ struct page *pages;
+ struct page *bigpages;
+};
+
+struct Region {
+ struct allocator normal;
+ struct Region *parent, *sibling, *children;
+};
+
+nomem_handler nomem_h;
+
+/* dummy region for NULL and malloc memory */
+struct Region zeroregion;
+
+static void clear(void *start, __rcintptr size)
+{
+ long *clear, *clearend;
+
+ clear = (long *)start;
+ clearend = (long *)((char *)start + size);
+ do *clear++ = 0;
+ while (clear < clearend) ;
+}
+
+#ifdef PRECLEAR
+#define preclear clear
+#define postclear(s, e)
+#else
+#define preclear(s, e)
+#define postclear clear
+#endif
+
+#include "pages.c"
+#include "alloc.c"
+
+static void nochildren(region r)
+{
+ if (r->children)
+ abort();
+}
+
+static void unlink_region(region r)
+{
+ region *scan;
+
+ scan = &r->parent->children;
+ while (*scan != r)
+ scan = &(*scan)->sibling;
+ *scan = (*scan)->sibling;
+}
+
+static void link_region(region r, region parent)
+{
+ r->sibling = parent->children;
+ r->parent = parent;
+ parent->children = r;
+}
+
+static int rstart;
+
+void initregion(region r)
+{
+ char *first =
+ (char *)r - rstart - offsetof(struct page, previous);
+
+ /* Start using page with region header as a pointer-containing page */
+ r->normal.page.base = first;
+ r->normal.page.allocfrom = (char *)(r + 1);
+
+ /* Guarantee failure for all other blocks */
+ r->normal.superpage.allocfrom = (char *)(K * RPAGESIZE + 1);
+ r->normal.hyperpage.allocfrom = (char *)(K * K * RPAGESIZE + 1);
+
+ /* Remember that r owns this page. */
+ r->normal.pages = (struct page *)first;
+ set_region(r->normal.pages, 1, r);
+}
+
+region newregion(void)
+{
+ return newsubregion(&zeroregion);
+}
+
+region newsubregion(region parent)
+{
+ char *first;
+ region r;
+
+ first = (char *)alloc_single_page(NULL);
+ preclear(first + offsetof(struct page, pagecount), RPAGESIZE - offsetof(struct page, pagecount));
+
+ /* stagger regions across cache lines a bit */
+ rstart += 64;
+ if (rstart > RPAGESIZE / K) rstart = 0;
+ r = (region)(first + rstart + offsetof(struct page, previous));
+ postclear(r, sizeof *r);
+ initregion(r);
+
+ link_region(r, parent);
+
+ return r;
+}
+
+void *typed_ralloc(region r, size_t size, type_t t)
+{
+ return rstralloc0(r, size);
+}
+
+void *typed_rarrayextend(region r, void *old, size_t n, size_t size, type_t t)
+{
+ return rstrextend0(r, old, n * size);
+}
+
+void *typed_rarrayalloc(region r, size_t n, size_t size, type_t t)
+{
+ return typed_ralloc(r, n * size, t);
+}
+
+char *rstralloc(region r, size_t size)
+{
+ void *mem, *dummy;
+
+ qalloc(r, &r->normal, &dummy, 0, 1, &mem, size, RALIGNMENT, 0);
+
+ return mem;
+}
+
+char *rstralloc0(region r, size_t size)
+{
+ char *mem;
+
+ mem = rstralloc(r, size);
+ clear(mem, size);
+
+ return mem;
+}
+
+char *rstrdup(region r, const char *s)
+{
+ char *news = rstralloc(r, strlen(s) + 1);
+
+ strcpy(news, s);
+
+ return news;
+}
+
+static char *internal_rstrextend(region r, const char *old, size_t newsize,
+ int needsclear)
+{
+ /* For now we don't attempt to extend the old storage area */
+ void *newmem, *hdr;
+ unsigned long *oldhdr, oldsize;
+
+ qalloc(r, &r->normal, &hdr, sizeof(unsigned long), ALIGNMENT_LONG,
+ &newmem, newsize, RALIGNMENT, 0);
+
+ /* If we don't do this we can't find the header: */
+ hdr = (char *)newmem - sizeof(unsigned long);
+
+ *(unsigned long *)hdr = newsize;
+
+ if (old)
+ {
+ oldhdr = (unsigned long *)(old - ALIGNMENT_LONG);
+ oldsize = *oldhdr;
+
+ if (oldsize > newsize)
+ oldsize = newsize;
+ else if (needsclear)
+ clear((char *) newmem + oldsize, newsize - oldsize);
+ memcpy(newmem, old, oldsize);
+ }
+ else if (needsclear)
+ clear(newmem, newsize);
+
+ return newmem;
+}
+
+char *rstrextend(region r, const char *old, size_t newsize)
+{
+ return internal_rstrextend(r, old, newsize, 0);
+}
+
+char *rstrextend0(region r, const char *old, size_t newsize)
+{
+ return internal_rstrextend(r, old, newsize, 1);
+}
+
+void typed_rarraycopy(void *to, void *from, size_t n, size_t size, type_t type)
+{
+ memcpy(to, from, n * size);
+}
+
+static void delregion(region r)
+{
+ nochildren(r);
+ free_all_pages(r, &r->normal);
+}
+
+void deleteregion(region r)
+{
+ unlink_region(r);
+ delregion(r);
+}
+
+void deleteregion_ptr(region *r)
+{
+ region tmp = *r;
+
+ *r = NULL;
+ deleteregion(tmp);
+}
+
+void deleteregion_array(int n, region *regions)
+{
+ int i;
+
+ for (i = 0; i < n; i++)
+ unlink_region(regions[i]);
+
+ for (i = 0; i < n; i++)
+ {
+ delregion(regions[i]);
+ regions[i] = NULL;
+ }
+}
+
+region regionof(void *ptr)
+{
+ return radix_tree_lookup (&__rcregionmap, (unsigned long)ptr >> RPAGELOG);
+}
+
+void region_init(void)
+{
+ static int initialized = 0;
+ radix_tree_init ();
+ if ( initialized )
+ return;
+ else
+ {
+ rstart = -64; /* Save 64 bytes of memory! (sometimes ;-)) */
+ init_pages();
+ }
+
+ initialized = 1;
+}
+
+nomem_handler set_nomem_handler(nomem_handler newhandler)
+{
+ nomem_handler oldh = nomem_h;
+
+ nomem_h = newhandler;
+
+ return oldh;
+}
+
+/*
+int region_main(int argc, char **argv, char **envp);
+
+int main(int argc, char **argv, char **envp)
+{
+ region_init();
+ return region_main(argc, argv, envp);
+}
+*/
+
+
+/* Debugging support */
+
+static FILE *out;
+
+static void printref(void *x)
+{
+/* if (x >= (void *)__rcregionmap && x < (void *)&__rcregionmap[MAXPAGE])
+ return;
+*/
+#ifdef RCPAIRS
+ if (x >= (void *)__rcregions && x < (void *)&__rcregions[MAXREGIONS])
+ return;
+
+#endif
+
+ fprintf(out, "info symbol 0x%p\n", x);
+}
+
+void findrefs(region r, void *from, void *to)
+{
+ char *f;
+
+ if (!out)
+ out = fopen("/dev/tty", "w");
+
+ for (f = PALIGN(from, PTRALIGNMENT); f < (char *)to; f += PTRALIGNMENT)
+ if (regionof(*(void **)f) == r)
+ printref(f);
+
+ fflush(out);
+}
+
+#ifdef sparc
+extern void _DYNAMIC, _end;
+
+void findgrefs(region r)
+{
+ findrefs(r, &_DYNAMIC, &_end);
+}
+#endif
+
+void findrrefs(region r, region from)
+{
+ struct page *p;
+
+ for (p = from->normal.pages; p; p = p->next)
+ findrefs(r, (char *)&p->previous, (char *)p + RPAGESIZE);
+
+ for (p = r->normal.bigpages; p; p = p->next)
+ findrefs(r, (char *)&p->previous, (char *)p + p->pagecount * RPAGESIZE);
+}
diff --git a/libbanshee/libcompat/regions.h b/libbanshee/libcompat/regions.h
new file mode 100644
index 00000000000..9f0231ddd82
--- /dev/null
+++ b/libbanshee/libcompat/regions.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1999-2001
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#ifndef REGIONS_H
+#define REGIONS_H
+
+#define RPAGELOG 13
+
+typedef struct Region *region;
+
+#include <stdlib.h>
+
+void region_init(void); /* You MUST call this function before using any
+ part of this library */
+
+region newregion(void);
+region newsubregion(region parent);
+
+typedef int type_t;
+#define rctypeof(type) 0
+
+/* Low-level alloc with dynamic type info */
+void *typed_ralloc(region r, size_t size, type_t type);
+void *typed_rarrayalloc(region r, size_t n, size_t size, type_t type);
+void *typed_rarrayextend(region r, void *old, size_t n, size_t size, type_t type);
+void typed_rarraycopy(void *to, void *from, size_t n, size_t size, type_t type);
+
+#define ralloc(r, type) typed_ralloc((r), sizeof(type), rctypeof(type))
+#define rarrayalloc(r, n, type) typed_rarrayalloc((r), (n), sizeof(type), rctypeof(type))
+#define rarrayextend(r, old, n, type) typed_rarrayextend((r), (old), (n), sizeof(type), rctypeof(type))
+#define rarraycopy(to, from, n, type) typed_rarraycopy((to), (from), (n), sizeof(type), rctypeof(type))
+
+char *rstralloc(region r, size_t size);
+char *rstralloc0(region r, size_t size);
+char *rstrdup(region r, const char *s);
+
+/* rstrextend is used to extend an old string. The string MUST have been
+ initially allocated by a call to rstrextend with old == NULL (you cannot
+ initially allocate the string with rstralloc) */
+char *rstrextend(region r, const char *old, size_t newsize);
+char *rstrextend0(region r, const char *old, size_t newsize);
+
+void deleteregion(region r);
+void deleteregion_ptr(region *r);
+void deleteregion_array(int n, region *regions);
+region regionof(void *ptr);
+
+typedef void (*nomem_handler)(void);
+nomem_handler set_nomem_handler(nomem_handler newhandler);
+
+/* Debugging support */
+void findrefs(region r, void *from, void *to);
+void findgrefs(region r);
+void findrrefs(region r, region from);
+
+#ifdef REGION_PROFILE
+#include "profile.h"
+#endif
+
+#endif
OpenPOWER on IntegriCloud