[Numpy-svn] r3692 - in branches/multicore: benchmarks numpy/core numpy/core/cprops_thread numpy/core/cprops_thread/tests numpy/core/include/numpy numpy/core/src numpy/core/tests

numpy-svn@scip... numpy-svn@scip...
Tue Apr 10 12:55:03 CDT 2007


Author: eric
Date: 2007-04-10 12:54:59 -0500 (Tue, 10 Apr 2007)
New Revision: 3692

Added:
   branches/multicore/benchmarks/time_thread.py
   branches/multicore/numpy/core/cprops_thread/
   branches/multicore/numpy/core/cprops_thread/README_ERIC.txt
   branches/multicore/numpy/core/cprops_thread/ThreadMakefile
   branches/multicore/numpy/core/cprops_thread/ThreadMakefile.unix
   branches/multicore/numpy/core/cprops_thread/ThreadMakefile.windows
   branches/multicore/numpy/core/cprops_thread/VERSION
   branches/multicore/numpy/core/cprops_thread/collection.c
   branches/multicore/numpy/core/cprops_thread/collection.h
   branches/multicore/numpy/core/cprops_thread/common.h
   branches/multicore/numpy/core/cprops_thread/configure.bat
   branches/multicore/numpy/core/cprops_thread/configure.in
   branches/multicore/numpy/core/cprops_thread/cp_config.h
   branches/multicore/numpy/core/cprops_thread/hashlist.c
   branches/multicore/numpy/core/cprops_thread/hashlist.h
   branches/multicore/numpy/core/cprops_thread/hashtable.c
   branches/multicore/numpy/core/cprops_thread/hashtable.h
   branches/multicore/numpy/core/cprops_thread/linked_list.c
   branches/multicore/numpy/core/cprops_thread/linked_list.h
   branches/multicore/numpy/core/cprops_thread/log.c
   branches/multicore/numpy/core/cprops_thread/log.h
   branches/multicore/numpy/core/cprops_thread/mempool.c
   branches/multicore/numpy/core/cprops_thread/mempool.h
   branches/multicore/numpy/core/cprops_thread/rb.c
   branches/multicore/numpy/core/cprops_thread/rb.h
   branches/multicore/numpy/core/cprops_thread/tests/
   branches/multicore/numpy/core/cprops_thread/tests/main.c
   branches/multicore/numpy/core/cprops_thread/thread.c
   branches/multicore/numpy/core/cprops_thread/thread.h
   branches/multicore/numpy/core/cprops_thread/vector.c
   branches/multicore/numpy/core/cprops_thread/vector.h
   branches/multicore/numpy/core/include/numpy/ufuncthreadapi.h
   branches/multicore/numpy/core/src/ufuncthreadapi.c
   branches/multicore/numpy/core/tests/test_threadapi.py
   branches/multicore/numpy/core/threadapi.py
Modified:
   branches/multicore/numpy/core/__init__.py
   branches/multicore/numpy/core/include/numpy/ndarrayobject.h
   branches/multicore/numpy/core/setup.py
   branches/multicore/numpy/core/src/ufuncobject.c
   branches/multicore/numpy/core/src/umathmodule.c.src
Log:
Multiple svk updates that added threading support for contiguous vector math operations in numpy
 r2039@monster:  eric | 2007-04-05 12:14:02 -0500
 made local version of numpy
 r2040@monster:  eric | 2007-04-05 12:37:10 -0500
 added first cut of vector threading api to umath module.  These methods mainly
manage the state of how vector threading is done.
 r2041@monster:  eric | 2007-04-05 13:54:47 -0500
 added cprops_thread library that is used for a pre-release version of the vecto
r thread support
 r2042@monster:  eric | 2007-04-05 14:10:41 -0500
 changed file names so tests for thread api are detected automatically.
 r2046@monster:  eric | 2007-04-05 17:39:22 -0500
 slightly better benchmarking code
 r2047@monster:  eric | 2007-04-05 17:54:11 -0500
 various threading cleanups
 r2048@monster:  eric | 2007-04-05 18:05:23 -0500
 util methods not really needed. commented out unused methods the accessed them.
 r2049@monster:  eric | 2007-04-05 18:06:01 -0500
 moved util files for the time being
 r2050@monster:  eric | 2007-04-05 18:12:39 -0500
 removing unneeded dependency on util.h in cprops_thread
 r2051@monster:  eric | 2007-04-06 12:57:26 -0500
 further removal of 'extra cruft' from cprops.  We now have a very minimal set o
f dependencies that should make it easy to build on most platforms.
 r2052@monster:  eric | 2007-04-06 12:58:12 -0500
 Added a couple of platform specific makefiles.
 r2053@monster:  eric | 2007-04-06 12:59:05 -0500
 added a tests directory
 r2054@monster:  eric | 2007-04-06 13:00:07 -0500
 moved main example to the tests directory
 r2055@monster:  eric | 2007-04-06 13:00:38 -0500
 updated main.c so that sleep (sorta) works on windows.
 r2056@monster:  eric | 2007-04-06 13:03:27 -0500
 deleted a number of files not used in minimal set of cprops.
 r2057@monster:  eric | 2007-04-06 15:04:18 -0500
 This vresion compiles on Linux, shows threading speed-up in benchmarks, and pas
ses the regression tests
 r2058@monster:  eric | 2007-04-06 18:56:29 -0500
 working with gcc on windows.
 r2072@monster:  eric | 2007-04-09 17:57:30 -0500
 update to work on linux
 r2078@monster:  eric | 2007-04-09 20:42:52 -0500
  removed _WINDOWS macro in favor of _WIN32 that is automatically defined on the
 windows platform (what about win64??? Is it defined there?)



Added: branches/multicore/benchmarks/time_thread.py
===================================================================
--- branches/multicore/benchmarks/time_thread.py	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/benchmarks/time_thread.py	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,48 @@
+import numpy
+import timeit
+
+
+def run_trial(array_sizes, code, init_template, repeats=1):
+    results = []
+    for size in array_sizes:
+        timer = timeit.Timer(code,init_template%(size,size))
+        # limit the number of iterations that are run to 10000.
+        iters = int(min(array_sizes[-1]/size,1e3))
+        results.append(min(timer.repeat(repeats,iters)))
+
+    return numpy.array(results)
+
+def compare_threads(code, init_template, thread_counts, array_sizes=None):
+
+    if array_sizes is None:
+        array_sizes = [1e3, 1e4, 1e5, 1e6, 1e7, 1e8]
+
+    use_threads = [0] + [1]*len(thread_counts)
+    thread_counts = [1] + thread_counts
+    element_threshold = [1] * len(thread_counts)
+    thread_settings = zip(use_threads, thread_counts, element_threshold)
+
+    results = []
+    numpy.set_printoptions(precision=2)
+    for i, settings in enumerate(thread_settings):
+        numpy.setthreading(*settings)
+        times = run_trial(array_sizes, code, init_template, repeats=3)
+        results.append(times)
+        speed_up = results[0]/times
+        if i == 0:
+           print 'times:', times
+        # print out the speed up along with the thread settings.
+        print code, settings[0], settings[1], speed_up 
+
+    return results
+
+init_template = "from numpy import ones, sin, cos, sqrt, arctanh;a=ones(%f);b=ones(%f)"
+mult = "a*b"
+dist = "sqrt(a*a+b*b)"
+finite_difference = "b[:1] * a[1:] - a[:-1]"
+trig = "sin(a);"
+trig_expr = "sin(a)+cos(b);"
+
+for code in [mult, dist, finite_difference, trig, trig_expr]:
+    compare_threads(code, init_template, [1,2,4,8], [1e4, 2e4, 5e4, 1e5, 2e5, 5e5, 1e6, 1e7])
+    #compare_threads([1,2,4,8], [1e7])


Property changes on: branches/multicore/benchmarks/time_thread.py
___________________________________________________________________
Name: svn:executable
   + *

Modified: branches/multicore/numpy/core/__init__.py
===================================================================
--- branches/multicore/numpy/core/__init__.py	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/__init__.py	2007-04-10 17:54:59 UTC (rev 3692)
@@ -17,6 +17,8 @@
 from memmap import *
 from defchararray import *
 import scalarmath
+import threadapi
+from threadapi import *
 del nt
 
 from fromnumeric import amax as max, amin as min, \
@@ -29,6 +31,7 @@
 __all__ += defmatrix.__all__
 __all__ += rec.__all__
 __all__ += char.__all__
+__all__ += threadapi.__all__
 
 
 

Added: branches/multicore/numpy/core/cprops_thread/README_ERIC.txt
===================================================================
--- branches/multicore/numpy/core/cprops_thread/README_ERIC.txt	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/README_ERIC.txt	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,21 @@
+This is a stripped down version of libcprops.  It only has the files in it necessary for building the thread pool library.
+
+./configure doesn't work because it is expecting some other files that aren't around.
+
+To build use:
+
+make -f ThreadMakefile
+
+I've edited the Makefile to only build the needed library files as well as a simple main file that tests it.
+
+To test, run:
+
+time ./main
+
+Todo:
+
+	* How much of the config.h file is really needed?
+	* If we can get rid of log.c, we also get rid of str.c.  These guys use a lot of the unix specific stuff.
+	  How much of log.c do we use?
+	* Is it possible to get setup.py to do all the configuration we need?
+	

Added: branches/multicore/numpy/core/cprops_thread/ThreadMakefile
===================================================================
--- branches/multicore/numpy/core/cprops_thread/ThreadMakefile	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/ThreadMakefile	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,333 @@
+# libcprops - c prototyping tools Makefile
+#
+# This is the Makefile for libcprops - c prototyping tools. If it has the name 
+# "Makefile.in" then it is a template for a Makefile;  to generate the actual 
+# Makefile, run "./configure", which is a configuration script generated by the
+# "autoconf" program (constructs like "@foo@" will get replaced in the actual 
+# Makefile.
+#
+# Copyright (c) 2005, 2006 by Ilan Aelion
+# iaelion@users.sourceforge.net
+# 
+# 2006-02-21 V 0.1.6
+#
+###############################################
+
+srcdir = .
+prefix = /usr/local
+exec_prefix = ${prefix}
+
+subdirs =  svc svc/cpsp
+
+CPROPSVERSION = 0.1.6
+CPROPSLIBVERSION = 10:0:0
+
+# top_builddir is needed for the $(LIBTOOL) definition
+
+top_builddir := /home/eric/thread_software/libcprops-0.1.6
+
+bindir = $(DESTDIR)${exec_prefix}/bin
+libdir = $(DESTDIR)${exec_prefix}/lib
+incdir = $(DESTDIR)${prefix}/include/cprops
+mandir = $(DESTDIR)${prefix}/man
+datadir = $(DESTDIR)${prefix}/share
+
+man3dir = $(mandir)/man3
+
+# OPT_OBJS = db.o
+OPT_OBJS = 
+OPT_TARGETS = 
+OPT_INSTALL= 
+
+OBJS   =  log.o collection.o mempool.o vector.o str.o \
+		  linked_list.o hashtable.o \
+		  hashlist.o rb.o  \
+		  thread.o $(OPT_OBJS)
+LOBJS  =  $(OBJS:.o=.lo)		  
+HEADER =  cp_config.h common.h collection.h mempool.h log.h \
+		  vector.h str.h linked_list.h  \
+		  hashtable.h hashlist.h rb.h  \
+	  	  thread.h $(OPT_OBJS:.o=.h)
+
+TEST_SRC = testhttpsrv.c
+TEST_OBJ = $(TEST_SRC:.c=.o)
+TEST_BIN = $(TEST_SRC:.c=)
+
+CC      =  gcc
+CFLAGS  =  -fPIC -D_REENTRANT  -D_REENTRANT -D_GNU_SOURCE -O2 
+SED     =  /bin/sed
+DEFS    =  -DHAVE_CONFIG_H
+LDFLAGS =   -L/usr/lib
+LIBS    =  -ldl  -lpthread 
+LIBTOOL =  $(SHELL) $(top_builddir)/libtool
+SHELL   =  /bin/sh
+
+MAKEDEPEND = /home/eric/thread_software/libcprops-0.1.6/makedepend.sh
+
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+
+PGSQL_SRC=
+PGSQL_OBJ=
+PGSQL_HDR=
+PGSQL_CFLAGS=
+PGSQL_LDFLAGS=
+PGSQL_LIBS=
+CP_DBMS_PGSQL_LIBVERSION=
+
+MYSQL_SRC=
+MYSQL_OBJ=
+MYSQL_HDR=
+MYSQL_CFLAGS=
+MYSQL_LDFLAGS=
+MYSQL_LIBS=
+CP_DBMS_MYSQL_LIBVERSION=
+
+DEPEND=$(MAKEDEPEND) $(CFLAGS)
+
+
+main: libcprops.a main.c
+	$(CC) $(CFLAGS) main.c $(LIBS) $(LDFLAGS) -L. -lcprops -o main
+
+all_old: libcprops.la $(OPT_TARGETS) $(subdirs)
+
+.PHONY: all $(subdirs) clean clean-recursive distclean distclean-recursive \
+        install install-libcprops install-recursive \
+		uninstall uninstall-recursive \
+		install-libcp-dbms-postgres install-libcp-dbms-mysql  
+
+libcprops.a: $(OBJS)
+	ar cru libcprops.a $(OBJS)
+
+$(subdirs):
+	(cd $@ && $(MAKE) || fail=yes; cd $(top_builddir); test -z "$$fail")
+
+
+libcprops.la: $(OBJS)
+	$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -rpath $(libdir) \
+		-version-info '$(CPROPSLIBVERSION)' -export-dynamic \
+		-o libcprops.la $(LOBJS)
+
+$(PGSQL_OBJ): $(PGSQL_SRC) $(PGSQL_HDR)
+	$(LIBTOOL) --mode=compile $(CC) $(PGSQL_CFLAGS) $(DEFS) -c $(PGSQL_SRC)
+
+libcp_dbms_postgres.la: libcprops.la $(PGSQL_OBJ)
+	$(LIBTOOL) --mode=link $(CC) $(PGSQL_CFLAGS) -rpath $(libdir) \
+		-version-info '$(CP_DBMS_PGSQL_LIBVERSION)' -export-dynamic \
+		$(PGSQL_LDFLAGS) -o libcp_dbms_postgres.la $(PGSQL_OBJ:.o=.lo) \
+		$(PGSQL_LIBS)
+
+db_mysql.o: db_mysql.c db_mysql.h
+	$(LIBTOOL) --mode=compile $(CC) $(MYSQL_CFLAGS) $(DEFS) -c $<
+
+libcp_dbms_mysql.la: libcprops.la db_mysql.o
+	$(LIBTOOL) --mode=link $(CC) $(MYSQL_CFLAGS) -rpath $(libdir) \
+		-version-info '$(CP_DBMS_MYSQL_LIBVERSION)' -export-dynamic \
+		$(MYSQL_LDFLAGS) -o libcp_dbms_mysql.la $(MYSQL_OBJ:.o=.lo) \
+		$(MYSQL_LIBS)
+
+test: $(TEST_BIN)
+
+$(TEST_BIN): $(TEST_OBJ) all
+	$(CC) $(CFLAGS) -L .libs $(LDFLAGS) -o $@ $(@:=).o -lcprops $(LIBS)
+
+$(TEST_OBJ): $(TEST_SRC)
+	$(CC) $(CFLAGS) -c $(LDFLAGS) -o $@ $(@:.o=.c)
+
+.c.o:
+	#$(LIBTOOL) --mode compile $(CC) $(CFLAGS) $(DEFS) -c $<
+	$(CC) $(CFLAGS) $(DEFS) -c $<
+
+install: install-libcprops $(OPT_INSTALL) install-recursive
+
+install-libcp-dbms-postgres: all installdirs
+	@echo "installing postgres dbms driver libcp_dbms_postgres.so"
+	$(LIBTOOL) --mode=install $(INSTALL) libcp_dbms_postgres.la \
+	           $(libdir)/libcp_dbms_postgres.la
+	@$(INSTALL_DATA) $(PGSQL_HDR) $(incdir)
+	$(LIBTOOL) --finish $(libdir)
+
+install-libcp-dbms-mysql: all installdirs
+	@echo "installing mysql dbms driver libcp_dbms_mysql.so"
+	$(LIBTOOL) --mode=install $(INSTALL) libcp_dbms_mysql.la \
+	           $(libdir)/libcp_dbms_mysql.la
+	@$(INSTALL_DATA) $(MYSQL_HDR) $(incdir)
+	$(LIBTOOL) --finish $(libdir)
+
+install-libcprops: all installdirs
+	@echo "Installing libcprops"
+	$(LIBTOOL) --mode=install $(INSTALL) libcprops.la $(libdir)/libcprops.la
+	@$(INSTALL_DATA) $(HEADER) $(incdir)
+	@ls man3/ | grep -v CVS | sed 's/^/man3\//' > .manpages
+	@$(INSTALL_DATA) `cat .manpages` $(man3dir)
+	rm -f .manpages
+	$(LIBTOOL) --finish $(libdir)
+
+installdirs:
+	$(SHELL) ${srcdir}/mkinstalldirs $(libdir) $(man3dir) $(incdir)
+
+install-recursive:
+	@list='$(subdirs)'; \
+	for subdir in $$list; do \
+	  (cd $$subdir && $(MAKE) install) || fail=yes; \
+	done; \
+	test -z "$$fail"
+
+uninstall: uninstall-recursive
+	@echo "Uninstalling libcprops"
+	$(LIBTOOL) --mode=uninstall $(libdir)
+	@echo removing header files
+	if [ -d $(incdir) ]; then \
+		pushd $(incdir) ; \
+		rm -f $(HEADER) ; \
+		popd; \
+	fi
+	@echo removing man pages
+	ls man3/ | grep -v CVS | sed "s|^|$(man3dir)/|" > .manpages
+	rm -f `cat .manpages`
+	rm -f .manpages
+
+uninstall-recursive: 
+	@list='$(subdirs)'; \
+	for subdir in $$list; do \
+	  (cd $$subdir && $(MAKE) uninstall) || fail=yes; \
+	done; \
+	test -z "$$fail"
+
+clean: clean-recursive
+	rm -rf core* *.o *.lo *.loT *.la *.so *.a .libs/* $(TEST_BIN) test*.log
+
+clean-recursive:
+	@list='$(subdirs)'; \
+	for subdir in $$list; do \
+	  (cd $$subdir && $(MAKE) clean) || fail=yes; \
+	done; \
+	test -z "$$fail"
+
+distclean: clean
+	rm -rf Makefile config.cache cp_config.h config.log config.status autom4te.cache aclocal.m4 libtool
+
+$(OBJS): Makefile
+
+depend: $(OBJS:.o=.c)
+	@$(DEPEND) $(OBJS:.o=.c) > /dev/null 2>&1
+# DO NOT DELETE
+
+util.o: cp_config.h
+util.o: common.h
+util.o: log.h
+util.o: str.h
+log.o: log.h
+log.o: common.h
+log.o: str.h
+log.o: cp_config.h
+log.o: hashtable.h
+log.o: collection.h
+collection.o: collection.h
+collection.o: common.h
+collection.o: log.h
+collection.o: str.h
+collection.o: cp_config.h
+mempool.o: mempool.h
+mempool.o: common.h
+mempool.o: collection.h
+mempool.o: log.h
+mempool.o: str.h
+mempool.o: cp_config.h
+mempool.o: rb.h
+mempool.o: vector.h
+mempool.o: hashtable.h
+vector.o: log.h
+vector.o: common.h
+vector.o: str.h
+vector.o: cp_config.h
+str.o: str.h
+str.o: common.h
+str.o: cp_config.h
+str.o: log.h
+linked_list.o: linked_list.h
+linked_list.o: common.h
+linked_list.o: cp_config.h
+linked_list.o: collection.h
+linked_list.o: log.h
+linked_list.o: str.h
+linked_list.o: mempool.h
+linked_list.o: rb.h
+linked_list.o: vector.h
+linked_list.o: hashtable.h
+heap.o: heap.h
+heap.o: cp_config.h
+heap.o: common.h
+heap.o: collection.h
+heap.o: log.h
+heap.o: str.h
+priority_list.o: collection.h
+priority_list.o: common.h
+priority_list.o: log.h
+priority_list.o: str.h
+priority_list.o: cp_config.h
+priority_list.o: priority_list.h
+priority_list.o: linked_list.h
+priority_list.o: mempool.h
+priority_list.o: rb.h
+priority_list.o: vector.h
+priority_list.o: hashtable.h
+hashtable.o: hashtable.h
+hashtable.o: common.h
+hashtable.o: collection.h
+hashtable.o: log.h
+hashtable.o: str.h
+hashtable.o: cp_config.h
+hashtable.o: linked_list.h
+hashtable.o: mempool.h
+hashtable.o: rb.h
+hashtable.o: vector.h
+hashtable.o: thread.h
+hashtable.o: hashlist.h
+hashlist.o: collection.h
+hashlist.o: common.h
+hashlist.o: log.h
+hashlist.o: str.h
+hashlist.o: cp_config.h
+hashlist.o: hashlist.h
+hashlist.o: hashtable.h
+hashlist.o: linked_list.h
+hashlist.o: mempool.h
+hashlist.o: rb.h
+hashlist.o: vector.h
+mtab.o: mtab.h
+mtab.o: common.h
+mtab.o: cp_config.h
+rb.o: collection.h
+rb.o: common.h
+rb.o: log.h
+rb.o: str.h
+rb.o: cp_config.h
+rb.o: vector.h
+rb.o: rb.h
+rb.o: mempool.h
+rb.o: hashtable.h
+sorted_hash.o: collection.h
+sorted_hash.o: common.h
+sorted_hash.o: log.h
+sorted_hash.o: str.h
+sorted_hash.o: cp_config.h
+sorted_hash.o: vector.h
+sorted_hash.o: sorted_hash.h
+sorted_hash.o: mempool.h
+sorted_hash.o: rb.h
+sorted_hash.o: hashtable.h
+nary.o: vector.h
+thread.o: thread.h
+thread.o: common.h
+thread.o: cp_config.h
+thread.o: collection.h
+thread.o: log.h
+thread.o: str.h
+thread.o: linked_list.h
+thread.o: mempool.h
+thread.o: rb.h
+thread.o: vector.h
+thread.o: hashtable.h
+thread.o: hashlist.h


Property changes on: branches/multicore/numpy/core/cprops_thread/ThreadMakefile
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/multicore/numpy/core/cprops_thread/ThreadMakefile.unix
===================================================================
--- branches/multicore/numpy/core/cprops_thread/ThreadMakefile.unix	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/ThreadMakefile.unix	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,203 @@
+# libcprops - c prototyping tools Makefile
+#
+# This is the Makefile for libcprops - c prototyping tools. If it has the name 
+# "Makefile.in" then it is a template for a Makefile;  to generate the actual 
+# Makefile, run "./configure", which is a configuration script generated by the
+# "autoconf" program (constructs like "@foo@" will get replaced in the actual 
+# Makefile.
+#
+# Copyright (c) 2005, 2006 by Ilan Aelion
+# iaelion@users.sourceforge.net
+# 
+# 2006-02-21 V 0.1.6
+#
+###############################################
+
+srcdir = .
+prefix = /usr/local
+exec_prefix = ${prefix}
+
+subdirs =  
+
+CPROPSVERSION = 0.1.6
+CPROPSLIBVERSION = 10:0:0
+
+# top_builddir is needed for the $(LIBTOOL) definition
+
+top_builddir := /home/eric/thread_software/libcprops-0.1.6
+
+bindir = $(DESTDIR)${exec_prefix}/bin
+libdir = $(DESTDIR)${exec_prefix}/lib
+incdir = $(DESTDIR)${prefix}/include/cprops
+mandir = $(DESTDIR)${prefix}/man
+datadir = $(DESTDIR)${prefix}/share
+
+man3dir = $(mandir)/man3
+
+# OPT_OBJS = db.o
+OPT_OBJS = 
+OPT_TARGETS = 
+OPT_INSTALL= 
+
+OBJS   =  log.o collection.o mempool.o vector.o linked_list.o hashtable.o \
+		  hashlist.o rb.o  thread.o $(OPT_OBJS)
+LOBJS  =  $(OBJS:.o=.lo)		  
+HEADER =  cp_config.h common.h collection.h mempool.h log.h \
+		  vector.h linked_list.h hashtable.h hashlist.h rb.h  \
+	  	  thread.h $(OPT_OBJS:.o=.h)
+
+TEST_SRC = testhttpsrv.c
+TEST_OBJ = $(TEST_SRC:.c=.o)
+TEST_BIN = $(TEST_SRC:.c=)
+
+CC      =  gcc
+CFLAGS  =  -fPIC -D_REENTRANT -D_GNU_SOURCE -O2 
+SED     =  /bin/sed
+DEFS    =  -DHAVE_CONFIG_H
+LDFLAGS =  
+LIBS    =  -lpthread 
+SHELL   =  /bin/sh
+
+MAKEDEPEND = /home/eric/thread_software/libcprops-0.1.6/makedepend.sh
+
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+
+PGSQL_SRC=
+PGSQL_OBJ=
+PGSQL_HDR=
+PGSQL_CFLAGS=
+PGSQL_LDFLAGS=
+PGSQL_LIBS=
+CP_DBMS_PGSQL_LIBVERSION=
+
+MYSQL_SRC=
+MYSQL_OBJ=
+MYSQL_HDR=
+MYSQL_CFLAGS=
+MYSQL_LDFLAGS=
+MYSQL_LIBS=
+CP_DBMS_MYSQL_LIBVERSION=
+
+DEPEND=$(MAKEDEPEND) $(CFLAGS)
+
+
+main: libcprops.a main.c
+	$(CC) $(CFLAGS) $(DEFS) main.c -lcprops $(LIBS) $(LDFLAGS) -L. -o main
+
+all_old: libcprops.la $(OPT_TARGETS) $(subdirs)
+
+.PHONY: all $(subdirs) clean clean-recursive distclean distclean-recursive \
+        install install-libcprops install-recursive \
+		uninstall uninstall-recursive \
+		install-libcp-dbms-postgres install-libcp-dbms-mysql  
+
+libcprops.a: $(OBJS)
+	ar cru libcprops.a $(OBJS)
+
+$(subdirs):
+	(cd $@ && $(MAKE) || fail=yes; cd $(top_builddir); test -z "$$fail")
+
+
+
+test: $(TEST_BIN)
+
+$(TEST_BIN): $(TEST_OBJ) all
+	$(CC) $(CFLAGS) -L .libs $(LDFLAGS) -o $@ $(@:=).o -lcprops $(LIBS)
+
+$(TEST_OBJ): $(TEST_SRC)
+	$(CC) $(CFLAGS) -c $(LDFLAGS) -o $@ $(@:.o=.c)
+
+.c.o:
+	$(CC) $(CFLAGS) $(DEFS) -c $<
+
+
+clean: clean-recursive
+	rm -rf core* *.o *.lo *.loT *.la *.so *.a .libs/* $(TEST_BIN) test*.log
+
+clean-recursive:
+	@list='$(subdirs)'; \
+	for subdir in $$list; do \
+	  (cd $$subdir && $(MAKE) clean) || fail=yes; \
+	done; \
+	test -z "$$fail"
+
+distclean: clean
+	rm -rf Makefile config.cache cp_config.h config.log config.status autom4te.cache aclocal.m4 libtool
+
+#$(OBJS): Makefile
+
+depend: $(OBJS:.o=.c)
+	@$(DEPEND) $(OBJS:.o=.c) > /dev/null 2>&1
+# DO NOT DELETE
+
+log.o: log.h
+log.o: common.h
+log.o: cp_config.h
+log.o: hashtable.h
+log.o: collection.h
+collection.o: collection.h
+collection.o: common.h
+collection.o: log.h
+collection.o: cp_config.h
+mempool.o: mempool.h
+mempool.o: common.h
+mempool.o: collection.h
+mempool.o: log.h
+mempool.o: cp_config.h
+mempool.o: rb.h
+mempool.o: vector.h
+mempool.o: hashtable.h
+vector.o: log.h
+vector.o: common.h
+vector.o: cp_config.h
+linked_list.o: linked_list.h
+linked_list.o: common.h
+linked_list.o: cp_config.h
+linked_list.o: collection.h
+linked_list.o: log.h
+linked_list.o: mempool.h
+linked_list.o: rb.h
+linked_list.o: vector.h
+linked_list.o: hashtable.h
+hashtable.o: hashtable.h
+hashtable.o: common.h
+hashtable.o: collection.h
+hashtable.o: log.h
+hashtable.o: cp_config.h
+hashtable.o: linked_list.h
+hashtable.o: mempool.h
+hashtable.o: rb.h
+hashtable.o: vector.h
+hashtable.o: thread.h
+hashtable.o: hashlist.h
+hashlist.o: collection.h
+hashlist.o: common.h
+hashlist.o: log.h
+hashlist.o: cp_config.h
+hashlist.o: hashlist.h
+hashlist.o: hashtable.h
+hashlist.o: linked_list.h
+hashlist.o: mempool.h
+hashlist.o: rb.h
+hashlist.o: vector.h
+rb.o: collection.h
+rb.o: common.h
+rb.o: log.h
+rb.o: cp_config.h
+rb.o: vector.h
+rb.o: rb.h
+rb.o: mempool.h
+rb.o: hashtable.h
+thread.o: thread.h
+thread.o: common.h
+thread.o: cp_config.h
+thread.o: collection.h
+thread.o: log.h
+thread.o: linked_list.h
+thread.o: mempool.h
+thread.o: rb.h
+thread.o: vector.h
+thread.o: hashtable.h
+thread.o: hashlist.h

Added: branches/multicore/numpy/core/cprops_thread/ThreadMakefile.windows
===================================================================
--- branches/multicore/numpy/core/cprops_thread/ThreadMakefile.windows	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/ThreadMakefile.windows	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,208 @@
+# libcprops - c prototyping tools Makefile
+#
+# This is the Makefile for libcprops - c prototyping tools. If it has the name 
+# "Makefile.in" then it is a template for a Makefile;  to generate the actual 
+# Makefile, run "./configure", which is a configuration script generated by the
+# "autoconf" program (constructs like "@foo@" will get replaced in the actual 
+# Makefile.
+#
+# Copyright (c) 2005, 2006 by Ilan Aelion
+# iaelion@users.sourceforge.net
+# 
+# 2006-02-21 V 0.1.6
+#
+###############################################
+
+srcdir = .
+prefix = /usr/local
+exec_prefix = ${prefix}
+
+subdirs =  
+
+CPROPSVERSION = 0.1.6
+CPROPSLIBVERSION = 10:0:0
+
+# top_builddir is needed for the $(LIBTOOL) definition
+
+top_builddir := /home/eric/thread_software/libcprops-0.1.6
+
+bindir = $(DESTDIR)${exec_prefix}/bin
+libdir = $(DESTDIR)${exec_prefix}/lib
+incdir = $(DESTDIR)${prefix}/include/cprops
+mandir = $(DESTDIR)${prefix}/man
+datadir = $(DESTDIR)${prefix}/share
+
+man3dir = $(mandir)/man3
+
+# OPT_OBJS = db.o
+OPT_OBJS = 
+OPT_TARGETS = 
+OPT_INSTALL= 
+
+OBJS   =  log.o collection.o mempool.o vector.o linked_list.o hashtable.o \
+		  hashlist.o rb.o  thread.o $(OPT_OBJS)
+LOBJS  =  $(OBJS:.o=.lo)		  
+HEADER =  cp_config.h common.h collection.h mempool.h log.h \
+		  vector.h linked_list.h hashtable.h hashlist.h rb.h  \
+	  	  thread.h $(OPT_OBJS:.o=.h)
+
+TEST_SRC = testhttpsrv.c
+TEST_OBJ = $(TEST_SRC:.c=.o)
+TEST_BIN = $(TEST_SRC:.c=)
+
+CC      =  gcc
+#CFLAGS  =  -D_REENTRANT -D_GNU_SOURCE -O2 
+CFLAGS  =  -O2 
+DEFS    =  -D_WINDOWS
+
+# msvcr71 -- provides sleep, but it is only used in main, not the library.
+# wsock32 -- provides select
+# iberty  -- provides random, srandom, and a few others...
+LDFLAGS =  -lwsock32 -liberty -lmsvcr71
+LIBS    =   
+LIBTOOL =  $(SHELL) $(top_builddir)/libtool
+SHELL   =  /bin/sh
+
+MAKEDEPEND = /home/eric/thread_software/libcprops-0.1.6/makedepend.sh
+
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+
+PGSQL_SRC=
+PGSQL_OBJ=
+PGSQL_HDR=
+PGSQL_CFLAGS=
+PGSQL_LDFLAGS=
+PGSQL_LIBS=
+CP_DBMS_PGSQL_LIBVERSION=
+
+MYSQL_SRC=
+MYSQL_OBJ=
+MYSQL_HDR=
+MYSQL_CFLAGS=
+MYSQL_LDFLAGS=
+MYSQL_LIBS=
+CP_DBMS_MYSQL_LIBVERSION=
+
+DEPEND=$(MAKEDEPEND) $(CFLAGS)
+
+
+main: libcprops.a main.c
+	$(CC) $(CFLAGS) $(DEFS) main.c -lcprops $(LIBS) $(LDFLAGS) -L. -o main
+
+all_old: libcprops.la $(OPT_TARGETS) $(subdirs)
+
+.PHONY: all $(subdirs) clean clean-recursive distclean distclean-recursive \
+        install install-libcprops install-recursive \
+		uninstall uninstall-recursive \
+		install-libcp-dbms-postgres install-libcp-dbms-mysql  
+
+libcprops.a: $(OBJS)
+	ar cru libcprops.a $(OBJS)
+
+$(subdirs):
+	(cd $@ && $(MAKE) || fail=yes; cd $(top_builddir); test -z "$$fail")
+
+
+
+test: $(TEST_BIN)
+
+$(TEST_BIN): $(TEST_OBJ) all
+	$(CC) $(CFLAGS) -L .libs $(LDFLAGS) -o $@ $(@:=).o -lcprops $(LIBS)
+
+$(TEST_OBJ): $(TEST_SRC)
+	$(CC) $(CFLAGS) -c $(LDFLAGS) -o $@ $(@:.o=.c)
+
+.c.o:
+	$(CC) $(CFLAGS) $(DEFS) -c $<
+
+
+clean: clean-recursive
+	rm -rf core* *.o *.lo *.loT *.la *.so *.a .libs/* $(TEST_BIN) test*.log
+
+clean-recursive:
+	@list='$(subdirs)'; \
+	for subdir in $$list; do \
+	  (cd $$subdir && $(MAKE) clean) || fail=yes; \
+	done; \
+	test -z "$$fail"
+
+distclean: clean
+	rm -rf Makefile config.cache cp_config.h config.log config.status autom4te.cache aclocal.m4 libtool
+
+#$(OBJS): Makefile
+
+depend: $(OBJS:.o=.c)
+	@$(DEPEND) $(OBJS:.o=.c) > /dev/null 2>&1
+# DO NOT DELETE
+
+log.o: log.h
+log.o: common.h
+log.o: cp_config.h
+log.o: hashtable.h
+log.o: collection.h
+collection.o: collection.h
+collection.o: common.h
+collection.o: log.h
+collection.o: cp_config.h
+mempool.o: mempool.h
+mempool.o: common.h
+mempool.o: collection.h
+mempool.o: log.h
+mempool.o: cp_config.h
+mempool.o: rb.h
+mempool.o: vector.h
+mempool.o: hashtable.h
+vector.o: log.h
+vector.o: common.h
+vector.o: cp_config.h
+linked_list.o: linked_list.h
+linked_list.o: common.h
+linked_list.o: cp_config.h
+linked_list.o: collection.h
+linked_list.o: log.h
+linked_list.o: mempool.h
+linked_list.o: rb.h
+linked_list.o: vector.h
+linked_list.o: hashtable.h
+hashtable.o: hashtable.h
+hashtable.o: common.h
+hashtable.o: collection.h
+hashtable.o: log.h
+hashtable.o: cp_config.h
+hashtable.o: linked_list.h
+hashtable.o: mempool.h
+hashtable.o: rb.h
+hashtable.o: vector.h
+hashtable.o: thread.h
+hashtable.o: hashlist.h
+hashlist.o: collection.h
+hashlist.o: common.h
+hashlist.o: log.h
+hashlist.o: cp_config.h
+hashlist.o: hashlist.h
+hashlist.o: hashtable.h
+hashlist.o: linked_list.h
+hashlist.o: mempool.h
+hashlist.o: rb.h
+hashlist.o: vector.h
+rb.o: collection.h
+rb.o: common.h
+rb.o: log.h
+rb.o: cp_config.h
+rb.o: vector.h
+rb.o: rb.h
+rb.o: mempool.h
+rb.o: hashtable.h
+thread.o: thread.h
+thread.o: common.h
+thread.o: cp_config.h
+thread.o: collection.h
+thread.o: log.h
+thread.o: linked_list.h
+thread.o: mempool.h
+thread.o: rb.h
+thread.o: vector.h
+thread.o: hashtable.h
+thread.o: hashlist.h

Added: branches/multicore/numpy/core/cprops_thread/VERSION
===================================================================
--- branches/multicore/numpy/core/cprops_thread/VERSION	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/VERSION	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,2 @@
+0.1.6
+10:0:0

Added: branches/multicore/numpy/core/cprops_thread/collection.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/collection.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/collection.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,282 @@
+#include <stdlib.h>
+#include "collection.h"
+
+cp_wrap *cp_wrap_new(void *item, cp_destructor_fn dtr)
+{
+/*
+	cp_wrap *wrap = calloc(1, sizeof(cp_wrap));
+	if (wrap)
+	{
+		wrap->item = item;
+		wrap->dtr = dtr;
+	}
+
+	return wrap;
+*/
+}
+
+void cp_wrap_delete(cp_wrap *wrap)
+{
+	if (wrap)
+	{
+		if (wrap->dtr)
+			(*wrap->dtr)(wrap->item);
+
+		free(wrap);
+	}
+}
+
+#ifdef _WINDOWS
+BOOL APIENTRY DllMain( HANDLE hModule, 
+                       DWORD  ul_reason_for_call, 
+                       LPVOID lpReserved
+					 )
+{
+    switch (ul_reason_for_call)
+	{
+		case DLL_PROCESS_ATTACH:
+		case DLL_THREAD_ATTACH:
+		case DLL_THREAD_DETACH:
+		case DLL_PROCESS_DETACH:
+			break;
+    }
+    return TRUE;
+}
+
+/* WIN32 implementation of cp_mutex_init */
+int cp_mutex_init(cp_mutex *mutex, void *attr)
+{ 
+	*mutex = CreateMutex((attr), FALSE, NULL);
+	return *mutex == NULL;
+}
+
+/* WIN32 implementation of read-write locks. cp_lock is not upgradeable. */
+
+int cp_lock_init(cp_lock *lock, void *attr)
+{
+	SECURITY_ATTRIBUTES sec_attr;
+	sec_attr.nLength = sizeof(SECURITY_ATTRIBUTES);
+	sec_attr.lpSecurityDescriptor = NULL;
+	sec_attr.bInheritHandle = FALSE;
+
+	lock->access_mutex = CreateMutex(&sec_attr, FALSE, NULL);
+//	lock->write_mutex = CreateMutex(&sec_attr, FALSE, NULL);
+	lock->readers = 0;
+	lock->writer = 0;
+	lock->writer_waiting = 0;
+
+	return 0;
+}
+
+int cp_lock_rdlock(cp_lock *lock)
+{
+	while (1)
+	{
+		WaitForSingleObject(lock->access_mutex, INFINITE);
+		if (lock->writer_waiting)
+			ReleaseMutex(lock->access_mutex);
+		else
+			break;
+	}
+	lock->readers++;
+	ReleaseMutex(lock->access_mutex);
+
+	return 0;
+}
+
+int cp_lock_wrlock(cp_lock *lock)
+{
+	if (lock->writer == GetCurrentThreadId()) return 0;
+
+	while (1)
+	{
+		WaitForSingleObject(lock->access_mutex, INFINITE);
+		lock->writer_waiting = 1;
+		if (lock->readers)
+			ReleaseMutex(lock->access_mutex);
+		else
+			break;
+	}
+
+	lock->writer = GetCurrentThreadId();
+	lock->writer_waiting = 0;
+
+	return 0;
+}
+
+int cp_lock_unlock(cp_lock *lock)
+{
+	if (lock->writer == GetCurrentThreadId())
+		lock->writer = 0;
+	else
+	{
+		WaitForSingleObject(lock->access_mutex, INFINITE);
+		lock->readers--;
+	}
+
+	ReleaseMutex(lock->access_mutex);
+	return 0;
+}
+
+int cp_lock_destroy(cp_lock *lock)
+{
+	CloseHandle(lock->access_mutex);
+	return 0;
+}
+
+/* WIN32 implementation of a basic POSIX-condition-variable-like API
+ * 
+ * based on "Strategies for Implementing POSIX Condition Variables on WIN32"
+ * by Douglas C. Schmidt and Irfan Pyarali - 
+ * see http://www.cs.wustl.edu/~schmidt/WIN32-cv-1.html
+ */
+int cp_cond_init(cp_cond *cv, const void *attr) // pthread_condattr_t *)
+{
+  cv->waiters_count_ = 0;
+  cv->was_broadcast_ = 0;
+  cv->sema_ = CreateSemaphore (NULL,       // no security
+                               0,          // initially 0
+                               0x7fffffff, // max count
+                               NULL);      // unnamed 
+  if (cv->sema_ == NULL) return -1;
+  InitializeCriticalSection (&cv->waiters_count_lock_);
+  cv->waiters_done_ = CreateEvent (NULL,  // no security
+                                   FALSE, // auto-reset
+                                   FALSE, // non-signaled initially
+                                   NULL); // unnamed
+  if (cv->waiters_done_ == NULL) return -1;
+
+  return 0;
+}
+
+int cp_cond_destroy(cp_cond *cv)
+{
+	if (cv)
+	{
+		CloseHandle(cv->sema_);
+		DeleteCriticalSection(&cv->waiters_count_lock_);
+		CloseHandle(cv->waiters_done_);
+		return 0;
+	}
+
+	return -1;
+}
+
+int cp_cond_wait(cp_cond *cv, cp_mutex *external_mutex)
+{
+	int last_waiter;
+//printf(" <<< cond_wait: starting\n");
+	// Avoid race conditions.
+	EnterCriticalSection (&cv->waiters_count_lock_);
+	cv->waiters_count_++;
+	LeaveCriticalSection (&cv->waiters_count_lock_);
+
+//printf("cond: calling SignalObjectAndWait\n");
+	// This call atomically releases the mutex and waits on the
+	// semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
+	// are called by another thread.
+	SignalObjectAndWait (*external_mutex, cv->sema_, INFINITE, FALSE);
+//printf("cond: popped wait\n");
+
+	// Reacquire lock to avoid race conditions.
+	EnterCriticalSection (&cv->waiters_count_lock_);
+
+	// We're no longer waiting...
+	cv->waiters_count_--;
+
+	// Check to see if we're the last waiter after <pthread_cond_broadcast>.
+	last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0;
+
+	LeaveCriticalSection (&cv->waiters_count_lock_);
+
+	// If we're the last waiter thread during this particular broadcast
+	// then let all the other threads proceed.
+	if (last_waiter)
+	{
+//		printf("cond_wait: signaling waiters_done_\n");
+		// This call atomically signals the <waiters_done_> event and waits until
+		// it can acquire the <external_mutex>.  This is required to ensure fairness. 
+		SignalObjectAndWait (cv->waiters_done_, *external_mutex, INFINITE, FALSE);
+	}
+	else
+	{
+//		printf("cond_wait: grab external_mutex\n");
+		// Always regain the external mutex since that's the guarantee we
+		// give to our callers. 
+		WaitForSingleObject(*external_mutex, INFINITE);
+	}
+//printf(" >>> cond_wait: done\n");
+	return 0;
+}
+
+int cp_cond_signal(cp_cond *cv)
+{
+	int have_waiters;
+
+	EnterCriticalSection (&cv->waiters_count_lock_);
+//printf("cp_cond_signal: %d waiters\n", cv->waiters_count_);
+	have_waiters = cv->waiters_count_ > 0;
+	LeaveCriticalSection (&cv->waiters_count_lock_);
+
+	// If there aren't any waiters, then this is a no-op.  
+	if (have_waiters)
+		ReleaseSemaphore (cv->sema_, 1, 0);
+
+	return 0;
+}
+
+int cp_cond_broadcast(cp_cond *cv)
+{
+	int have_waiters;
+	// This is needed to ensure that <waiters_count_> and <was_broadcast_> are
+	// consistent relative to each other.
+	EnterCriticalSection (&cv->waiters_count_lock_);
+	have_waiters = 0;
+//printf("cp_cond_broadcast: %d waiters\n", cv->waiters_count_);
+	if (cv->waiters_count_ > 0) {
+		// We are broadcasting, even if there is just one waiter...
+		// Record that we are broadcasting, which helps optimize
+		// <pthread_cond_wait> for the non-broadcast case.
+		cv->was_broadcast_ = 1;
+		have_waiters = 1;
+	}
+
+	if (have_waiters) {
+		// Wake up all the waiters atomically.
+		ReleaseSemaphore (cv->sema_, cv->waiters_count_, 0);
+
+		LeaveCriticalSection (&cv->waiters_count_lock_);
+
+		// Wait for all the awakened threads to acquire the counting
+		// semaphore. 
+		WaitForSingleObject (cv->waiters_done_, INFINITE);
+		// This assignment is okay, even without the <waiters_count_lock_> held 
+		// because no other waiter threads can wake up to access it.
+		cv->was_broadcast_ = 0;
+	}
+	else
+		LeaveCriticalSection (&cv->waiters_count_lock_);
+
+	return 0;
+}
+
+void *cp_calloc(size_t count, size_t size)
+{
+	return calloc(count, size);
+}
+
+void *cp_realloc(void *p, size_t size)
+{
+	return realloc(p, size);
+}
+
+void *cp_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+void cp_free(void *p)
+{
+	free(p);
+}
+#endif /* _WINDOWS */

Added: branches/multicore/numpy/core/cprops_thread/collection.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/collection.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/collection.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,262 @@
+#ifndef _CP_COLLECTION_H
+#define _CP_COLLECTION_H
+
+#include "cp_config.h"
+#include "common.h"
+
+__BEGIN_DECLS
+
+#ifdef CP_HAS_PTHREAD_H
+#include <pthread.h>
+#endif
+
+#ifdef _WINDOWS
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0400 /* for SignalObjectAndWait */
+#include <Windows.h>
+#endif
+
+/** @{ */
+/**
+ * @file
+ *
+ * The c collection classes provide plain c implementations of famous data
+ * structures and algorithms such as linked lists, hash tables, hash lists and
+ * an extensible tree implementation (see graph.h). Behavior in terms of
+ * synchronization and member uniqueness may be set on initialization using the
+ * appropriate constructor function with the required flags. The default 
+ * implementations are synchronized, and mostly allow mutliple values with the
+ * notable exception of the cp_hashtable and cp_hashlist collections which do 
+ * not by default. Other subtle differences deriving from data structure 
+ * characteristics or implentation inconsistencies would suggest reading the 
+ * inline documentation in the header files for the specific collection you 
+ * intend to use. 
+ *
+ * This header file defines macros and function types used commonly throughout 
+ * the package.
+ */
+
+/** use collection defaults */
+#define COLLECTION_MODE_PLAIN             0
+/** collection copies and deletes elements (keys, values) */
+#define COLLECTION_MODE_DEEP              1
+/** collection allows non-unique keys */
+#define COLLECTION_MODE_MULTIPLE_VALUES   2
+/** collection stores copies of elements (keys, values) */
+#define COLLECTION_MODE_COPY              4
+/** no synchronization - suitable for the single threaded situation or if you 
+  * want to do the synchronization yourself. */
+#define COLLECTION_MODE_NOSYNC            8
+/** 
+ * The collection does not resize underlying hashtables. It might make sense 
+ * to set this temporarily in code sections that shouldn't be unexpectedly 
+ * slowed down by a resize operation, but resize should be allowed if the 
+ * table fill factor is expected to go over ~70%, which is the point at which
+ * hashtable performace is rumored to start degrading. 
+ */
+#define COLLECTION_MODE_NORESIZE         16
+/**
+ * hashlist multiple values are returned in list order (O(N)) rather than 
+ * insertion order (O(1))
+ */
+#define COLLECTION_MODE_LIST_ORDER		 32
+/**
+ * indicates a transaction is in progress
+ */
+#define COLLECTION_MODE_IN_TRANSACTION   64
+
+/** no lock */
+#define COLLECTION_LOCK_NONE   0
+/** lock for reading */
+#define COLLECTION_LOCK_READ   1
+/** lock for writing */
+#define COLLECTION_LOCK_WRITE  2
+
+/**
+ * copy function.
+ *
+ * In cases where the collection holds copies rather than references to the
+ * original objects. To do this you need to provide a copy function for
+ * the items.
+ */
+typedef void *(*cp_copy_fn)(void *);
+
+/**
+ * destructor function.
+ */
+typedef void (*cp_destructor_fn)(void *);
+
+/**
+ * comparator functions implement strcmp semantics - 0 for identical keys, 
+ * non-zero otherwise.
+ */
+typedef int (*cp_compare_fn)(void *, void *);
+
+/**
+ * callback function for iterator callback etc
+ */
+typedef int (*cp_callback_fn)(void *entry, void *client_prm);
+
+/**
+ * lock for collection types - current implementation uses pthread_rwlock_t
+ *
+ * _WINDOWS implementation for cp_cond is based on "Strategies for Implementing 
+ * POSIX Condition Variables on _WINDOWS" by Douglas C. Schmidt and Irfan Pyarali
+ * see http://www.cs.wustl.edu/~schmidt/_WINDOWS-cv-1.html
+ */
+#ifdef CP_HAS_PTHREAD_H
+typedef pthread_t cp_thread;
+typedef pthread_rwlock_t cp_lock;
+typedef pthread_mutex_t cp_mutex;
+typedef pthread_cond_t cp_cond;
+#define cp_thread_create(thread, attr, fn, prm) pthread_create(&(thread), attr, fn, prm)
+#define cp_thread_join pthread_join
+#define cp_thread_detach pthread_detach
+#define cp_thread_self pthread_self
+#define cp_mutex_init pthread_mutex_init
+#define cp_mutex_lock pthread_mutex_lock
+#define cp_mutex_unlock pthread_mutex_unlock
+#define cp_mutex_destroy pthread_mutex_destroy
+#define cp_cond_init pthread_cond_init
+#define cp_cond_wait pthread_cond_wait
+#define cp_cond_signal pthread_cond_signal
+#define cp_cond_broadcast pthread_cond_broadcast
+#define cp_cond_destroy pthread_cond_destroy
+#define cp_lock_init pthread_rwlock_init
+#define cp_lock_rdlock pthread_rwlock_rdlock
+#define cp_lock_wrlock pthread_rwlock_wrlock
+#define cp_lock_unlock pthread_rwlock_unlock
+#define cp_lock_destroy pthread_rwlock_destroy
+#define cp_thread_equal pthread_equal
+#ifndef CP_HAS_PTHREAD_MUTEX_RECURSIVE
+#ifdef CP_HAS_PTHREAD_MUTEX_RECURSIVE_NP
+#define CP_HAS_PTHREAD_MUTEX_RECURSIVE CP_HAS_PTHREAD_MUTEX_RECURSIVE_NP
+#endif /* CP_HAS_PTHREAD_MUTEX_RECURSIVE_NP */
+#endif /* CP_HAS_PTHREAD_MUTEX_RECURSIVE */
+#else 
+#ifdef _WINDOWS
+typedef HANDLE cp_thread;
+typedef HANDLE *cp_mutex;
+#define cp_thread_create(thread, attr, fn, prm) \
+	(((thread) = CreateThread(attr, 0, (LPTHREAD_START_ROUTINE) fn, prm, 0, NULL)) == NULL)
+#define cp_thread_join(thread, exp) \
+	{ \
+		cp_thread p = thread; \
+		WaitForSingleObject(p, INFINITE); \
+	}
+#define cp_thread_detach 
+#define cp_thread_self GetCurrentThread
+CPROPS_DLL
+int cp_mutex_init(cp_mutex *mutex, void *attr);
+#define cp_mutex_lock(mutex) (WaitForSingleObject((*(mutex)), INFINITE))
+#define cp_mutex_unlock(mutex) (ReleaseMutex(*(mutex)))
+#define cp_mutex_destroy(mutex) (CloseHandle(*(mutex)))
+
+/* WIN32 implementation of a basic POSIX-condition-variable-like API
+ * 
+ * based on "Strategies for Implementing POSIX Condition Variables on WIN32"
+ * by Douglas C. Schmidt and Irfan Pyarali - 
+ * see http://www.cs.wustl.edu/~schmidt/WIN32-cv-1.html
+ */
+typedef CPROPS_DLL struct
+{
+  int waiters_count_;
+  // Number of waiting threads.
+
+  CRITICAL_SECTION waiters_count_lock_;
+  // Serialize access to <waiters_count_>.
+
+  HANDLE sema_;
+  // Semaphore used to queue up threads waiting for the condition to
+  // become signaled. 
+
+  HANDLE waiters_done_;
+  // An auto-reset event used by the broadcast/signal thread to wait
+  // for all the waiting thread(s) to wake up and be released from the
+  // semaphore. 
+
+  size_t was_broadcast_;
+  // Keeps track of whether we were broadcasting or signaling.  This
+  // allows us to optimize the code if we're just signaling.
+} cp_cond;
+
+CPROPS_DLL int cp_cond_init(cp_cond *cv, const void *attr); // pthread_condattr_t *)
+CPROPS_DLL int cp_cond_wait(cp_cond *cv, cp_mutex *mutex);
+CPROPS_DLL int cp_cond_signal(cp_cond *cv);
+CPROPS_DLL int cp_cond_broadcast(cp_cond *cv);
+CPROPS_DLL int cp_cond_destroy(cp_cond *cv);
+
+/* WIN32 implementation of a basic POSIX-read-write-lock-like API. cp_lock
+ * is not upgradeable, ie attempting to obtain the lock if the current
+ * thread already owns it causes deadlock.
+ */
+typedef CPROPS_DLL struct _cp_lock
+{
+	HANDLE access_mutex;
+//	HANDLE write_mutex;
+
+	DWORD writer;
+
+	int readers;
+	int writer_waiting;
+
+} cp_lock;
+
+CPROPS_DLL int cp_lock_init(cp_lock *lock, void *attr);
+CPROPS_DLL int cp_lock_rdlock(cp_lock *lock);
+CPROPS_DLL int cp_lock_wrlock(cp_lock *lock);
+CPROPS_DLL int cp_lock_unlock(cp_lock *lock);
+CPROPS_DLL int cp_lock_destroy(cp_lock *lock);
+
+#define cp_thread_equal(p, q) ((p) == (q))
+#endif
+#endif
+
+typedef CPROPS_DLL struct _cp_wrap
+{
+	void *item;
+	cp_destructor_fn dtr;
+} cp_wrap;
+
+CPROPS_DLL cp_wrap *cp_wrap_new(void *item, cp_destructor_fn dtr);
+CPROPS_DLL void cp_wrap_delete(cp_wrap *wrap);
+	
+typedef CPROPS_DLL struct _cp_mapping
+{
+	void *key;
+	void *value;
+} cp_mapping;
+
+#define cp_mapping_key(m) 	((m)->key)
+#define cp_mapping_value(m)	((m)->value)
+
+typedef int (*cp_mapping_cmp_fn)(cp_mapping *a, cp_mapping *b);
+
+/* free an allocation made by a cprops api function. On Windows you can't just
+ * call free on memory allocated in a call to a DLL function.
+ */
+#ifdef _WINDOWS
+CPROPS_DLL
+void *cp_malloc(size_t size);
+CPROPS_DLL
+void *cp_calloc(size_t count, size_t size);
+CPROPS_DLL 
+void *cp_realloc(void *p, size_t size);
+CPROPS_DLL
+void cp_free(void *p);
+#else
+#define cp_malloc malloc
+#define cp_calloc calloc
+#define cp_realloc realloc
+#define cp_free free
+#endif /* _WINDOWS */
+
+struct _cp_mempool;
+struct _cp_shared_mempool;
+
+__END_DECLS
+
+/** @} */
+
+#endif
+

Added: branches/multicore/numpy/core/cprops_thread/common.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/common.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/common.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,134 @@
+#ifndef _CP_COMMON_H
+#define _CP_COMMON_H
+
+/** @{ */
+/**
+ * @file
+ * common symbols for cprops library -- mostly error codes
+ */
+
+#ifdef	__cplusplus
+#ifndef __BEGIN_DECLS
+#define __BEGIN_DECLS	extern "C" {
+#endif
+#ifndef __END_DECLS
+#define __END_DECLS	}
+#endif
+#else
+#ifndef __BEGIN_DECLS
+#define __BEGIN_DECLS
+#endif
+#ifndef __END_DECLS
+#define __END_DECLS
+#endif
+#endif
+
+#if defined(linux) || defined(__linux__) || defined (__linux) || defined(__gnu_linux__)
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif /* _GNU_SOURCE */
+#endif /* linux */
+
+#ifdef __NetBSD__
+#ifndef __unix__
+#define __unix__ 1
+#endif /* __unix__ */
+#endif /* __NetBSD__ */
+
+#ifdef _WINDOWS
+
+/* compatibility definitions */
+typedef int pid_t;
+
+#define SHUT_RD 	SD_RECEIVE
+#define SHUT_WR 	SD_SEND
+#define SHUT_RDWR 	SD_BOTH
+
+#define close closesocket
+
+// eric: done so that we aren't a dll.
+#define CPROPS_DLL
+//#ifdef CPROPS_EXPORTS
+//#define CPROPS_DLL __declspec(dllexport)
+//#else
+//#define CPROPS_DLL __declspec(dllimport)
+//#endif
+#else /* _WINDOWS */
+#define CPROPS_DLL
+#endif /* _WINDOWS */
+
+#if (defined linux || defined __linux || defined __gnu_linux__)
+
+#ifndef _REENTRANT
+#define _REENTRANT
+#endif
+
+/* for pthread_rwlock_t et al. */
+#ifndef _XOPEN_SOURCE 
+#define _XOPEN_SOURCE 600
+#endif
+#ifndef __USE_UNIX98
+#define __USE_UNIX98
+#endif
+
+#include <features.h>
+
+#endif
+
+#define DEFAULT_LOGFILE                                    "cp.log"
+#if defined(unix) || defined(__unix__) || defined(__MACH__)
+#define DEFAULT_TIME_FORMAT                                "%Y-%m-%d %T"
+#else
+#define DEFAULT_TIME_FORMAT                                "%Y-%m-%d %H:%M:%S"
+#endif /* unix */
+        /* error codes */
+
+#define CP_MEMORY_ALLOCATION_FAILURE                       10000
+#define CP_INVALID_FUNCTION_POINTER                        10010
+#define CP_THREAD_CREATION_FAILURE                         10020
+
+#define CP_LOADLIB_FAILED                                  11010
+#define CP_LOADFN_FAILED                                   11020
+#define CP_MODULE_NOT_LOADED                               11030
+
+#define CP_IO_ERROR                                        12000
+#define CP_OPEN_PORT_FAILED                                12010
+#define CP_HTTP_FETCH_FAILED                               12020
+#define CP_INVALID_RESPONSE                                12030
+#define CP_HTTP_EMPTY_REQUEST                              12100
+#define CP_HTTP_INVALID_REQUEST_LINE                       12110
+#define CP_HTTP_INVALID_STATUS_LINE                        12111
+#define CP_HTTP_UNKNOWN_REQUEST_TYPE                       12120
+#define CP_HTTP_INVALID_URI                                12130
+#define CP_HTTP_INVALID_URL                                12131
+#define CP_HTTP_VERSION_NOT_SPECIFIED                      12140
+#define CP_HTTP_1_1_HOST_NOT_SPECIFIED                     12150
+#define CP_HTTP_INCORRECT_REQUEST_BODY_LENGTH              12160
+#define CP_SSL_CTX_INITIALIZATION_ERROR                    12200
+#define CP_SSL_HANDSHAKE_FAILED                            12210
+#define CP_SSL_VERIFICATION_ERROR                          12220
+
+#define CP_LOG_FILE_OPEN_FAILURE                           13000
+#define CP_LOG_NOT_OPEN                                    13010
+
+#define CP_INVALID_VALUE                                   14000
+#define CP_MISSING_PARAMETER                               14010
+#define CP_BAD_PARAMETER_SET                               14020
+#define CP_ITEM_EXISTS                                     14030
+#define CP_UNHANDLED_SIGNAL                                14040
+#define CP_FILE_NOT_FOUND                                  14050
+#define CP_METHOD_NOT_IMPLEMENTED                          14060
+
+#define CP_REGEX_COMPILATION_FAILURE                       15000
+#define CP_COMPILATION_FAILURE                             15010
+
+#define CP_DBMS_NO_DRIVER                                  16000
+#define CP_DBMS_CONNECTION_FAILURE                         16010
+#define CP_DBMS_QUERY_FAILED                               16020
+#define CP_DBMS_CLIENT_ERROR                               16030
+#define CP_DBMS_STATEMENT_ERROR                            16040
+
+/** @} */
+
+#endif
+

Added: branches/multicore/numpy/core/cprops_thread/configure.bat
===================================================================
--- branches/multicore/numpy/core/cprops_thread/configure.bat	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/configure.bat	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,1143 @@
+@echo off
+echo +--------------------------------------------------------------------------+
+echo ^|                                                                          ^|
+echo ^|                  cprops configuration script for windows                 ^|
+echo ^|                                                                          ^|
+echo +--------------------------------------------------------------------------+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                              set up utilities                             *
+rem *                                                                           *
+rem *****************************************************************************
+
+echo Checking for C compiler CL
+cl > nul: 2>&1
+if errorlevel 1 (
+	@echo can^'t find CL on the path
+	goto :EOF
+)
+echo found.
+if defined LDFLAGS set LINKFLAGS=/link %LDFLAGS%
+set CFG_CFLAGS=%CFLAGS%
+set CFG_LDFLAGS=%LDFLAGS%
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                  newline                                  *
+rem *                                                                           *
+rem *****************************************************************************
+
+if exist newline.c del /q newline.c
+echo #include ^<stdio.h^> > newline.c
+echo int main() >> newline.c
+echo { >> newline.c
+echo     printf("\n"); >> newline.c
+echo     return 0; >> newline.c
+echo } >> newline.c
+
+cl %CFLAGS% newline.c %LINKFLAGS% > nul: 2>&1
+if errorlevel 1 (
+	@echo can^'t compile newline utility
+	goto :END
+)
+
+if exist newline.c del /q newline.c
+if exist newline.obj del /q newline.obj
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                 readline                                  *
+rem *                                                                           *
+rem *****************************************************************************
+
+if exist readline.c del /q readline.c
+echo #include ^<stdio.h^> > readline.c
+echo #include ^<stdlib.h^> >> readline.c
+echo #include ^<string.h^> >> readline.c
+newline >> readline.c
+echo #define MAXLEN 0x400 >> readline.c
+newline >> readline.c
+echo int main(int argc, char *argv[]) >> readline.c
+echo { >> readline.c
+echo     char *question; >> readline.c
+echo     char answer[MAXLEN]; >> readline.c
+echo     FILE *out; >> readline.c
+newline >> readline.c
+echo     if (argc ^> 1) printf("%%s ", argv[1]); >> readline.c
+echo     if (argc ^> 2) printf("[%%s] ", argv[2]); >> readline.c
+echo     printf(": "); >> readline.c
+echo     fgets(answer, MAXLEN - 1, stdin); >> readline.c
+echo     if ((answer == NULL ^|^| *answer == '\0' ^|^| *answer == '\n') ^&^& argc ^> 2) >> readline.c
+echo         strcpy(answer, argv[2]); >> readline.c
+echo     else /* chop newline */ >> readline.c
+echo         answer[strlen(answer) - 1] = '\0'; >> readline.c
+echo     if ((out = fopen("__answer", "w")) == NULL) >> readline.c
+echo         return -1; >> readline.c
+echo     fputs(answer, out); >> readline.c
+echo     fclose(out); >> readline.c
+newline >> readline.c
+echo     return 0; >> readline.c
+echo } >> readline.c
+
+cl %CFLAGS% readline.c %LINKFLAGS% > nul: 2>&1
+if errorlevel 1 (
+	@echo can^'t compile readline utility
+	goto :END
+)
+
+if exist readline.c del /q readline.c
+if exist readline.obj del /q readline.obj
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                   match                                   *
+rem *                                                                           *
+rem *****************************************************************************
+
+if exist match.c del /q match.c
+echo #include ^<stdio.h^> > match.c
+newline >> match.c
+echo #define UC(c) ((c) ^>= 'a' ^&^& (c) ^<= 'z' ? (c) - 'a' + 'A' : (c)) >> match.c
+newline >> match.c
+echo char *stristr(char *buffer, char *key) >> match.c
+echo { >> match.c
+echo     char *p, *q, *r; >> match.c
+newline >> match.c
+echo     p = buffer; >> match.c
+echo     while (*p != '\0') >> match.c
+echo     { >> match.c
+echo         q = p; >> match.c
+echo         r = key; >> match.c
+echo         while (*q != '\0' ^&^& *r != '\0' ^&^& UC(*q) == UC(*r)) >> match.c
+echo         { >> match.c
+echo             q++; >> match.c
+echo             r++; >> match.c
+echo         } >> match.c
+echo         if (*r == '\0') return p; >> match.c
+echo         p++; >> match.c
+echo      } >> match.c
+newline >> match.c
+echo      return NULL; >> match.c
+echo } >> match.c
+newline >> match.c
+echo char *strirstr(char *buffer, char *key) >> match.c
+echo { >> match.c
+echo     char *p, *q, *r; >> match.c
+newline >> match.c
+echo     p = ^&buffer[strlen(buffer) - 1]; >> match.c
+echo     while (p ^>= buffer) >> match.c
+echo     { >> match.c
+echo         q = p; >> match.c
+echo         r = key; >> match.c
+echo         while (*q != '\0' ^&^& *r != '\0' ^&^& UC(*q) == UC(*r)) >> match.c
+echo         { >> match.c
+echo             q++; >> match.c
+echo             r++; >> match.c
+echo         } >> match.c
+echo         if (*r == '\0') return p; >> match.c
+echo         p--; >> match.c
+echo      } >> match.c
+newline >> match.c
+echo      return NULL; >> match.c
+echo } >> match.c
+newline >> match.c
+echo int main(int argc, char *argv[]) >> match.c
+echo { >> match.c
+echo     char *src; >> match.c
+echo     char *key; >> match.c
+echo     int len; >> match.c
+echo     int reverse; >> match.c
+echo     char *p, ch; >> match.c
+echo     FILE *out; >> match.c
+newline >> match.c
+echo     if (argc ^< 3) return 1; >> match.c
+echo     src = argv[1]; >> match.c
+echo     key = argv[2]; >> match.c
+echo     reverse = argc ^> 3 ^&^& strcmp(argv[3], "-r") == 0; >> match.c
+echo     p = reverse ? strirstr(src, key) : stristr(src, key); >> match.c
+echo     if (p == NULL) return 2; >> match.c  
+newline >> match.c
+echo     ch = *p; >> match.c
+echo     *p = '\0'; >> match.c
+echo     out = fopen("__prefix", "w"); >> match.c
+echo     fputs(src, out); >> match.c
+echo     fclose(out); >> match.c
+echo     *p = ch; >> match.c
+newline >> match.c
+echo     src = p; >> match.c
+echo     p += strlen(key); >> match.c
+echo     ch = *p; >> match.c
+echo     *p = '\0'; >> match.c
+echo     out = fopen("__match", "w"); >> match.c
+echo     fputs(src, out); >> match.c
+echo     fclose(out); >> match.c
+echo     *p = ch; >> match.c
+newline >> match.c
+echo     out = fopen("__suffix", "w"); >> match.c
+echo     fputs(p, out); >> match.c
+echo     fclose(out); >> match.c
+newline >> match.c
+echo     return 0; >> match.c
+echo } >> match.c
+
+cl %CFLAGS% match.c %LINKFLAGS% > nul: 2>&1
+if errorlevel 1 (
+	@echo can^'t compile match utility
+	goto :END
+)
+if exist match.c del /q match.c
+if exist match.obj del /q match.obj
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                 strsubst                                  *
+rem *                                                                           *
+rem *****************************************************************************
+
+if exist strsubst.c del /q strsubst.c
+echo #include ^<stdio.h^> > strsubst.c
+echo #include ^<stdlib.h^> >> strsubst.c
+echo #include ^<string.h^> >> strsubst.c
+newline >> strsubst.c
+echo int main(int argc, char *argv[]) >> strsubst.c
+echo { >> strsubst.c
+echo     char buf[0x400]; >> strsubst.c
+echo     char *p, *q; >> strsubst.c
+echo     int rc; >> strsubst.c
+echo     FILE *in, *out; >> strsubst.c
+echo     char *fname_in, *fname_out, *token, *subst; >> strsubst.c
+newline >> strsubst.c
+echo     if (argc ^< 4) >> strsubst.c
+echo     { >> strsubst.c
+echo         fprintf(stderr, "usage: %%s <filename> <src string> <dest string>\n", >> strsubst.c
+echo                 argv[0]); >> strsubst.c
+echo         return 1; >> strsubst.c
+echo     } >> strsubst.c
+newline >> strsubst.c
+echo     fname_in = argv[1]; >> strsubst.c
+echo     token = argv[2]; >> strsubst.c
+echo     subst = argv[3]; >> strsubst.c
+newline >> strsubst.c
+echo     if (strcmp(fname_in, "-") == 0) >> strsubst.c
+echo     { >> strsubst.c
+echo         in = stdin; >> strsubst.c
+echo         out = stdout; >> strsubst.c
+echo     } >> strsubst.c
+echo     else >> strsubst.c
+echo     { >> strsubst.c
+echo         fname_out = malloc(strlen(fname_in) + strlen(".strsubst") + 1); >> strsubst.c
+echo         sprintf(fname_out, "%%s.strsubst", fname_in); >> strsubst.c
+echo         if ((in = fopen(fname_in, "r")) == NULL) >> strsubst.c
+echo         { >> strsubst.c
+echo             fprintf(stderr, "%%s: can\'t open %%s\n", argv[0], fname_in); >> strsubst.c
+echo             return 2; >> strsubst.c
+echo         } >> strsubst.c
+newline >> strsubst.c
+echo         if ((out = fopen(fname_out, "w")) == NULL) >> strsubst.c
+echo         { >> strsubst.c
+echo             fprintf(stderr, "%%s: can\'t open %s\n", argv[0], fname_out); >> strsubst.c
+echo             return 2; >> strsubst.c
+echo         } >> strsubst.c
+echo         free(fname_out); >> strsubst.c
+echo     } >> strsubst.c
+newline >> strsubst.c
+echo     while ((fgets(buf, 0x400, in))) >> strsubst.c
+echo     { >> strsubst.c
+echo         q = buf; >> strsubst.c
+echo         while ((p = strstr(q, token)) != NULL) >> strsubst.c
+echo         { >> strsubst.c
+echo             *p = '\0'; >> strsubst.c
+echo             fprintf(out, "%%s%%s", q, subst); >> strsubst.c
+echo             q = p + strlen(token); >> strsubst.c
+echo         } >> strsubst.c
+echo         fprintf(out, q); >> strsubst.c
+echo     } >> strsubst.c
+newline >> strsubst.c
+echo     fclose(in); >> strsubst.c
+echo     fclose(out); >> strsubst.c
+newline >> strsubst.c
+echo     return 0; >> strsubst.c
+echo } >> strsubst.c
+
+cl %CFLAGS% strsubst.c %LINKFLAGS% > nul: 2>&1
+if errorlevel 1 (
+	@echo can^'t compile strsubst utility
+	goto :END
+)
+if exist strsubst.c del /q strsubst.c
+if exist strsubst.obj del /q strsubst.obj
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                    head                                   *
+rem *                                                                           *
+rem *****************************************************************************
+
+if exist head.c del /q head.c
+echo #include ^<stdio.h^> > head.c
+echo #include ^<stdlib.h^> >> head.c
+newline >> head.c
+echo int main(int argc, char *argv[]) >> head.c
+echo { >> head.c
+echo     char buf[0x400]; >> head.c
+echo     int line_count; >> head.c
+newline >> head.c
+echo     if (argc ^< 2) >> head.c
+echo     { >> head.c
+echo         fprintf(stderr, "usage: %%s <line count>\n", argv[0]); >> head.c
+echo         return 1; >> head.c
+echo     } >> head.c
+echo     line_count = atoi(argv[1]); >> head.c
+newline >> head.c
+echo     while (line_count-- ^&^& (fgets(buf, 0x400, stdin)) != NULL) >> head.c
+echo         printf(buf); >> head.c
+newline >> head.c
+echo     return 0; >> head.c
+echo } >> head.c
+
+cl %CFLAGS% head.c %LINKFLAGS% > nul: 2>&1
+if errorlevel 1 (
+	@echo can^'t compile head utility
+	goto :END
+)
+if exist head.c del /q head.c
+if exist head.obj del /q head.obj
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                   filter                                  *
+rem *                                                                           *
+rem *****************************************************************************
+
+if exist filter.c del /q filter.c
+echo #include ^<stdio.h^> > filter.c
+newline >> filter.c
+echo #define BUFSIZE 0x1000 >> filter.c
+newline >> filter.c
+echo int main(int argc, char *argv[]) >> filter.c
+echo { >> filter.c
+echo 	char buf[BUFSIZE]; >> filter.c
+echo 	char *mark; >> filter.c
+echo 	char *p; >> filter.c
+newline >> filter.c
+echo 	mark = argv[1]; >> filter.c
+newline >> filter.c
+echo 	while (!feof(stdin)) >> filter.c
+echo 	{ >> filter.c
+echo 		if ((p = fgets(buf, BUFSIZE - 1, stdin)) == NULL) break; >> filter.c
+echo 		if (strstr(buf, mark)) continue; >> filter.c
+echo 		fprintf(stdout, "%%s", buf); >> filter.c
+echo 	} >> filter.c
+newline >> filter.c
+echo 	return 0; >> filter.c
+echo } >> filter.c
+
+cl %CFLAGS% filter.c %LINKFLAGS% > nul: 2>&1
+if errorlevel 1 (
+	@echo can^'t compile filter utility
+	goto :END
+)
+if exist filter.c del /q filter.c
+if exist filter.obj del /q filter.obj
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                               configuration                               *
+rem *                                                                           *
+rem *****************************************************************************
+
+newline
+
+set PREFIX=
+set MATCH=
+set SUFFIX=
+set NEEDLE=
+set HAYSTACK=
+set QUESTION=
+set ANSWER=
+set USE_SSL=
+set SSL_DIR=
+set PCRE_DIR=
+set SUBDIRS=
+set DEBUG=
+
+echo please choose a few configuration options.
+newline
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                   PCRE                                    *
+rem *                                                                           *
+rem *****************************************************************************
+
+echo the cprops build on windows requires PCRE. 
+:GET_PCRE
+newline
+set _PCRE=
+if exist _pcre (
+	for /f "tokens=*" %%i in (_pcre) do set _PCRE=%%i
+)
+
+set QUESTION="Please specify PCRE include and library path"
+set DEFAULT=
+if defined _PCRE set DEFAULT=%_PCRE%
+call :readline
+
+if x%ANSWER% == x (
+	newline
+	echo libcprops requires PCRE to build on windows. If you do not have PCRE installed,
+	echo you could download it from http://gnuwin32.sourceforge.net/packages/pcre.htm
+	goto :END
+)
+
+set PCRE_DIR=%ANSWER%
+if not exist %PCRE_DIR%\include\pcreposix.h (
+	echo can^'t find %PCRE_DIR%\include\pcreposix.h
+	goto :GET_PCRE
+)
+newline
+
+if exist _pcre del /q _pcre
+echo %PCRE_DIR% > _pcre
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                             Create DLL or lib                             *
+rem *                                                                           *
+rem *****************************************************************************
+
+set QUESTION="link libcprops dynamically (DLL) or statically (LIB)"
+set DEFAULT=dll
+call :readline
+newline
+set TARGET=libcprops.lib
+
+if /i not "d"=="%ANSWER:~0,1%" goto :ENDLINK
+
+set TARGET=libcprops.dll
+set MAIN_CFLAGS=/D "_USRDLL" /D "CPROPS_EXPORTS" /GD
+:ENDLINK
+
+newline
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                  DEBUG                                    *
+rem *                                                                           *
+rem *****************************************************************************
+
+echo cprops may be built in DEBUG mode. The resulting DLL or library includes debug
+echo information, and some routines make debug printouts. 
+set QUESTION="Build in DEBUG mode?"
+set DEFAULT=no
+call :readline
+newline
+if /i "n"=="%ANSWER:~0,1%" goto :END_DEBUG
+set DEBUG=yes
+
+echo defining __TRACE__ gives a higher resolution of debug printouts.
+set QUESTION="define __TRACE__?"
+set DEFAULT=no
+call :readline
+newline
+if /i "n"=="%ANSWER:~0,1%" goto :END_DEBUG
+set __TRACE__=yes
+:END_DEBUG
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                       Multiple values in hash tables                      *
+rem *                                                                           *
+rem *****************************************************************************
+
+set QUESTION="allow multiple values in hash tables"
+set DEFAULT=no
+call :readline
+newline
+set HASHTABLE_MULTIPLES=
+
+if /i not "y"=="%ANSWER:~0,1%" goto :END_HASHTABLE_MULTIPLES
+
+set HASHTABLE_MULTIPLES=yes
+
+:END_HASHTABLE_MULTIPLES
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                       Multiple values in hash lists                       *
+rem *                                                                           *
+rem *****************************************************************************
+
+set QUESTION="allow multiple values in hash lists"
+set DEFAULT=no
+call :readline
+newline
+set HASHLIST_MULTIPLES=
+
+if /i not "y"=="%ANSWER:~0,1%" goto :END_HASHLIST_MULTIPLES
+
+set HASHLIST_MULTIPLES=yes
+
+:END_HASHLIST_MULTIPLES
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                            HTTP cookie support                            *
+rem *                                                                           *
+rem *****************************************************************************
+
+set QUESTION="include support for HTTP cookies"
+set DEFAULT="yes"
+call :readline
+newline
+set USE_COOKIES=yes
+
+if /i "y"=="%ANSWER:~0,1%" goto :END_COOKIES
+
+set USE_COOKIES=
+
+:END_COOKIES
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                            HTTP session support                           *
+rem *                                                                           *
+rem *****************************************************************************
+
+set QUESTION="include support for HTTP sessions"
+set DEFAULT="yes"
+call :readline
+newline
+set USE_HTTP_SESSIONS=yes
+
+if /i "y"=="%ANSWER:~0,1%" goto :END_HTTP_SESSIONS
+
+set USE_HTTP_SESSIONS=
+
+:END_HTTP_SESSIONS
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                 Open SSL                                  *
+rem *                                                                           *
+rem *****************************************************************************
+
+set QUESTION="include ssl support (this requires Open SSL)" 
+set DEFAULT="yes"
+call :readline
+newline
+
+if /i not "y"=="%ANSWER:~0,1%" goto :ENDSSL
+
+set USE_SSL=1
+
+if not defined OPENSSL_CONF goto :NO_OPENSSL_CONF
+
+echo found OPENSSL_CONF at %OPENSSL_CONF%
+set NEEDLE=OpenSSL
+set HAYSTACK=%OPENSSL_CONF%
+call :match
+set SSL_DIR=%PREFIX%%MATCH%
+if defined MATCH goto ENDSSL
+
+:NO_OPENSSL_CONF
+
+set QUESTION="please specify the location of your Open SSL installation"
+set DEFAULT=
+call :readline
+
+set SSL_DIR=%ANSWER%
+@echo using openssl installation at %SSL_DIR%
+
+:ENDSSL
+
+newline
+newline
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                  cpsvc                                    *
+rem *                                                                           *
+rem *****************************************************************************
+
+echo cpsvc is a simple web server included as sample code with the cprops 
+echo distribution. cpsvc is based on the cp_httpsocket API and supports CGI, 
+echo HTTP sessions, request piplining, and SSL if libcprops is configured 
+echo accordingly.
+set QUESTION="build cpsvc?"
+set DEFAULT=yes
+call :readline
+newline
+
+if /i not "y"=="%ANSWER:~0,1%" goto :END_CPSVC
+
+set BUILD_CPSVC=yes
+
+echo cpsp is an html page scripting framework allowing embedding C code in web 
+echo pages. Requires lex or an equivalent and yacc or an equivalent. 
+set QUESTION="build cpsp?"
+set DEFAULT=yes
+call :readline
+newline
+
+if /i not "y"=="%ANSWER:~0,1%" goto :END_CPSVC
+
+set BUILD_CPSP=yes
+set SUBDIRS=%SUBDIRS% svc\cpsp
+
+lex --version > nul: 2>&1
+if errorlevel 1 goto :FLEX 
+set LEX=lex
+goto :FIND_YACC
+
+:FLEX
+flex --version > nul: 2>&1
+if errorlevel 1 goto :ASK_LEX
+
+set LEX=flex
+goto :FIND_YACC
+
+:ASK_LEX
+echo can't find lex or flex on the path. If you don't have lex installed, a flex 
+echo version for windows is vailable at 
+echo http://www.monmouth.com/~wstreett/lex-yacc/lex-yacc.html
+newline
+
+set _LEX=
+if exist _lex (
+	for /f "tokens=*" %%i in (_lex) do set _LEX=%%i
+)
+
+:LEX
+set QUESTION="please specify path to lex executable"
+set DEFAULT=
+if defined _LEX set DEFAULT=%_LEX%
+
+call :readline
+newline
+if x%ANSWER%==x (
+	echo no lex available, stopping
+	goto :END
+)
+set LEX=%ANSWER%
+%LEX% --version > nul: 2>&1
+if errorlevel 1 (
+	echo can't execute lex at [%LEX%]
+	goto :LEX
+)
+if exist _lex del /q _lex
+echo %LEX% > _lex
+
+:FIND_YACC
+yacc --version > nul: 2>&1
+if errorlevel 1 goto :BISON
+
+set YACC=yacc
+goto :END_CPSVC
+
+
+:BISON
+bison --version > nul: 2>&1 
+if errorlevel 1 goto :ASK_YACC
+
+set YACC=bison
+goto :END_CPSVC
+
+:ASK_YACC
+echo can't find yacc or bison on the path. If you don't have yacc installed, a 
+echo bison version for windows is available at 
+echo http://www.monmouth.com/~wstreett/lex-yacc/lex-yacc.html
+newline
+
+set _YACC=
+if exist _yacc (
+	for /f "tokens=*" %%i in (_yacc) do set _YACC=%%i
+)
+
+:YACC
+set QUESTION="please specify path to yacc executable"
+set DEFAULT=
+if defined _YACC set DEFAULT=%_YACC%
+
+call :readline
+if x%ANSWER%==x (
+	echo no yacc available, stopping
+	goto :END
+)
+set YACC=%ANSWER%
+%YACC% --version > nul: 2>&1
+if errorlevel 1 (
+	echo can't execute yacc at [%YACC%]
+	goto :YACC
+)
+
+if exist _yacc del /q _yacc
+echo %YACC% > _yacc
+
+if exist %YACC%.simple copy %YACC%.simple svc\cpsp > nul: 2>&1 
+
+:END_CPSVC
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                            DBMS abstraction layer                         *
+rem *                                                                           *
+rem *****************************************************************************
+
+set QUESTION="Build cp_dbms - DBMS abstraction layer"
+set DEFAULT="yes"
+call :readline
+newline
+set BUILD_DBMS=dynamic
+
+if /i "y"=="%ANSWER:~0,1%" goto :DBMS_LINKAGE
+
+set BUILD_CP_DBMS=
+
+goto :END_DBMS
+
+:DBMS_LINKAGE
+
+set QUESTION="link DBMS driver/s statically or dynamically"
+set DEFAULT="dynamic"
+call :readline
+newline
+
+if /i not "s"=="%ANSWER:~0,1%" goto :DBMS_DRIVERS
+
+set BUILD_DBMS=static
+
+:DBMS_DRIVERS
+set CP_DBMS_DRIVERS=
+set QUESTION="install PostgresQL driver (requires libpq)"
+set DEFAULT=no
+call :readline
+newline
+
+if /i not "y"=="%ANSWER:~0,1%" goto :DBMS_MYSQL
+
+:GET_PGSQL_PATH
+set _PGSQL=
+if exist _pgsql (
+	for /f "tokens=*" %%i in (_pgsql) do set _PGSQL=%%i
+)
+
+set QUESTION="please specify path to postgres headers and include files"
+set DEFAULT=
+if defined _PGSQL set DEFAULT=%_PGSQL%
+call :readline
+set _PGSQL=
+newline
+set POSTGRES_DIR=%ANSWER%
+
+if "x%ANSWER%"=="x" (
+	echo "postgres path not specified, stopping"
+	goto :END
+)
+
+if not exist %POSTGRES_DIR%\include\libpq-fe.h (
+	echo can't find libpq-fe.h under %POSTGRES_DIR%\include
+	goto :GET_PGSQL_PATH
+)
+if exist %POSTGRES_DIR%\lib\libpq.lib goto :GOT_LIBPQ
+if exist %POSTGRES_DIR%\lib\ms\libpq.lib goto :GOT_LIBPQ
+echo can't find libpq.lib under %POSTGRES_DIR%\lib or %POSTGRES_DIR%\lib\ms
+echo did you install postgres from the no-installer zip? You'll need the 
+echo installer. Make sure to select developer files and MSVC libraries. 
+goto :GET_PGSQL_PATH
+:GOT_LIBPQ
+
+echo %POSTGRES_DIR%>_pgsql
+
+:DBMS_MYSQL
+set QUESTION="install MySQL driver (requires mysqlclient.lib)"
+set DEFAULT=no
+call :readline
+newline
+
+if /i not "y"=="%ANSWER:~0,1%" goto :END_DBMS
+
+:GET_MYSQL_PATH
+set _MYSQL=
+if exist _mysql (
+	for /f "tokens=*" %%i in (_mysql) do set _MYSQL=%%i
+)
+set QUESTION="please specify path to MySQL headers and include files"
+set DEFAULT=
+if defined _MYSQL set DEFAULT=%_MYSQL%
+call :readline
+set _MYSQL=
+newline
+set MYSQL_DIR=%ANSWER%
+
+if "x%ANSWER%"=="x" (
+	echo "MySQL path not specified, stopping"
+	goto :END
+)
+
+if not exist "%MYSQL_DIR%\lib\opt\mysqlclient.lib" (
+	echo can't find mysqlclient.lib on mysql path [%MYSQL_DIR%]
+	goto :GET_MYSQL_PATH
+)
+if not exist "%MYSQL_DIR%\include\mysql.h" (
+	echo can't find mysql.h header in mysql installation - possibly MySQL was 
+	echo installed without developer files
+	goto :GET_MYSQL_PATH
+)
+
+echo "%MYSQL_DIR%">_mysql
+:END_DBMS
+
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                                write output                               *
+rem *                                                                           *
+rem *****************************************************************************
+
+newline
+echo +--------------------------------------------------------------------------+
+echo ^|                                                                          ^|
+echo ^|              generating configuration headers and make files             ^|
+echo ^|                                                                          ^|
+echo +--------------------------------------------------------------------------+
+newline
+
+if exist config-cpwin.h del /q config-cpwin.h
+
+set CFG_CFLAGS=%CFG_CFLAGS% /I%PCRE_DIR%\include
+set CFG_LDFLAGS=%CFG_LDFLAGS%
+set CFG_LIBS=%PCRE_DIR%\lib\pcre.lib
+
+newline
+copy config.h.vc config.h > nul: 2>&1
+
+echo writing config-cpwin.h
+
+if defined HASHTABLE_MULTIPLES (
+	echo #define CP_HASHTABLE_MULTIPLE_VALUES 1 >> config-cpwin.h
+)
+
+if defined HASHLIST_MULTIPLES (
+	echo #define CP_HASHLIST_MULTIPLE_VALUES 1 >> config-cpwin.h
+)
+
+if defined USE_COOKIES (
+	echo #define CP_USE_COOKIES 1 >> config-cpwin.h
+)
+
+if defined USE_HTTP_SESSIONS (
+	echo #define CP_USE_HTTP_SESSIONS 1 >> config-cpwin.h
+)
+
+if defined BUILD_CPSVC (
+	set SUBDIRS=svc %SUBDIRS%
+)
+
+if defined BUILD_DBMS (
+	set OPT_OBJS=%OPT_OBJS% db.obj
+	if /i "d"=="%BUILD_DBMS:~0,1%" call :set_db_directories
+	if /i "s"=="%BUILD_DBMS:~0,1%" call :set_db_objects
+)
+
+if defined USE_SSL (
+	echo #define CP_USE_SSL 1 >> config-cpwin.h
+	set CFG_CFLAGS=%CFG_CFLAGS% /I%SSL_DIR%\include
+	set CFG_LDFLAGS=%CFG_LDFLAGS% %SSL_DIR%\lib\VC\libeay32MT.lib %SSL_DIR%\lib\VC\ssleay32MT.lib
+)
+
+if defined DEBUG (
+	set CFG_CFLAGS=%CFG_CFLAGS% /DDEBUG /D_DEBUG /Zi /MTd
+	set CFG_LDFLAGS=%CFG_LDFLAGS% /debug /pdb:libcprops.pdb /pdbtype:sept 
+)
+if not defined DEBUG set CFG_CFLAGS=%CFG_CFLAGS% /MT
+
+if defined __TRACE__ set CFG_CFLAGS=%CFG_CFLAGS% /D__TRACE__
+
+if exist Makefile del /q Makefile
+echo writing Makefile
+
+echo ############################################################################ > Makefile
+echo # >> Makefile
+echo # This makefile was generated by the configure.bat script. run nmake in this >> Makefile
+echo # directory to build libcprops. >> Makefile
+echo # >> Makefile
+echo # Copyright Ilan Aelion 2005, 2006 >> Makefile
+echo # >> Makefile
+echo # Please send bug reports, comments, suggestions, patches etc. to iaelion at  >> Makefile 
+echo # users dot sourceforge dot net. >> Makefile
+echo # >> Makefile
+echo ############################################################################ >> Makefile
+newline >> Makefile
+echo CC=CL >> Makefile
+echo LD=LINK >> Makefile
+echo CFLAGS=%MAIN_CFLAGS% %CFG_CFLAGS% >> Makefile
+echo LDFLAGS=%CFG_LDFLAGS% >> Makefile
+echo LIBS=%CFG_LIBS% >> Makefile
+newline >> Makefile
+echo TARGET=%TARGET% >> Makefile
+echo OPT_OBJS=%OPT_OBJS% >> Makefile
+echo OPT_TARGETS=%OPT_TARGETS% >> Makefile
+if defined POSTGRES_DIR (
+	newline >> Makefile
+	echo PGSQL_CFLAGS=/I"%POSTGRES_DIR%"\include >> Makefile
+	echo PGSQL_LDFLAGS=/libpath:"%POSTGRES_DIR%"\lib /libpath:"%POSTGRES_DIR%"\lib\ms>> Makefile
+	echo PGSQL_LIBS=libpq.lib >> Makefile
+)
+if defined MYSQL_DIR (
+	newline >> Makefile
+	echo MYSQL_CFLAGS=/I"%MYSQL_DIR%"\include >> Makefile
+	echo MYSQL_LDFLAGS=/libpath:"%MYSQL_DIR%"\lib\opt >> Makefile
+	echo MYSQL_LIBS=mysqlclient.lib >> Makefile
+)
+
+CD > CWD
+for /f "tokens=*" %%i in (CWD) do set CWD=%%i
+echo top_builddir=%CWD%>> Makefile
+del /q CWD
+newline >> Makefile
+echo subdirs=%SUBDIRS% >> Makefile
+newline >> Makefile
+
+type Makefile.vc >> Makefile
+if errorlevel 1 (
+	echo can't find Makefile.vc
+	goto :EOF
+)
+
+if defined BUILD_CPSVC (
+	echo writing svc\win.mak
+	if exist svc\win.mak del /q svc\win.mak > nul: 2>&1
+
+	copy svc\Makefile.vc svc\Makefile > nul: 2>&1
+	if errorlevel 1 (
+		echo can't find svc\Makefile.vc
+		goto :EOF
+	)
+	call :write_svc_mak
+
+	if exist svc\runcpsvc.bat del /q svc\runcpsvc.bat
+	CD > CWD
+	for /f "tokens=*" %%i in (CWD) do set CWD=%%i
+	echo set PATH=%%^PATH%%;%CWD%;%PCRE_DIR%\lib;%SSL_DIR%\lib\vc > svc\runcpsvc.bat
+	echo cpsvc %%^1 %%^2 %%^3 %%^4 %%^5 %%^6 %%^7 %%^8 %%^9 >> svc\runcpsvc.bat
+)
+
+if defined BUILD_CPSP (
+	echo #define CP_USE_CPSP 1 >> config-cpwin.h
+
+	if exist svc\cpsp\win.cpsp.mak del svc\cpsp\win.cpsp.mak
+	call :write_svc_cpsp_mak
+	CD > CWD
+	for /f "tokens=*" %%i in (CWD) do set CWD=%%i
+	echo top_builddir=%CWD%>> svc\cpsp\win.cpsp.mak
+	del /q CWD
+	echo prefix= >> svc\cpsp\win.cpsp.mak
+	echo exec_prefix= >> svc\cpsp\win.cpsp.mak
+	newline >> svc\cpsp\win.cpsp.mak
+	echo libdir=%CWD% >> svc\cpsp\win.cpsp.mak
+	echo incdir=%CWD%\.. >> svc\cpsp\win.cpsp.mak
+	echo bindir=%CWD%\svc >> svc\cpsp\win.cpsp.mak
+	newline >> svc\cpsp\win.cpsp.mak
+	echo LEX=%LEX% >> svc\cpsp\win.cpsp.mak
+	echo YACC=%YACC% >> svc\cpsp\win.cpsp.mak
+	
+	echo CPSP_SOURCES=cpsp.c cpsp_invoker.c >> svc\win.mak
+
+	copy svc\cpsp\Makefile.vc svc\cpsp\Makefile > nul: 2>&1
+	copy svc\cpsp\Makefile.cpsp.vc svc\cpsp\Makefile.cpsp > nul: 2>&1
+	
+	set SETPATH=svc\cpsp\setpath.bat
+	call :write_setpath
+	set SETPATH=svc\setpath.bat
+	call :write_setpath
+	set SETPATH=
+	copy newline.exe svc > nul: 2>&1
+	copy newline.exe svc\cpsp > nul: 2>&1
+	copy match.exe svc > nul: 2>&1
+	copy match.exe svc\cpsp > nul: 2>&1
+	copy strsubst.exe svc > nul: 2>&1
+	copy strsubst.exe svc\cpsp > nul: 2>&1
+	copy filter.exe svc > nul: 2>&1
+	copy filter.exe svc\cpsp > nul: 2>&1
+)
+
+echo writing example\win.mak
+copy example\Makefile.vc example\Makefile > nul: 2>&1
+if errorlevel 1 (
+	echo can't find example\Makefile.vc
+	goto :EOF
+)
+if exist example\win.mak del /q example\win.mak > nul: 2>&1
+echo CFLAGS=$(CFLAGS) %CFG_CFLAGS% > example\win.mak
+echo LDFLAGS=$(LDFLAGS) %CFG_LDFLAGS% >> example\win.mak
+echo LIBS=$(LIBS) %CFG_LIBS% >> example\win.mak
+if defined POSTGRES_DIR echo OPT_SRC=test_pq.c>> example\win.mak
+if defined MYSQL_DIR echo OPT_SRC=$(OPT_SRC) test_mysql.c>> example\win.mak
+
+echo writing http.h
+head 1 < VERSION > LIBVERSION
+for /f "tokens=*" %%i in (LIBVERSION) do set VERSION=%%i
+if exist http.h.in del http.h.in
+ren http.h http.h.in
+strsubst http.h.in __CPROPSVERSION %VERSION%
+copy http.h.in.strsubst http.h > nul: 2>&1
+set VERSION=
+
+echo done.
+newline 
+echo run nmake to build libcprops.
+
+goto :END
+
+
+rem *****************************************************************************
+rem *                                                                           *
+rem *                              utility invocations                          *
+rem *                                                                           *
+rem *****************************************************************************
+
+:readline
+set ANSWER=
+readline %QUESTION% %DEFAULT%
+if errorlevel 1 goto :EOF
+for /f "tokens=*" %%i in (__answer) do set ANSWER=%%i
+if exist __answer del __answer
+goto :EOF
+
+:match
+set MATCH=
+set PREFIX=
+set SUFFIX=
+match %HAYSTACK% %NEEDLE%
+if errorlevel 1 goto :EOF
+
+for /f "tokens=*" %%i in (__prefix) do set PREFIX=%%i
+for /f "tokens=*" %%i in (__match) do set MATCH=%%i
+for /f "tokens=*" %%i in (__suffix) do set SUFFIX=%%i
+if exist __prefix del __prefix
+if exist __match del __match
+if exist __suffix del __suffix
+goto :EOF
+
+:write_svc_mak
+echo CFLAGS=$(CFLAGS) %CFG_CFLAGS% > svc\win.mak
+echo LDFLAGS=$(LDFLAGS) %CFG_LDFLAGS% >> svc\win.mak
+echo LIBS=$(LIBS) %CFG_LIBS% >> svc\win.mak
+goto :EOF
+
+:write_svc_cpsp_mak
+echo CFLAGS=$(CFLAGS) %CFG_CFLAGS% > svc\cpsp\win.cpsp.mak
+echo LDFLAGS=$(LDFLAGS) %CFG_LDFLAGS% >> svc\cpsp\win.cpsp.mak
+echo LIBS=$(LIBS) %CFG_LIBS% >> svc\cpsp\win.cpsp.mak
+goto :EOF
+
+:set_db_directories
+if defined POSTGRES_DIR set OPT_TARGETS=libcp_dbms_postgres.dll
+if defined MYSQL_DIR set OPT_TARGETS=%OPT_TARGETS% libcp_dbms_mysql.dll
+goto :EOF
+
+:set_db_objects
+if defined POSTGRES_DIR (
+	set OPT_OBJS=%OPT_OBJS% db_postgres.obj
+	set CFG_CFLAGS=%CFG_CFLAGS% /I%POSTGRES_DIR%\include
+	set CFG_LDFLAGS=%CFG_LDFLAGS% /libpath:%POSTGRES_DIR%\lib /libpath:%POSTGRES_DIR%\lib\ms libpq.lib
+)
+if defined MYSQL_DIR (
+	set OPT_OBJS=%OPT_OBJS% db_mysql.obj
+	set CFG_CFLAGS=%CFG_CFLAGS% /I"%MYSQL_DIR%"\include
+	set CFG_LDFLAGS=%CFG_LDFLAGS% /libpath:"%MYSQL_DIR%"\lib\opt mysqlclient.lib
+	set CFG_LIBS=%CFG_LIBS% crypt32.lib advapi32.lib
+)
+goto :EOF
+
+:write_setpath
+if exist %SETPATH% del /q %SETPATH%
+set PATHSTR=%%^PATH%%
+echo set PCRE=> %SETPATH%
+echo match "%PATHSTR%" "%PCRE_DIR%">> %SETPATH%
+echo for /f "tokens=*" %%^%%^i in (__match) do set PCRE=%%^%%^i>> %SETPATH%
+echo if defined PCRE goto :CPROPS>> %SETPATH%
+echo @set PATH=%%^PATH%%;%PCRE_DIR%\lib>> %SETPATH%
+newline>> %SETPATH%
+echo :CPROPS>> %SETPATH%
+echo set CPDLL=>> %SETPATH%
+echo match "%PATHSTR%" "%CWD%">> %SETPATH%
+echo for /f "tokens=*" %%^%%^i in (__match) do set CPDLL=%%^%%^i>> %SETPATH%
+echo if defined CPDLL goto :CPSPEXE>> %SETPATH%
+echo @set PATH=%%^PATH%%;%CWD%>> %SETPATH%
+newline>> %SETPATH%
+echo :CPSPEXE>> %SETPATH%
+echo set CPSPPATH=>> %SETPATH%
+echo match "%PATHSTR%" "%CWD%\svc\cpsp">> %SETPATH%
+echo for /f "tokens=*" %%^%%^i in (__match) do set CPSPPATH=%%^%%^i>> %SETPATH%
+echo if defined CPSPPATH goto :SSL>> %SETPATH%
+echo @set PATH=%%^PATH%%;%CWD%\svc\cpsp>> %SETPATH%
+newline>> %SETPATH%
+echo :SSL>> %SETPATH%
+echo set OPENSSL=>> %SETPATH%
+echo match "%PATHSTR%" "%SSL_DIR%\lib\vc">> %SETPATH%
+echo for /f "tokens=*" %%^%%^i in (__match) do set OPENSSL=%%^%%^i>> %SETPATH%
+echo if defined OPENSSL goto :DONE>> %SETPATH%
+echo @set PATH=%%^PATH%%;%SSL_DIR%\lib\vc>> %SETPATH%
+echo :DONE>> %SETPATH%
+newline>> %SETPATH%
+echo set PCRE=>> %SETPATH%
+echo set CPDLL=>> %SETPATH%
+echo set CPSPPATH=>> %SETPATH%
+echo set OPENSSL=>> %SETPATH%
+set PATHSTR=
+goto :EOF
+
+:END
+rem clear variables and temporary files
+set QUESTION=
+set ANSWER=
+set NEEDLE=
+set HAYSTACK=
+set MATCH=
+set PREFIX=
+set SUFFIX=
+
+set CPROPS_LINK=
+set HASHTABLE_MULTIPLES=
+set HASHLIST_MULTIPLES=
+set USE_COOKIES=
+set USE_HTTP_SESSIONS=
+set BUILD_CPSVC=
+set BUILD_CPSP=
+set LEX=
+set YACC=
+set BUILD_DBMS=
+set TARGET=
+set OPT_OBJS=
+set OPT_TARGETS=
+set SUBDIRS=
+set PCRE_DIR=
+set SSL_DIR=
+set POSTGRES_DIR=
+set MYSQL_DIR=
+set DEBUG=
+set __TRACE__=
+set CFG_CFLAGS=
+set CFG_LDFLAGS=
+set LINKFLAGS=
+set CFG_LIBS=
+set MAIN_CFLAGS=
+
+if exist __suffix del __suffix
+if exist __answer del __answer
+if exist __prefix del __prefix 
+set USE_SSL=
+

Added: branches/multicore/numpy/core/cprops_thread/configure.in
===================================================================
--- branches/multicore/numpy/core/cprops_thread/configure.in	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/configure.in	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,762 @@
+dnl Process this file with autoconf to produce a configure script.
+AC_INIT(hashlist.c)
+AC_CONFIG_HEADER(config.h)
+
+CPROPSVERSION=`head -n 1 VERSION`
+AC_SUBST(CPROPSVERSION)
+CPROPSLIBVERSION=`head -n 2 VERSION | tail -n 1`
+AC_SUBST(CPROPSLIBVERSION)
+AC_SUBST(SED)
+
+SUBDIRS=
+root_dir=`pwd`
+AC_SUBST(root_dir)
+
+AC_ARG_WITH(cflags,
+[  --with-cflags=FLAGS     use FLAGS for CFLAGS],
+CFLAGS="$CFLAGS $withval")
+
+AC_ARG_WITH(libs,
+[  --with-libs=LIBS        use LIBS for extra libraries],
+LIBS="$LIBS $withval")
+
+OPT_OBJS=""
+
+AC_CANONICAL_HOST
+
+case "$host" in
+  *-linux-*)
+    CFLAGS="$CFLAGS -D_REENTRANT -D_GNU_SOURCE"
+    ;;
+  *-solaris*)
+    LIBS="$LIBS -lsocket -lnsl"
+    AC_MSG_CHECKING([where ar is])
+    for loc in /usr/xpg4/bin /usr/ccs/bin /usr/local/bin /usr/bin; do
+      if test -x "$loc/ar"; then
+        ardir="$loc"
+		break;
+      fi
+    done
+    if test "x$ardir" != "x"; then
+	AR=$ardir/ar
+    fi
+    AC_MSG_RESULT($ardir)
+    ;;
+  *-apple-darwin6*)
+    CFLAGS="$CFLAGS -no-cpp-precomp"
+	;;
+esac
+
+
+dnl -------------------------------------------------------------------------
+dnl check for gnu make
+dnl -------------------------------------------------------------------------
+
+make_command=""
+for a in "$MAKE" make gmake gnumake 
+  do test -z "$a" && continue
+    if  ( sh -c "$a --version" 2>/dev/null | grep GNU >/dev/null ) 
+      then make_command=$a ; break;
+    fi
+  done
+if test -z $make_command ; then 
+  gnu_make=""
+else
+  gnu_make="$make_command"
+fi
+
+AC_SUBST(gnu_make)
+
+
+dnl -------------------------------------------------------------------------
+dnl Checks for programs.
+dnl -------------------------------------------------------------------------
+
+AC_PROG_CC
+AC_PROG_LEX
+AC_PROG_YACC
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+if test "$GCC" = "yes" ; then
+  CFLAGS="$CFLAGS -O2"
+fi
+
+dnl -------------------------------------------------------------------------
+dnl Checks for libraries.
+dnl -------------------------------------------------------------------------
+
+AC_CHECK_LIB(dl, dlsym)
+if test -z "$pthread"; then
+    AC_CHECK_LIB(pthread, pthread_create, [LIBS="$LIBS -lpthread"])
+fi
+
+dnl -------------------------------------------------------------------------
+dnl Checks for header files
+dnl -------------------------------------------------------------------------
+
+AC_HEADER_STDC
+AC_CHECK_HEADER(fcntl.h, AC_DEFINE([CP_HAS_FCNTL_H]), )
+AC_CHECK_HEADER(sys/time.h, AC_DEFINE([CP_HAS_SYS_TIME_H]), )
+AC_CHECK_HEADER(stdarg.h, AC_DEFINE([CP_HAS_STDARG_H]), )
+AC_CHECK_HEADER(unistd.h, AC_DEFINE([CP_HAS_UNISTD_H]), )
+AC_CHECK_HEADER(pthread.h, AC_DEFINE([CP_HAS_PTHREAD_H]), )
+AC_CHECK_HEADER(regex.h, AC_DEFINE([CP_HAS_REGEX_H]), )
+AC_CHECK_HEADER(sys/socket.h, AC_DEFINE([CP_HAS_SYS_SOCKET_H]), )
+AC_CHECK_HEADER(sys/select.h, AC_DEFINE([CP_HAS_SYS_SELECT_H]), )
+AC_CHECK_HEADER(netinet/in.h, AC_DEFINE([CP_HAS_NETINET_IN_H]), )
+AC_CHECK_HEADER(netdb.h, AC_DEFINE([CP_HAS_NETDB_H]), )
+AC_CHECK_HEADER(sys/poll.h, AC_DEFINE([CP_HAS_SYS_POLL_H]), )
+AC_CHECK_HEADER(dirent.h, AC_DEFINE([CP_HAS_DIRENT_H]), )
+
+AC_CHECK_HEADER(dlfcn.h,[
+AC_DEFINE_UNQUOTED(CP_HAS_DLFCN_H, 1, [define if you have <dlfcn.h>])
+ac_have_dlfcn_h=yes
+],[
+ac_have_dlfcn_h=
+])
+
+dnl -------------------------------------------------------------------------
+dnl Checks for typedefs, structures, and compiler characteristics
+dnl -------------------------------------------------------------------------
+
+AC_C_CONST
+AC_C_INLINE 
+AC_HEADER_TIME
+AC_STRUCT_TM
+
+AC_MSG_CHECKING(whether long long is supported)
+AC_TRY_COMPILE([
+#include <stdio.h>
+], [
+    long long l = 1;
+], 
+[ 
+    AC_MSG_RESULT(yes)
+    AC_DEFINE([CP_HAS_LONG_LONG], [1], [long long supported])
+], [
+    AC_MSG_RESULT(no)
+])
+
+AC_MSG_CHECKING(whether variadic macros are supported)
+AC_TRY_COMPILE([
+#include <stdio.h>
+#define PRINT(fmt, ...) printf(fmt, ## __VA_ARGS__)
+], [
+    PRINT("%d %d %d", 1, 2, 3);
+    return 0;
+], [
+AC_MSG_RESULT(yes)
+AC_DEFINE([CP_HAS_VARIADIC_MACROS], [1], [variadic macros are supported])
+], [
+AC_MSG_RESULT(no)
+])
+
+
+dnl -------------------------------------------------------------------------
+dnl Checks for library functions
+dnl -------------------------------------------------------------------------
+
+AC_MSG_CHECKING(whether struct addrinfo is defined)
+AC_TRY_LINK([
+#include <sys/types.h>
+#include <netdb.h>
+], [
+struct addrinfo p;
+struct addrinfo *a = &p;
+], [
+AC_MSG_RESULT(yes)
+AC_DEFINE([CP_HAS_ADDRINFO], [1], [struct addrinfo is defined])
+], [
+AC_MSG_RESULT(no)
+])
+
+AC_MSG_CHECKING(whether PTHREAD_MUTEX_RECURSIVE is supported)
+AC_TRY_RUN([
+#define GNU_SOURCE
+#include <pthread.h>
+
+int main(void) 
+{
+    int rc;
+    pthread_mutex_t m;
+    pthread_mutexattr_t a;
+
+    if ((rc = pthread_mutexattr_init(&a))) return rc;
+    if ((rc = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE)))
+        return rc;
+
+    if ((rc = pthread_mutex_init(&m, &a))) return rc;
+    if ((rc = pthread_mutex_lock(&m))) return rc;
+    if ((rc = pthread_mutex_trylock(&m))) return rc;
+    pthread_mutex_unlock(&m);
+    pthread_mutex_unlock(&m);
+
+    return 0;
+}
+],
+recursive_mutex=yes
+AC_MSG_RESULT(yes)
+AC_DEFINE(CP_HAS_PTHREAD_MUTEX_RECURSIVE, [1], 
+              [Define to 1 if PTHREAD_MUTEX_RECURSIVE is supported]),
+AC_MSG_RESULT(no))
+
+if test "x$recursive_mutex" = "x" ; then
+AC_MSG_CHECKING(whether PTHREAD_MUTEX_RECURSIVE_NP is supported)
+AC_TRY_RUN([
+#define GNU_SOURCE
+#include <pthread.h>
+
+int main(void) 
+{
+    int rc;
+    pthread_mutex_t m;
+    pthread_mutexattr_t a;
+
+    if ((rc = pthread_mutexattr_init(&a))) return rc;
+    if ((rc = pthread_mutexattr_settype(&a, PTHREAD_MUTEX_RECURSIVE_NP)))
+        return rc;
+
+    if ((rc = pthread_mutex_init(&m, &a))) return rc;
+    if ((rc = pthread_mutex_lock(&m))) return rc;
+    if ((rc = pthread_mutex_trylock(&m))) return rc;
+    pthread_mutex_unlock(&m);
+    pthread_mutex_unlock(&m);
+
+    return 0;
+}
+],
+recursive_mutex=yes
+AC_MSG_RESULT(yes)
+AC_DEFINE(CP_HAS_PTHREAD_MUTEX_RECURSIVE_NP, [1], 
+              [Define to 1 if PTHREAD_MUTEX_RECURSIVE_NP is supported]),
+AC_MSG_RESULT(no))
+fi
+
+AC_FUNC_MEMCMP
+AC_FUNC_STRFTIME
+AC_FUNC_VPRINTF
+AC_CHECK_FUNC(strstr, AC_DEFINE([CP_HAS_STRSTR]),)
+AC_CHECK_FUNC(memset, AC_DEFINE([CP_HAS_MEMSET]),)
+AC_CHECK_FUNC(strdup, AC_DEFINE([CP_HAS_STRDUP]),)
+AC_CHECK_FUNC(strndup, AC_DEFINE([CP_HAS_STRNDUP]),)
+AC_CHECK_FUNC(regcomp, AC_DEFINE([CP_HAS_REGCOMP]),)
+AC_CHECK_FUNC(strerror_r, AC_DEFINE([CP_HAS_STRERROR_R]),)
+AC_CHECK_FUNC(gettimeofday, AC_DEFINE([CP_HAS_GETTIMEOFDAY]),)
+AC_CHECK_FUNC(getopt, AC_DEFINE([CP_HAS_GETOPT]),)
+AC_CHECK_FUNC(dlopen, AC_DEFINE([CP_HAS_DLOPEN]),)
+AC_CHECK_FUNC(sigaction, AC_DEFINE([CP_HAS_SIGACTION]),)
+AC_CHECK_FUNC(read, AC_DEFINE([CP_HAS_READ]),)
+AC_CHECK_FUNC(write, AC_DEFINE([CP_HAS_WRITE]),)
+AC_CHECK_FUNC(socket, AC_DEFINE([CP_HAS_SOCKET]),)
+AC_CHECK_FUNC(select, AC_DEFINE([CP_HAS_SELECT]),)
+AC_CHECK_FUNC(poll, AC_DEFINE([CP_HAS_POLL]),)
+AC_CHECK_FUNC(inet_ntoa, AC_DEFINE([CP_HAS_INET_NTOA]),)
+AC_CHECK_FUNC(inet_ntop, AC_DEFINE([CP_HAS_INET_NTOP]),)
+AC_CHECK_FUNC(gethostname, AC_DEFINE([CP_HAS_GETHOSTNAME]),)
+AC_CHECK_FUNC(getaddrinfo, AC_DEFINE([CP_HAS_GETADDRINFO]),)
+AC_CHECK_FUNC(getcwd, AC_DEFINE([CP_HAS_GETCWD]),)
+AC_CHECK_FUNC(gmtime_r, AC_DEFINE([CP_HAS_GMTIME_R]),)
+AC_CHECK_FUNC(localtime_r, AC_DEFINE([CP_HAS_LOCALTIME_R]),)
+AC_CHECK_FUNC(pthread_getunique_np, AC_DEFINE([CP_HAS_PTHREAD_GETUNIQUE_NP]),)
+AC_CHECK_FUNC(random, AC_DEFINE([CP_HAS_RANDOM]),)
+AC_CHECK_FUNC(strlcat, AC_DEFINE([CP_HAS_STRLCAT]),)
+AC_CHECK_FUNC(strlcpy, AC_DEFINE([CP_HAS_STRLCPY]),)
+AC_CHECK_FUNC(snprintf, AC_DEFINE([CP_HAS_SNPRINTF]),)
+AC_CHECK_FUNC(vsprintf, AC_DEFINE([CP_HAS_VSPRINTF]),)
+AC_CHECK_FUNC(vsnprintf, AC_DEFINE([CP_HAS_VSNPRINTF]),)
+AC_CHECK_FUNC(strcasecmp, AC_DEFINE([CP_HAS_STRCASECMP]),)
+AC_CHECK_FUNC(strncasecmp, AC_DEFINE([CP_HAS_STRNCASECMP]),)
+AC_CHECK_FUNC(srandom, AC_DEFINE([CP_HAS_SRANDOM]),)
+AC_CHECK_FUNC(stat, AC_DEFINE([CP_HAS_STAT]),)
+AC_CHECK_FUNC(strptime, AC_DEFINE([CP_HAS_STRPTIME]),)
+AC_CHECK_FUNC(getpagesize, AC_DEFINE([CP_HAS_GETPAGESIZE]),)
+
+
+dnl -------------------------------------------------------------------------
+dnl collection behavior options
+dnl -------------------------------------------------------------------------
+
+AC_ARG_ENABLE(hashtable-multiples,
+[  --enable-hashtable-multiples   hashtables allow multiple values [[disabled]]], [
+  if test "$enableval" = yes; then
+      echo enabling multiple values in hash tables
+      AC_DEFINE([CP_HASHTABLE_MUTLIPLE_VALUES], [1], [allow multiple values])
+  else
+      echo disabling multiple values in hash tables
+      AC_DEFINE([CP_HASHTABLE_MUTLIPLE_VALUES], [0], [no multiple values])
+  fi
+])
+
+AC_ARG_ENABLE(hashlist-multiples,
+[  --enable-hashlist-multiples    hashlists allow multiple values [[disabled]]], [
+  if test "$enableval" = yes; then
+      echo enabling multiple values in hash lists
+      AC_DEFINE([CP_HASHLIST_MUTLIPLE_VALUES], [1], [allow multiple values])
+  else
+      echo disabling multiple values in hash lists
+      AC_DEFINE([CP_HASHLIST_MUTLIPLE_VALUES], [0], [no multiple values])
+  fi
+])
+
+dnl -------------------------------------------------------------------------
+dnl server cookie support
+dnl -------------------------------------------------------------------------
+
+AC_ARG_ENABLE(server-cookies,
+[  --disable-server-cookies       server support for http cookies [[enabled]]], 
+  enable_server_cookies=$enableval, enable_server_cookies=yes)
+
+if test "$enable_server_cookies" = yes ; then
+  echo enabling server support for http cookies
+  AC_DEFINE(CP_USE_COOKIES, [1], [Define to 1 if supporting http cookies])
+else
+  echo disabling server support for http cookies
+  AC_DEFINE(CP_USE_COOKIES, [0], [not supporting http cookies])
+fi
+	
+dnl -------------------------------------------------------------------------
+dnl http session support
+dnl -------------------------------------------------------------------------
+
+AC_ARG_ENABLE(http-sessions,
+[  --disable-http-sessions        support for http sessions [[enabled]]], 
+	enable_http_sessions=$enableval, enable_http_sessions=yes)
+
+if test "$enable_http_sessions" = yes ; then
+    echo enabling http sessions
+    AC_DEFINE(CP_USE_HTTP_SESSIONS, [1], [Define to 1 if supporting http sessions])
+else
+	echo disabling http sessions
+    AC_DEFINE(CP_USE_HTTP_SESSIONS, [0], [not supporting http sessions])
+fi
+
+dnl -------------------------------------------------------------------------
+dnl openssl 
+dnl -------------------------------------------------------------------------
+
+AC_ARG_WITH(ssl, 
+[  --with-ssl[=DIR]          path to OpenSSL installation [[/usr/local/ssl]]], [
+  AC_MSG_CHECKING(for libssl)
+  if test -d "$withval"; then
+    ssllib="$withval/lib";
+    sslinc="$withval/include";
+	AC_MSG_RESULT(found)
+  else
+    AC_MSG_RESULT(not found)
+    AC_MSG_ERROR(can't find OpenSSL installation at $withval)
+  fi
+])
+
+AC_ARG_ENABLE(ssl,
+[  --enable-ssl                   enable ssl support [[enabled]]], [
+  if test "$enableval" = no ; then
+    AC_MSG_RESULT(disabling ssl)
+	ssl=no
+  else
+    ssl=yes
+  fi
+],[
+  ssl=yes
+])
+
+dnl check where openssl is installed
+if test "$ssl" = "yes" ; then
+  AC_MSG_CHECKING(libssl location)
+  if test "x$ssllib" = "x" && test "x$sslinc" = "x"; then
+    for loc in /usr/lib /usr/local/ssl/lib /usr/local/openssl/lib; do
+      if test -f "$loc/libssl.a"; then
+        ssllib="$loc"
+		break
+      fi
+    done
+    for loc in /usr/include/ssl /usr/include/openssl /usr/local/ssl/include \
+               /usr/local/openssl/include; do
+      if test -d "$loc"; then
+        sslinc="$loc"
+		break
+      fi
+    done
+  fi
+
+  if test "x$ssllib" = "x" ; then
+    AC_MSG_RESULT(not found, disabling)
+	ssl=no
+  else
+    AC_MSG_RESULT( $ssllib)
+  fi
+fi
+
+
+if test "$ssl" = "yes" ; then
+  LIBS="$LIBS -lssl"
+  ssl_example="test_ssl_client.c"
+  AC_DEFINE(CP_USE_SSL, [1], [Define to 1 if compiling with OpenSSL support])
+  if test "x$sslinc" != "x" ; then
+    CFLAGS="$CFLAGS -I $sslinc"
+  fi
+  if test "x$ssllib" != "x" ; then
+    LDFLAGS="$LDFLAGS -L$ssllib"
+  fi
+
+  case "$host" in
+    *-*-openbsd* | *-*-freebsd* | *-*-netbsd* | *-*-darwin*)
+      LIBS="$LIBS -lcrypto"
+      ;;
+    *-solaris*)
+      LIBS="$LIBS -lcrypto"
+      ;;
+  esac
+fi
+  
+dnl -------------------------------------------------------------------------
+dnl cp_dbms support 
+dnl -------------------------------------------------------------------------
+
+dnl cp_dbms enabled by default unless dlfcn.h is missing
+if test "$ac_have_dlfcn_h" = "yes" ; then
+  AC_ARG_ENABLE(cp-dbms,
+  [  --enable-cp-dbms               build dbms abstraction layer [[enabled]]], 
+    make_cp_dbms=$enableval, make_cp_dbms=yes)
+else
+  AC_ARG_ENABLE(cp-dbms,
+  [  --enable-cp-dbms               build dbms abstraction layer [[disabled]]], 
+    make_cp_dbms=$enableval, make_cp_dbms=)
+fi
+  
+dnl -------------------------------------------------------------------------
+dnl postgres declarations
+dnl -------------------------------------------------------------------------
+
+use_pgsql=""
+pg_dir_prm=""
+pg_lib_prm=""
+pg_include_prm=""
+
+AC_ARG_WITH(postgres, 
+[  --with-postgres[[=DIR]]          enable postgres support, assume postgres
+                                 installation in DIR [[disabled]]], 
+[ use_pgsql="1"
+  pg_dir_prm=$withval], [])
+
+AC_ARG_WITH(postgres-libs,
+[  --with-postgres-libs=DIR       use postgres libraries installed in DIR],
+[ use_pgsql="1"
+  pg_lib_prm=$withval], [])
+
+AC_ARG_WITH(postgres-includes,
+[  --with-postgres-includes=DIR   use postgres header files installed in DIR],
+[ use_pgsql="1"
+  pg_include_prm=$withval], [])
+
+if test "x$use_pgsql" != "x" ; then
+  make_cp_dbms=yes
+fi
+
+dnl -------------------------------------------------------------------------
+dnl mysql declarations
+dnl -------------------------------------------------------------------------
+
+use_mysql=""
+mysql_dir_prm=""
+mysql_lib_prm=""
+mysql_include_prm=""
+
+AC_ARG_WITH(mysql, 
+[  --with-mysql[[=DIR]]             enable mysql support, assume mysql
+                                 installation in DIR [[disabled]]], 
+[ use_mysql="1"
+  mysql_dir_prm=$withval], [])
+
+AC_ARG_WITH(mysql-libs,
+[  --with-mysql-libs=DIR          use mysql libraries installed in DIR],
+[ use_mysql="1"
+  mysql_lib_prm=$withval], [])
+
+AC_ARG_WITH(mysql-includes,
+[  --with-mysql-includes=DIR      use mysql header files installed in DIR],
+[ use_mysql="1"
+  mysql_include_prm=$withval], [])
+
+if test "x$use_mysql" != "x" ; then
+  make_cp_dbms=yes
+fi
+
+dnl -------------------------------------------------------------------------
+dnl link cp_dbms support statically or dynamically
+dnl -------------------------------------------------------------------------
+
+dnl if dlfcn available, use --enable-static-dbms configuration option. 
+dnl Otherwise, link dbms libraries statically.
+if test "$ac_have_dlfcn_h" = "yes" ; then
+  AC_ARG_ENABLE(static-dbms,
+  [  --enable-static-dbms           link dbms drivers statically [[disabled]]], 
+    cp_dbms_static=$enableval, cp_dbms_static=no)
+else
+  cp_dbms_static=yes
+fi
+
+if test "$make_cp_dbms" = yes; then
+  OPT_OBJS=db.o
+  if test "$cp_dbms_static" = yes ; then
+    echo linking dbms drivers statically
+	AC_DEFINE(CP_DBMS_STATIC, [1], 
+              [Define to 1 if linking dbms libraries statically]),
+  else
+    echo linking dbms drivers dynamically
+  fi
+fi
+
+dnl -------------------------------------------------------------------------
+dnl postgres setup
+dnl -------------------------------------------------------------------------
+
+AC_MSG_CHECKING(whether to compile postgres support) 
+if test "x$use_pgsql" != "x" ; then
+  AC_MSG_RESULT(yes)
+  if test -e "$pg_lib_prm/libpq.a" ; then
+    pg_lib = $pg_lib_prm
+  else
+    for loc in $pg_dir_prm /usr/local /usr /usr/local/pgsql /usr/local/postgres /usr/local/postgresql /opt/pgsql /opt/postgres /opt/postgresql ; do
+      if test -e "$loc/lib/libpq.a" ; then
+	    pg_lib="$loc/lib"
+		break
+	  fi
+    done
+  fi
+
+  if test "x$pg_lib" = "x" ; then
+    AC_MSG_ERROR(can't find postgres client library)
+  fi
+
+  if test -e "$pg_include_prm/libpq-fe.h" ; then
+    pg_include = $pg_include_prm
+  else
+    for loc in $pg_dir_prm /usr/local /usr /usr/local/pgsql /usr/local/postgres /usr/local/postgresql /opt/pgsql /opt/postgres /opt/postgresql ; do
+      if test -e "$loc/include/libpq-fe.h" ; then
+  	    pg_include="$loc/include"
+		break
+      fi
+    done
+  fi
+
+  if test "x$pg_include" = "x" ; then
+    AC_MSG_ERROR(can't find postgres client header files)
+  fi
+
+  dnl libpq treats binary parameters as big endian (network order) - check if 
+  dnl conversions required
+  AC_MSG_CHECKING(whether hardware byte order is little endian)
+  AC_TRY_RUN([
+    int main(void) 
+	{
+	    int i = 1;
+		char *c = (char *) &i;
+		return *c == 0;
+	}],
+    AC_MSG_RESULT(yes)
+    AC_DEFINE(CP_BYTE_ORDER_LITTLE_ENDIAN, [1], 
+              [Define to 1 if hardware byte order is little endian]),
+	AC_MSG_RESULT(no))
+
+  OPT_TARGETS="$OPT_TARGETS libcp_dbms_postgres.la"
+  OPT_INSTALL="$OPT_INSTALL install-libcp-dbms-postgres"
+  PGSQL_CFLAGS="$CFLAGS -I$pg_include"
+  PGSQL_LDFLAGS="$LDFLAGS -L$pg_lib"
+  PGSQL_LIBS="$LIBS -lpq"
+  AC_SUBST(PGSQL_CFLAGS)
+  AC_SUBST(PGSQL_LDFLAGS)
+  AC_SUBST(PGSQL_LIBS)
+  PGSQL_SRC=db_postgres.c
+  PGSQL_HDR=db_postgres.h
+  PGSQL_OBJ=db_postgres.o
+  AC_SUBST(PGSQL_SRC)
+  AC_SUBST(PGSQL_HDR)
+  AC_SUBST(PGSQL_OBJ)
+  CP_DBMS_PGSQL_LIBVERSION=`cat LIBVERSION_CP_DBMS_POSTGRES`
+  AC_SUBST(CP_DBMS_PGSQL_LIBVERSION)
+  db_examples="$db_examples test_pq.c"
+  if test "$cp_dbms_static" = "yes" ; then
+    CFLAGS="$CFLAGS -I$pg_include"
+    LDFLAGS="$LDFLAGS -L$pg_lib"
+    LIBS="$LIBS -lpq"
+    OPT_OBJS="$OPT_OBJS db_postgres.o"
+  fi
+else
+  AC_MSG_RESULT(no)
+fi
+  
+dnl -------------------------------------------------------------------------
+dnl mysql setup
+dnl -------------------------------------------------------------------------
+
+AC_MSG_CHECKING(whether to compile mysql support) 
+if test "x$use_mysql" != "x" ; then
+  AC_MSG_RESULT(yes)
+  if test -e "$mysql_lib_prm/libmysqlclient.a" ; then
+    mysql_lib = $mysql_lib_prm
+  else
+    for loc in $mysql_dir_prm /usr/local /usr /usr/local/mysql /opt/mysql ; do
+      if test -e "$loc/lib/libmysqlclient.a" ; then
+	    mysql_lib="$loc/lib"
+		break
+	  fi
+    done
+  fi
+
+  if test "x$mysql_lib" = "x" ; then
+    AC_MSG_ERROR(can't find mysql client library)
+  fi
+
+  if test -e "$mysql_include_prm/mysql.h" ; then
+    mysql_include = $mysql_include_prm
+  else
+    for loc in $mysql_dir_prm /usr/local /usr /usr/local/mysql /opt/mysql ; do
+      if test -e "$loc/include/mysql.h" ; then
+  	    mysql_include="$loc/include"
+		break
+      fi
+    done
+  fi
+
+  if test "x$mysql_include" = "x" ; then
+    AC_MSG_ERROR(can't find mysql client header files)
+  fi
+
+  OPT_TARGETS="$OPT_TARGETS libcp_dbms_mysql.la"
+  OPT_INSTALL="$OPT_INSTALL install-libcp-dbms-mysql"
+  MYSQL_CFLAGS="$CFLAGS -I$mysql_include"
+  MYSQL_LDFLAGS="$LDFLAGS -L$mysql_lib"
+  MYSQL_LIBS="$LIBS -lmysqlclient -lz"
+  AC_SUBST(MYSQL_CFLAGS)
+  AC_SUBST(MYSQL_LDFLAGS)
+  AC_SUBST(MYSQL_LIBS)
+  MYSQL_SRC=db_mysql.c
+  MYSQL_HDR=db_mysql.h
+  MYSQL_OBJ=db_mysql.o
+  AC_SUBST(MYSQL_SRC)
+  AC_SUBST(MYSQL_HDR)
+  AC_SUBST(MYSQL_OBJ)
+  CP_DBMS_MYSQL_LIBVERSION=`cat LIBVERSION_CP_DBMS_MYSQL`
+  AC_SUBST(CP_DBMS_MYSQL_LIBVERSION)
+  db_examples="$db_examples test_mysql.c"
+  if test "$cp_dbms_static" = "yes" ; then
+    CFLAGS="$CFLAGS -I$mysql_include"
+    LDFLAGS="$LDFLAGS -L$mysql_lib"
+    LIBS="$LIBS -lmysqlclient -lz"
+    OPT_OBJS="$OPT_OBJS db_mysql.o"
+  fi
+else
+  AC_MSG_RESULT(no)
+fi
+  
+dnl -------------------------------------------------------------------------
+dnl build cpsvc
+dnl -------------------------------------------------------------------------
+
+AC_ARG_ENABLE(cpsvc,
+[  --enable-cpsvc                 build cpsvc [[yes]]], 
+  enable_cpsvc=$enableval, enable_cpsvc=yes)
+
+if test "$enable_cpsvc" = yes ; then
+  echo building cpsvc
+  CPSVC=yes
+  subdirs="$subdirs svc"
+else
+  echo skipping cpsvc
+  CPSVC=
+fi
+
+dnl define enable-cpsp option unless dlfcn.h missing
+if test "$ac_have_dlfcn_h" = "yes" ; then 
+AC_ARG_ENABLE(cpsp,
+[  --enable-cpsp                  build cpsp [[yes]]], 
+  enable_cpsp=$enableval, enable_cpsp=yes)
+else
+  enable_cpsp=
+fi
+
+if test "$enable_cpsp" = yes ; then
+
+  if test "$LEX" = "" || test "$LEX" = ":" ; then
+    AC_MSG_ERROR(lex required for cpsp - either install lex or disable cpsp);
+  fi
+
+  if test "$YACC" = "" || test "$YACC" = ":" ; then
+    AC_MSG_ERROR(yacc required for cpsp - either install yacc or disable cpsp);
+  fi
+
+  echo enabling cpsp service
+  CPSP=yes
+  AC_DEFINE([CP_USE_CPSP], [1], [supporting cpsp])
+  subdirs="$subdirs svc/cpsp"
+  cpsp_sources="cpsp.c cpsp_invoker.c"
+  AC_SUBST(cpsp_sources)
+else
+  echo skipping cpsp
+  CPSP=
+fi
+
+AC_SUBST(subdirs)
+AC_SUBST(OPT_TARGETS)
+AC_SUBST(OPT_INSTALL)
+AC_SUBST(ssl_example)
+AC_SUBST(db_examples)
+
+if test "x$CFLAGS" = "x" ; then
+  CFLAGS=-O2
+fi
+
+output=Makefile
+
+if test "x$CPSVC" != "x" ; then
+  output="$output svc/Makefile"
+fi
+
+if test "x$CPSP" != "x" ; then
+  output="$output svc/cpsp/Makefile svc/cpsp/cpsp-gen.sh svc/cpsp/Makefile.cpsp"
+fi
+
+output="$output example/Makefile"
+
+dnl -------------------------------------------------------------------------
+dnl set current version number for default server name in http.h
+dnl -------------------------------------------------------------------------
+mv http.h http.h.in
+sed "s/__CPROPSVERSION/$CPROPSVERSION/" http.h.in > http.h
+
+AC_SUBST(OPT_OBJS)
+
+dnl check for makedepend
+MAKEDEPEND=`which makedepend | sed '/^no /d'`
+if test "x$MAKEDEPEND" = "x" ; then
+  for loc in /usr/X11R6/bin /usr/X/bin; do
+    if test -e "$loc/makedepend"; then
+	  MAKEDEPEND=$loc/makedepend -Y
+	  break
+	fi
+  done
+  if test "x$MAKEDEPEND" = "x" ; then
+    MAKEDEPEND=$root_dir/makedepend.sh
+  fi
+else
+  MAKEDEPEND="$MAKEDEPEND -Y"
+fi
+
+AC_SUBST(MAKEDEPEND)
+
+AC_OUTPUT($output)
+
+dnl -------------------------------------------------------------------------
+dnl create dependencies
+dnl -------------------------------------------------------------------------
+
+make depend
+if test "$enable_cpsvc" = "yes" ; then
+	pushd svc  > /dev/null
+	make depend 
+	popd > /dev/null
+fi
+pushd example > /dev/null
+make depend
+popd > /dev/null

Added: branches/multicore/numpy/core/cprops_thread/cp_config.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/cp_config.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/cp_config.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,48 @@
+/* config.h.  Generated by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* fixme: #define values that have been commented out with //// are not used 
+          in any of the files we need.
+*/
+
+#ifndef _CP_CONFIG_H
+#define _CP_CONFIG_H
+
+/* Unix specific things.
+ * fixme: this ifdef can check more intelligently.  For now, it assumes any
+ * non-windows platform has pthreads.
+ */
+#ifndef _WIN32
+/* eric: This is used quite a few places but isn't valid on windows. */
+/* Define to 1 if you have the <pthread.h> header file. */
+#define CP_HAS_PTHREAD_H 1
+
+/* eric: used in mempool.c.  Not valid on windows. */
+/* Define to 1 if you have the `getpagesize' function. */
+#define CP_HAS_GETPAGESIZE 1
+#endif
+
+/* eric: This is used in mempool.c, but I don't know how important it is... */
+/* Define to 1 if PTHREAD_MUTEX_RECURSIVE works */
+#define CP_HAS_PTHREAD_MUTEX_RECURSIVE 1
+
+
+/* eric: used in thread.c */
+/* Define to 1 if you have the `random' function. */
+#define CP_HAS_RANDOM 1
+
+/* eric: used in thread.c */
+/* Define to 1 if you have the `srandom' function. */
+#define CP_HAS_SRANDOM 1
+
+/* eric: what system doesn't have this??? */
+/* Define to 1 if you have the `read' function. */
+#define CP_HAS_READ 1
+
+/* eric: what system doesn't have this??? */
+/* Define to 1 if you have the `write' function. */
+#define CP_HAS_WRITE 1
+
+
+
+#endif /* _CP_CONFIG_H */

Added: branches/multicore/numpy/core/cprops_thread/hashlist.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/hashlist.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/hashlist.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,1330 @@
+
+/**
+ * @addtogroup cp_hashlist
+ */
+/** @{ */
+/**
+ * @file
+ * Implementation for cp_hashlist Collection with linked elements and hash key
+ * and with cp_hashlist_iterator.
+ * 
+ * @copydoc collection
+ */
+/* ----------------------------------------------------------------- */
+
+#include <stdio.h> /* debug */
+#include <stdlib.h>
+#include <errno.h>
+
+#include "collection.h"
+//#include "log.h"
+#include "common.h"
+
+#include "hashlist.h"
+#include "linked_list.h"
+
+#include "cp_config.h"
+
+/* debug */
+#ifndef CP_HASHLIST_MULTIPLE_VALUES
+#define CP_HASHLIST_MULTIPLE_VALUES 1
+#endif
+
+
+	/* internal methods */
+
+/* internal lock function */
+int cp_hashlist_txlock(cp_hashlist *list, int type);
+/* internal unlock function */
+int cp_hashlist_txunlock(cp_hashlist *list);
+
+static cp_hashlist_entry *
+	cp_hashlist_create_entry(cp_hashlist *list, int mode, 
+							 void *key, void *value);
+
+static void 
+	cp_hashlist_entry_delete(cp_hashlist_entry *entry);
+
+static void cp_hashlist_entry_release_by_option(cp_hashlist *list, 
+												cp_hashlist_entry *entry, 
+												int mode);
+/**
+ * insert an entry
+ * 
+ * @param list the collection object
+ * @param entry the entry to insert
+ * @return entry the inserted entry
+ */
+static cp_hashlist_entry *
+	cp_hashlist_insert_internal(cp_hashlist *list, cp_hashlist_entry *entry);
+
+/**
+ * remove first entry matching key
+ * 
+ * @param list the collection object
+ * @param key that is searched for
+ * @retval entry if successful the removed entry
+ * @retval NULL  if the entry was not found
+ */
+static cp_hashlist_entry *
+	cp_hashlist_remove_internal(cp_hashlist *list, void *key);
+
+/**
+ * remove specified entry
+ * 
+ * @param list the collection object
+ * @param entry the entry to remove
+ * @retval entry if successful the passed entry
+ * @retval NULL  if the entry was not found
+ */
+static cp_hashlist_entry *
+	cp_hashlist_remove_entry_internal(cp_hashlist *list, 
+									  cp_hashlist_entry *entry);
+
+static void *cp_hashlist_get_internal(cp_hashlist *list, void *key);
+
+	/* end internal methods */
+
+
+cp_hashlist *
+	cp_hashlist_create_by_option(int mode, 
+								 unsigned long size_hint, 
+		               		   	 cp_hashfunction hash_fn, 
+                               	 cp_compare_fn compare_fn,
+                               	 cp_copy_fn copy_key,
+								 cp_destructor_fn free_key,
+                               	 cp_copy_fn copy_value,
+								 cp_destructor_fn free_value)
+{
+    cp_hashlist *list = (cp_hashlist *) calloc(1, sizeof(cp_hashlist));
+    if (list == NULL) 
+	{
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    list->table_size = cp_hashtable_choose_size(size_hint);
+    list->items = 0;
+    list->table = (cp_hashlist_entry **) calloc(list->table_size, sizeof(cp_hashlist_entry *));
+    if (list->table == NULL) 
+	{
+		errno = ENOMEM;
+        return NULL;
+    }
+
+    list->hash_fn = hash_fn;
+    list->compare_fn = compare_fn;
+    list->copy_key = NULL;
+    list->copy_value = NULL;
+
+    list->head = list->tail = NULL;
+	list->lock = malloc(sizeof(cp_lock));
+	if (list->lock == NULL)
+	{
+		free(list->table);
+		free(list);
+		errno = ENOMEM;
+		return NULL;
+	}
+    if (!(mode & COLLECTION_MODE_NOSYNC)) 
+		if (cp_lock_init(list->lock, NULL))
+		{
+			free(list->lock);
+			free(list->table);
+			free(list);
+			return NULL;
+		}
+
+    list->mode = mode;
+
+    list->copy_key = copy_key;
+    list->copy_value = copy_value;
+	list->free_key = free_key;
+	list->free_value = free_value;
+
+	list->min_size = size_hint;
+	list->fill_factor_min = CP_HASHTABLE_DEFAULT_MIN_FILL_FACTOR;
+	list->fill_factor_max = CP_HASHTABLE_DEFAULT_MAX_FILL_FACTOR;
+
+    return list;
+}
+
+
+cp_hashlist *cp_hashlist_create_by_mode(int mode, 
+										unsigned long size_hint, 
+										cp_hashfunction hash_fn, 
+										cp_compare_fn compare_fn)
+{
+	return 
+		cp_hashlist_create_by_option(mode, size_hint, hash_fn, compare_fn,
+									 NULL, NULL, NULL, NULL);
+}
+
+static cp_hashlist_entry *
+	cp_hashlist_create_entry(cp_hashlist *list, int mode,
+						     void *key, void *value)
+{
+	cp_copy_fn ck = list->copy_key;
+	cp_copy_fn cv = list->copy_value;
+    cp_hashlist_entry *entry = 
+		(cp_hashlist_entry *) calloc(1, sizeof(cp_hashlist_entry));
+	
+	if (entry == NULL) 
+	{
+		errno = ENOMEM;
+		return NULL;
+	}
+
+    entry->next = entry->prev = entry->bucket = NULL;
+    if (mode & COLLECTION_MODE_COPY) 
+	{
+        entry->key = ck ? (*ck)(key) : key;
+        entry->value = cv ? (*cv)(value) : value;
+    } 
+	else 
+	{
+        entry->key = key;
+        entry->value = value;
+    }
+
+    return entry;
+}
+
+
+static void 
+	cp_hashlist_destroy_internal(cp_hashlist *list, 
+							  	 int mode, 
+								 cp_destructor_fn dk,
+								 cp_destructor_fn dv)
+{
+	int syncbit = list->mode & COLLECTION_MODE_NOSYNC;
+
+    if (!syncbit) cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE);
+	while (list->head != NULL)
+	{
+        cp_hashlist_entry *entry = list->head;
+		list->head = entry->next;
+		if (mode & COLLECTION_MODE_DEEP)
+		{
+			if (dk) (*dk)(entry->key);
+			if (dv) (*dv)(entry->value);
+		}
+		cp_hashlist_entry_delete(entry);
+	}
+
+    if (!syncbit) cp_hashlist_txunlock(list);
+	if (list->lock)
+	{
+        cp_lock_destroy(list->lock);
+		free(list->lock);
+    }
+
+    free(list->table);
+    free(list);
+}
+
+void cp_hashlist_destroy(cp_hashlist *list)
+{
+   	cp_hashlist_destroy_internal(list, list->mode, 
+								 list->free_key, list->free_value);
+}
+
+void cp_hashlist_destroy_deep(cp_hashlist *list)
+{
+    cp_hashlist_set_mode(list, COLLECTION_MODE_DEEP);
+    cp_hashlist_destroy_custom(list, list->free_key, list->free_value);
+}
+
+void cp_hashlist_destroy_by_option(cp_hashlist *list, int mode)
+{
+	
+	if (list) 
+		cp_hashlist_destroy_internal(list, mode, 
+									 list->free_key, list->free_value);
+}
+
+void cp_hashlist_destroy_custom(cp_hashlist *list, 
+									   cp_destructor_fn dk, 
+									   cp_destructor_fn dv)
+{
+	if (list)
+		cp_hashlist_destroy_internal(list, list->mode, dk, dv);
+}
+
+int cp_hashlist_callback(cp_hashlist *list, 
+						 int (*cb)(void *key, void *value, void *id),
+						 void *id)
+{
+    cp_hashlist_entry *entry;
+
+	if (list == NULL || cb == NULL) 
+	{
+		errno = EINVAL;
+		return -1;
+	}
+
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_READ)) return -1;
+
+	entry = list->head;
+    while (entry != NULL) 
+	{
+		if ((*cb)(entry->key, entry->value, id) != 0)
+			break;
+        entry = entry->next;
+    }
+
+    cp_hashlist_txunlock(list);
+	return 0;
+}
+
+int cp_hashlist_get_mode(cp_hashlist *list)
+{
+	return list->mode;
+}
+
+int cp_hashlist_set_mode(cp_hashlist *list, int mode)
+{
+	int rc = EINVAL;
+	if (list)
+	{
+		int syncbit = list->mode & COLLECTION_MODE_NOSYNC;
+
+		/* can't set NOSYNC in the middle of a transaction */
+		if ((list->mode & COLLECTION_MODE_IN_TRANSACTION) && 
+			(mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
+
+		syncbit = list->mode & COLLECTION_MODE_NOSYNC;
+
+		if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return -1;
+		list->mode |= mode;
+		if (!syncbit) cp_hashlist_txunlock(list);
+
+		rc = 0;
+	}
+
+	return 0;
+}
+
+int cp_hashlist_unset_mode(cp_hashlist *list, int mode)
+{
+	int syncbit;
+	if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return -1;
+	syncbit = list->mode & COLLECTION_MODE_NOSYNC;
+    list->mode &= list->mode ^ mode;
+   	if (!syncbit) cp_hashlist_txunlock(list);
+
+	return 0;
+}
+
+int cp_hashlist_set_min_size(cp_hashlist *list, unsigned long min_size)
+{
+	if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return -1;
+	list->min_size = min_size;
+	cp_hashlist_txunlock(list);
+	return 0;
+}
+
+
+int cp_hashlist_set_max_fill_factor(cp_hashlist *list, int fill_factor)
+{
+	if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return -1;
+	list->fill_factor_max = fill_factor;
+	cp_hashlist_txunlock(list);
+	return 0;
+}
+
+int cp_hashlist_set_min_fill_factor(cp_hashlist *list, int fill_factor)
+{
+	if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return -1;
+	list->fill_factor_min = fill_factor;
+	cp_hashlist_txunlock(list);
+	return 0;
+}
+
+void *cp_hashlist_resize_nosync(cp_hashlist *list, unsigned long new_size)
+{
+    unsigned long old_size;
+    cp_hashlist_entry **old_table;
+    cp_hashlist_entry *entry, *next, **insert;
+    unsigned long i, index;
+
+    old_size = list->table_size;
+    old_table = list->table;
+    
+	new_size = cp_hashtable_choose_size(new_size);
+	if (old_size == new_size) /* not enough gap to make a change yet */
+		return list;
+	else
+    	list->table_size = new_size;
+#ifdef __TRACE__
+    DEBUGMSG("resizing table (nosync): %d to %d\n", old_size, list->table_size);
+#endif
+
+    list->table = (cp_hashlist_entry **) calloc(list->table_size, sizeof(cp_hashlist_entry *));
+
+    if (list->table == NULL) 
+	{
+		errno = ENOMEM;
+        return NULL;
+    }
+
+    for (i = 0; i < old_size; i++) 
+	{
+        entry = old_table[i];
+        while (entry != NULL) 
+		{
+            index = abs((*list->hash_fn)(entry->key)) % list->table_size;
+            next = entry->bucket;
+            entry->bucket = NULL;
+            insert = &list->table[index];
+            while (*insert != NULL) insert = &(*insert)->bucket;
+            *insert = entry;
+            
+            entry = next;
+        }
+    }
+
+    free(old_table);
+
+    return list;
+}
+
+void *cp_hashlist_append(cp_hashlist *list, void *key, void *value)
+{
+    return cp_hashlist_append_by_option(list, key, value, list->mode);
+}
+
+static int cp_hashlist_contains_internal(cp_hashlist *list, void *key)
+{
+	int rc = 0;
+	cp_hashlist_entry *curr;
+	int index = abs((*list->hash_fn)(key)) % list->table_size;
+    
+	curr = list->table[index];
+
+    while (curr != NULL) 
+	{
+		if ((*list->compare_fn)(key, curr->key) == 0)
+		{
+			rc = 1;
+			break;
+		}
+		curr = curr->bucket;
+	}
+
+	return rc;
+}
+
+int cp_hashlist_contains(cp_hashlist *list, void *key)
+{
+	int rc = 0;
+
+	if (cp_hashlist_txlock(list, COLLECTION_LOCK_READ)) return -1;
+	rc = cp_hashlist_contains_internal(list, key);
+	cp_hashlist_txunlock(list);
+
+	return rc;
+}
+
+void *cp_hashlist_append_by_option(cp_hashlist *list, 
+								   void *key, 
+								   void *value, 
+								   int mode)
+{
+    cp_hashlist_entry *entry;
+    void *res = NULL;
+	int rc = 0;
+
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+	if ((mode & COLLECTION_MODE_MULTIPLE_VALUES) == 0
+		&& cp_hashlist_contains_internal(list, key)) 
+	{
+		rc = EINVAL;
+		goto DONE;
+	}
+
+    if ((entry = cp_hashlist_create_entry(list, mode, key, value)) == NULL)
+	{
+		rc = ENOMEM;
+		goto DONE;
+	}
+
+    cp_hashlist_insert_internal(list, entry);
+
+    if (list->tail) 
+	{
+        entry->prev = list->tail;
+        list->tail->next = entry;
+        list->tail = entry;
+    }
+    else list->tail = list->head = entry;
+
+    res = value;
+
+DONE:
+    cp_hashlist_txunlock(list);
+	if (rc) errno = rc;
+
+    return res;
+}
+
+
+void *cp_hashlist_insert(cp_hashlist *list, void *key, void *value)
+{
+    return cp_hashlist_insert_by_option(list, key, value, list->mode);
+}
+
+
+void *cp_hashlist_insert_by_option(cp_hashlist *list, void *key, 
+								   void *value, int mode)
+{
+    cp_hashlist_entry *entry;
+    void *res = NULL;
+	int rc = 0;
+
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+	if ((mode & COLLECTION_MODE_MULTIPLE_VALUES) == 0
+		&& cp_hashlist_contains_internal(list, key)) 
+	{
+		rc = EINVAL;
+		goto DONE;
+	}
+
+    if ((entry = cp_hashlist_create_entry(list, mode, key, value)) == NULL)
+	{
+		rc = errno;
+		goto DONE;
+	}
+
+    cp_hashlist_insert_internal(list, entry);
+    if (list->head) 
+	{
+        entry->next = list->head;
+        list->head->prev = entry;
+        list->head = entry;
+    }
+    else list->head = list->tail = entry;
+
+    res = value;
+
+DONE:
+    cp_hashlist_txunlock(list);
+	if (rc) errno = rc;
+
+    return res;
+}
+    
+
+void *cp_hashlist_get(cp_hashlist *list, void *key)
+{
+    void *res = NULL;
+
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_READ)) return NULL;
+
+    res = cp_hashlist_get_internal(list, key);
+
+#if CP_HASHLIST_MULTIPLE_VALUES
+	if (!(list->mode & COLLECTION_MODE_MULTIPLE_VALUES))
+#endif
+    if (res) res = ((cp_hashlist_entry *) res)->value;
+
+    cp_hashlist_txunlock(list);
+
+    return res;
+}
+
+static void *cp_hashlist_unlink_internal(cp_hashlist *list, 
+										 cp_hashlist_entry *holder,
+										 int mode)
+{
+	void *res = NULL;
+
+    if (holder) 
+	{    
+        if (holder->next) 
+			holder->next->prev = holder->prev;
+        else              
+			list->tail = holder->prev;
+		
+        if (holder->prev) 
+			holder->prev->next = holder->next;
+        else              
+			list->head = holder->next;
+		
+        res = holder->value;
+        cp_hashlist_entry_release_by_option(list, holder, mode);
+    }
+	
+	return res;
+}
+
+void *cp_hashlist_remove_by_option(cp_hashlist *list, void *key, int mode)
+{
+    void *res;
+    cp_hashlist_entry *holder;
+
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    holder = cp_hashlist_remove_internal(list, key);
+	res = cp_hashlist_unlink_internal(list, holder, mode);
+
+    cp_hashlist_txunlock(list);
+
+    return res;
+}
+
+void *cp_hashlist_remove(cp_hashlist *list, void *key)
+{
+	return cp_hashlist_remove_by_option(list, key, list->mode);
+}
+
+void *cp_hashlist_remove_deep(cp_hashlist *list, void *key)
+{
+	return 
+		cp_hashlist_remove_by_option(list, key, 
+									 list->mode | COLLECTION_MODE_DEEP);
+}
+
+void *cp_hashlist_get_head(cp_hashlist *list)
+{
+    void *res;
+
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    res = list->head ? list->head->value : NULL;
+    
+    cp_hashlist_txunlock(list);
+    return res;
+}
+
+void *cp_hashlist_get_tail(cp_hashlist *list)
+{
+    void *res;
+	
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    res = list->tail ? list->tail->value : NULL;
+    
+    cp_hashlist_txunlock(list);
+    return res;
+}
+
+
+void *cp_hashlist_remove_head(cp_hashlist *list)
+{
+    return cp_hashlist_remove_head_by_option(list, list->mode);
+}
+
+void *cp_hashlist_remove_head_by_option(cp_hashlist *list, int mode)
+{
+    cp_hashlist_entry *entry;
+    void *res = NULL;
+
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    entry = list->head;
+    if (entry) 
+	{
+        if (!cp_hashlist_remove_entry_internal(list, entry))  /* should _not_ happen */
+            printf("failed to remove item from cp_hashlist table: %s\n", (char *) entry->value);
+
+        list->head = list->head->next;
+        if (list->head) 
+			list->head->prev = NULL;
+        else
+			list->tail = NULL;
+
+        res = entry->value;
+
+        cp_hashlist_entry_release_by_option(list, entry, mode);
+    }
+
+    cp_hashlist_txunlock(list);
+    return res;
+}
+
+void *cp_hashlist_remove_tail(cp_hashlist *list)
+{
+    return cp_hashlist_remove_tail_by_option(list, list->mode);
+}
+
+void *cp_hashlist_remove_tail_by_option(cp_hashlist *list, int mode)
+{
+    cp_hashlist_entry *entry;
+    void *res = NULL;
+
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    entry = list->tail;
+    if (entry) 
+	{
+        if (!cp_hashlist_remove_entry_internal(list, entry)) /* should _not_ happen */
+            printf("failed to remove item from cp_hashlist table: %s\n", (char *) entry->value);
+
+        list->tail = entry->prev;
+        if (list->tail) 
+			list->tail->next = NULL;
+        else
+			list->head = NULL;
+
+        res = entry->value;
+        cp_hashlist_entry_release_by_option(list, entry, mode);
+    }
+
+    cp_hashlist_txunlock(list);
+    return res;
+}
+
+unsigned long cp_hashlist_item_count(cp_hashlist *list)
+{
+    unsigned long count;
+    if (cp_hashlist_txlock(list, COLLECTION_LOCK_READ)) return -1;
+
+    count = list->items;
+
+    cp_hashlist_txunlock(list);
+    return count;
+}
+
+    
+int cp_hashlist_lock_internal(cp_hashlist *list, int lock_mode)
+{
+    int rc = -1;
+
+    switch (lock_mode) 
+	{
+        case COLLECTION_LOCK_READ:
+            rc = cp_lock_rdlock(list->lock);
+            break;
+
+        case COLLECTION_LOCK_WRITE:
+            rc = cp_lock_wrlock(list->lock);
+            break;
+
+		case COLLECTION_LOCK_NONE:
+			rc = 0;
+			break;
+
+        default:
+			errno = EINVAL;
+            break;
+    }
+
+    return rc;
+}
+
+int cp_hashlist_unlock_internal(cp_hashlist *list)
+{
+    return cp_lock_unlock(list->lock);
+}
+
+int cp_hashlist_txlock(cp_hashlist *list, int type)
+{
+	if (list->mode & COLLECTION_MODE_NOSYNC) return 0;
+	if (list->mode & COLLECTION_MODE_IN_TRANSACTION && 
+		list->txtype == COLLECTION_LOCK_WRITE)
+	{
+		cp_thread self = cp_thread_self();
+		if (cp_thread_equal(self, list->txowner)) return 0;
+	}
+	return cp_hashlist_lock_internal(list, type);
+}
+
+int cp_hashlist_txunlock(cp_hashlist *list)
+{
+	if (list->mode & COLLECTION_MODE_NOSYNC) return 0;
+	if (list->mode & COLLECTION_MODE_IN_TRANSACTION && 
+		list->txtype == COLLECTION_LOCK_WRITE)
+	{
+		cp_thread self = cp_thread_self();
+		if (cp_thread_equal(self, list->txowner)) return 0;
+	}
+	return cp_hashlist_unlock_internal(list);
+}
+
+/* lock and set the transaction indicators */
+int cp_hashlist_lock(cp_hashlist *list, int type)
+{
+	int rc;
+	if ((list->mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
+	if ((rc = cp_hashlist_lock_internal(list, type))) return rc;
+	list->txtype = type;
+	list->txowner = cp_thread_self();
+	list->mode |= COLLECTION_MODE_IN_TRANSACTION;
+	return 0;
+}
+
+/* unset the transaction indicators and unlock */
+int cp_hashlist_unlock(cp_hashlist *list)
+{
+	cp_thread self = cp_thread_self();
+	if (list->txowner == self)
+	{
+		list->txtype = 0;
+		list->txowner = 0;
+		list->mode ^= COLLECTION_MODE_IN_TRANSACTION;
+	}
+	else if (list->txtype == COLLECTION_LOCK_WRITE)
+		return -1;
+	return cp_hashlist_unlock_internal(list);
+}
+
+
+void *cp_hashlist_entry_get_key(cp_hashlist_entry *entry)
+{
+    return (entry) ? entry->key : NULL;
+}
+
+void *cp_hashlist_entry_get_value(cp_hashlist_entry *entry)
+{
+    return (entry) ? entry->value : NULL;
+}
+
+int cp_hashlist_is_empty(cp_hashlist *list)
+{
+    return cp_hashlist_item_count(list) == 0;
+}
+
+
+/****************************************************************************
+ *                                                                          *
+ *                    cp_hashlist_iterator implementation                   *
+ *                                                                          *
+ ****************************************************************************/
+ 
+cp_hashlist_iterator* cp_hashlist_create_iterator(cp_hashlist *list, int type)
+{
+    int rc = - 1;
+    cp_hashlist_iterator *iterator = 
+		(cp_hashlist_iterator *) malloc(sizeof(cp_hashlist_iterator));
+	if (iterator == NULL) return NULL;
+
+    iterator->list = list;
+    iterator->pos = &list->head;
+    iterator->lock_type = type;
+
+    switch (type)
+    {
+        case COLLECTION_LOCK_READ : 
+            rc = cp_hashlist_txlock(list, COLLECTION_LOCK_READ);
+            break;
+
+        case COLLECTION_LOCK_WRITE :
+            rc = cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE);
+            break;
+    
+        default :
+            rc = 0;
+    }
+
+	if (rc) /* locking failed */
+	{
+		free(iterator);
+		iterator = NULL;
+	}
+
+    return iterator;
+}
+
+int cp_hashlist_iterator_init(cp_hashlist_iterator *iterator, 
+							  cp_hashlist *list, int type)
+{
+    int rc;
+    iterator->list = list;
+    iterator->pos = &list->head;
+    iterator->lock_type = type;
+
+    switch (type)
+    {
+        case COLLECTION_LOCK_READ : 
+            rc = cp_hashlist_txlock(list, COLLECTION_LOCK_READ);
+            break;
+
+        case COLLECTION_LOCK_WRITE :
+            rc = cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE);
+            break;
+    
+        default :
+            rc = 0;
+    }
+
+    return rc;
+}
+
+
+int cp_hashlist_iterator_head(cp_hashlist_iterator *iterator)
+{
+    if (iterator == NULL) return -1;
+    iterator->pos = &iterator->list->head;
+
+    return 0;
+}
+
+int cp_hashlist_iterator_tail(cp_hashlist_iterator *iterator)
+{
+    if (iterator == NULL) return -1;
+    iterator->pos = &iterator->list->tail;
+
+    return 0;
+}
+
+int cp_hashlist_iterator_init_tail(cp_hashlist_iterator *iterator, cp_hashlist *list, int type)
+{
+    int rc;
+    iterator->list = list;
+    iterator->pos = &list->tail;
+    iterator->lock_type = type;
+
+    switch (type)
+    {
+        case COLLECTION_LOCK_READ : 
+            rc = cp_hashlist_txlock(list, COLLECTION_LOCK_READ);
+            break;
+
+        case COLLECTION_LOCK_WRITE :
+            rc = cp_hashlist_txlock(list, COLLECTION_LOCK_WRITE);
+            break;
+    
+        default :
+            rc = 0;
+    }
+
+    return rc;
+}
+
+int cp_hashlist_iterator_to_key(cp_hashlist_iterator *iterator, void *key)
+{
+	cp_hashlist_entry *entry = NULL;
+	
+#if CP_HASHLIST_MULTIPLE_VALUES
+	if ((iterator->list->mode & COLLECTION_MODE_MULTIPLE_VALUES))
+	{
+		cp_list *res = cp_hashlist_get_internal(iterator->list, key);
+		if (res)
+		{
+			entry = cp_list_get_head(res);
+			cp_list_destroy(res);
+		}
+	}
+	else
+#endif
+	entry = cp_hashlist_get_internal(iterator->list, key);
+
+	if (entry == NULL) return -1;
+
+	if (entry->prev) 
+		iterator->pos = &entry->prev->next;
+	else 
+		iterator->pos = &iterator->list->head;
+
+	return 0;
+}
+
+
+int cp_hashlist_iterator_release(cp_hashlist_iterator *iterator)
+{
+	int rc = 0;
+    if (iterator->lock_type != COLLECTION_LOCK_NONE) 
+		rc = cp_hashlist_txunlock(iterator->list);
+
+    return rc;
+}
+
+int cp_hashlist_iterator_destroy(cp_hashlist_iterator *iterator)
+{
+    int rc = cp_hashlist_iterator_release(iterator);
+    free(iterator);
+
+    return rc;
+}
+
+cp_hashlist_entry *cp_hashlist_iterator_next(cp_hashlist_iterator *iterator)
+{
+    cp_hashlist_entry *entry = NULL;
+
+    if (*(iterator->pos)) 
+	{
+        entry = (*iterator->pos);
+        iterator->pos = &(*(iterator->pos))->next;
+    }
+	else if (iterator->list->head && 
+			 iterator->pos == &iterator->list->head->prev)
+	{
+		entry = iterator->list->head;
+		iterator->pos = &iterator->list->head;
+	}
+
+    return entry;
+}
+
+void *cp_hashlist_iterator_next_key(cp_hashlist_iterator *iterator)
+{
+    return cp_hashlist_entry_get_key(cp_hashlist_iterator_next(iterator));
+}
+
+void *cp_hashlist_iterator_next_value(cp_hashlist_iterator *iterator)
+{
+    return cp_hashlist_entry_get_value(cp_hashlist_iterator_next(iterator));
+}
+
+cp_hashlist_entry *cp_hashlist_iterator_prev(cp_hashlist_iterator *iterator)
+{
+    cp_hashlist_entry  *entry = NULL;
+
+    if (*iterator->pos) 
+	{
+        entry = (*iterator->pos);
+        iterator->pos = &(*iterator->pos)->prev;
+    }
+	else if (iterator->list->tail && 
+			 iterator->pos == &iterator->list->tail->next)
+	{
+		entry = iterator->list->tail;
+		iterator->pos = &iterator->list->tail;
+	}
+
+    return entry;
+}
+
+void *cp_hashlist_iterator_prev_key(cp_hashlist_iterator *iterator)
+{
+    return cp_hashlist_entry_get_key(cp_hashlist_iterator_prev(iterator));
+}
+
+void *cp_hashlist_iterator_prev_value(cp_hashlist_iterator *iterator)
+{
+    return cp_hashlist_entry_get_value(cp_hashlist_iterator_prev(iterator));
+}
+
+cp_hashlist_entry *cp_hashlist_iterator_curr(cp_hashlist_iterator *iterator)
+{
+    cp_hashlist_entry *item = NULL;
+
+    if (*iterator->pos)
+        item = (*iterator->pos);
+
+    return item;
+}
+
+void *cp_hashlist_iterator_curr_key(cp_hashlist_iterator *iterator)
+{
+    return cp_hashlist_entry_get_key(cp_hashlist_iterator_curr(iterator));
+}
+
+void *cp_hashlist_iterator_curr_value(cp_hashlist_iterator *iterator)
+{
+    return cp_hashlist_entry_get_value(cp_hashlist_iterator_curr(iterator));
+}
+
+cp_hashlist_entry *cp_hashlist_iterator_insert(cp_hashlist_iterator *iterator, 
+								  			   void *key, 
+								  			   void *value)
+{
+	cp_hashlist_entry *new_entry = NULL;
+
+	if ((iterator->list->mode & COLLECTION_MODE_NOSYNC) || 
+		(iterator->lock_type == COLLECTION_LOCK_WRITE))
+	{
+		cp_hashlist_entry *entry; 
+		if ((iterator->list->mode & COLLECTION_MODE_MULTIPLE_VALUES) == 0
+			&& cp_hashlist_contains_internal(iterator->list, key)) 
+		{
+			errno = EINVAL;
+			return NULL;
+		}
+		
+		entry = cp_hashlist_create_entry(iterator->list, 
+									 	 iterator->list->mode, 
+									 	 key, 
+									 	 value);
+		if (entry == NULL) return NULL;
+		cp_hashlist_insert_internal(iterator->list, entry);
+		new_entry = entry;
+		
+		entry->next = *iterator->pos;
+
+		if (*iterator->pos)
+		{
+			entry->prev = (*iterator->pos)->prev;
+			(*iterator->pos)->prev = entry;
+			if (entry->prev)
+				entry->prev->next = entry;
+		}
+		else if (iterator->list->head == NULL) /* iterator not pointing at much - list may be empty */
+			iterator->list->head = iterator->list->tail = entry;
+		else if (iterator->pos == &iterator->list->head->prev) /* iterator moved before head */
+		{
+			entry->prev = NULL;
+			entry->next = iterator->list->head;
+			entry->next->prev = entry;
+			iterator->list->head = entry;
+		}
+		else /* iterator moved after tail */
+		{
+			entry->prev = iterator->list->tail;
+			entry->prev->next = entry;
+			iterator->list->tail = entry;
+		}
+
+		iterator->pos = &entry->next; /* keep iterator on same entry */
+		
+		iterator->list->items++;
+	}
+	else /* mode is not NOSYNC and no LOCK_WRITE */
+		errno = EINVAL;
+
+	return new_entry;
+}
+
+cp_hashlist_entry *cp_hashlist_iterator_append(cp_hashlist_iterator *iterator, 
+											   void *key,
+											   void *value)
+{
+	cp_hashlist_entry *new_entry = NULL;
+
+	if ((iterator->list->mode & COLLECTION_MODE_NOSYNC) || 
+		(iterator->lock_type == COLLECTION_LOCK_WRITE))
+	{
+		cp_hashlist_entry *entry;
+
+		if ((iterator->list->mode & COLLECTION_MODE_MULTIPLE_VALUES) == 0
+			&& cp_hashlist_contains_internal(iterator->list, key)) 
+		{
+			errno = EINVAL;
+			return NULL;
+		}
+
+		entry = cp_hashlist_create_entry(iterator->list, 
+									 	 iterator->list->mode,
+									 	 key, 
+									 	 value);
+		if (entry == NULL) return NULL;
+		cp_hashlist_insert_internal(iterator->list, entry);
+		new_entry = entry;
+		
+		entry->prev = *iterator->pos;
+
+		if (*iterator->pos)
+		{
+			entry->next = (*iterator->pos)->next;
+			(*iterator->pos)->next = entry;
+			if (entry->next)
+				entry->next->prev = entry;
+		}
+		else if (iterator->list->tail == NULL) /* iterator not pointing at much - list may be empty */
+			iterator->list->tail = iterator->list->head = entry;
+		else if (iterator->pos == &iterator->list->tail->next) /* iterator moved after tail */
+		{
+			entry->next = NULL;
+			entry->prev = iterator->list->tail;
+			entry->prev->next = entry;
+			iterator->list->tail = entry;
+		}
+		else /* iterator moved before head */
+		{
+			entry->next = iterator->list->head;
+			entry->next->prev = entry;
+			iterator->list->head = entry;
+		}
+
+		iterator->pos = &entry->prev; /* keep iterator on same entry */
+		iterator->list->items++;
+	}
+	else /* mode is not NOSYNC and no LOCK_WRITE */
+		errno = EINVAL;
+
+	return new_entry;
+}
+
+void *cp_hashlist_iterator_remove(cp_hashlist_iterator *iterator)
+{
+	void *rm_value = NULL;
+
+	if ((iterator->list->mode & COLLECTION_MODE_NOSYNC) || 
+		(iterator->lock_type == COLLECTION_LOCK_WRITE))
+	{
+		if (*iterator->pos)
+		{
+			cp_hashlist_entry *curr = *iterator->pos;
+
+			if (curr->next)
+				iterator->pos = &curr->next->prev;
+			else if (curr->prev)
+				iterator->pos = &curr->prev->next;
+			else /* removing last item */
+				iterator->pos = &iterator->list->head;			
+
+			curr = cp_hashlist_remove_internal(iterator->list, curr->key);
+			rm_value = 
+				cp_hashlist_unlink_internal(iterator->list, 
+											curr, iterator->list->mode);
+		}
+	}
+
+	return rm_value;
+}
+
+/* ----------------------------------------------------------------- */
+/** @} */
+
+
+/* ----------------------------------------------------------------- */
+/* Internal methods */
+/* ----------------------------------------------------------------- */
+
+static cp_hashlist_entry *
+	cp_hashlist_insert_internal(cp_hashlist *list, 
+                                cp_hashlist_entry *entry)
+{
+    cp_hashlist_entry **insert;
+    unsigned long index;
+
+    if (!(list->mode & COLLECTION_MODE_NORESIZE) && 
+		list->items * 100 > list->table_size * list->fill_factor_max)
+        cp_hashlist_resize_nosync(list, list->table_size * 2);
+
+    index = abs((*list->hash_fn)(entry->key)) % list->table_size;
+    insert = &list->table[index];
+
+    /* accept doubles */
+    while (*insert != NULL) 
+		insert = &(*insert)->bucket;
+
+    *insert = entry;
+    list->items++;
+
+    return entry;
+}
+
+
+static void *cp_hashlist_get_internal(cp_hashlist *list, void *key)
+{
+    unsigned long index;
+    cp_hashlist_entry *entry;
+
+    index = abs((*list->hash_fn)(key)) % list->table_size;
+    entry = list->table[index];
+    while (entry && (*list->compare_fn)(entry->key, key)) 
+		entry = entry->bucket;
+
+#if CP_HASHLIST_MULTIPLE_VALUES
+	if ((list->mode & COLLECTION_MODE_MULTIPLE_VALUES) && entry)
+	{
+		cp_list *res = 
+			cp_list_create_view(list->mode, 
+								NULL, 
+								list->copy_value,
+								list->free_value,
+								list->lock);
+		cp_list_insert(res, entry->value);
+
+		if (list->mode & COLLECTION_MODE_LIST_ORDER) /* list order */
+		{
+			cp_hashlist_entry *i;
+			for (i = entry->prev; i; i++)
+				if ((*list->compare_fn)(i->key, key) == 0)
+					cp_list_insert(res, i->value);
+
+			for (i = entry->next; i; i++)
+				if ((*list->compare_fn)(i->key, key) == 0)
+					cp_list_append(res, i->value);
+		}
+		else /* insertion order */
+		{
+			entry = entry->bucket;
+			while (entry)
+				if ((*list->compare_fn)(entry->key, key) == 0)
+					cp_list_append(res, entry->value);
+		}
+
+		return res;
+	}
+#endif
+			
+    return entry;
+}
+
+
+static cp_hashlist_entry *
+	cp_hashlist_remove_entry_internal(cp_hashlist *list, 
+                                      cp_hashlist_entry *entry)
+{
+    cp_hashlist_entry **remove;
+    unsigned long index;
+
+    index = abs((*list->hash_fn)(entry->key)) % list->table_size;
+    remove = &list->table[index];
+    while (*remove != NULL) 
+	{
+        if (*remove == entry) break;
+        remove = &(*remove)->bucket;
+    }
+
+    if (*remove) 
+	{
+        *remove = (*remove)->bucket;
+        list->items--;
+    } 
+	else /* should _not_ happen */
+	{
+        printf("may day, cannot find that entry: %s\n", (char *) entry->key);
+        return NULL;
+    }
+
+    return entry;
+}
+
+static cp_hashlist_entry *
+	cp_hashlist_remove_internal(cp_hashlist *list, void *key)
+{
+    cp_hashlist_entry **remove, *holder;
+    unsigned long index;
+
+    if (!(list->mode & COLLECTION_MODE_NORESIZE) && 
+		list->items * 100 < list->table_size * list->fill_factor_min &&
+		list->items > list->min_size)
+        cp_hashlist_resize_nosync(list, list->table_size / 2);
+
+    index = abs((*list->hash_fn)(key)) % list->table_size;
+    remove = &list->table[index];
+    while (*remove != NULL) 
+	{
+        if ((*list->compare_fn)((*remove)->key, key) == 0) break;
+        remove = &(*remove)->bucket;
+    }
+
+    holder = NULL;
+    if (*remove) 
+	{
+        holder = *remove;
+        *remove = (*remove)->bucket;
+        list->items--;
+    }
+
+    return holder;
+}
+
+
+static void cp_hashlist_entry_delete(cp_hashlist_entry *entry)
+{
+    if (entry) free(entry);
+}
+
+static void 
+	cp_hashlist_entry_release_by_option(cp_hashlist *list, 
+										cp_hashlist_entry *entry, 
+										int mode)
+{
+    if (entry) 
+	{
+        if (mode & COLLECTION_MODE_DEEP) 
+		{
+            if (list->free_key) (*list->free_key)(entry->key);
+            if (list->free_value) (*list->free_value)(entry->value);
+        }
+        free(entry);
+    }
+}
+


Property changes on: branches/multicore/numpy/core/cprops_thread/hashlist.c
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/multicore/numpy/core/cprops_thread/hashlist.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/hashlist.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/hashlist.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,572 @@
+#ifndef _CP_HASHLIST_H
+#define _CP_HASHLIST_H
+
+/** @{ */
+/**
+ * @file
+ *
+ * a mapping traversable by iterator - who could want more. access elements 
+ * sequentially or by key. 
+ */
+/* ----------------------------------------------------------------- */
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+#include "cp_config.h"
+
+#include "collection.h"
+#include "hashtable.h"
+
+/*************/
+
+typedef CPROPS_DLL struct _cp_hashlist_entry
+{
+    void *key;                         /**< key of stored element */
+    void *value;                       /**< stored element (content) */
+    struct _cp_hashlist_entry *next;      /**< next entry */
+    struct _cp_hashlist_entry *prev;      /**< previous entry */
+    struct _cp_hashlist_entry *bucket;    /**< next record in bucket */
+} cp_hashlist_entry;
+
+
+/**
+ * Main object that holds the endpoints of the hash-list and the hash-table.
+ * 
+ * It also stores the hash, compare and copy methods and the default
+ * operation mode.
+ */
+typedef CPROPS_DLL struct _cp_hashlist
+{
+    cp_hashlist_entry **table;    /**< table of entries in the hash-table */
+    cp_hashlist_entry *head;      /**< first item in the list */
+    cp_hashlist_entry *tail;      /**< last item in the list */
+    unsigned long table_size;     /**< size of the hash-table */
+    unsigned long items;          /**< number of items in the collection */
+
+    cp_hashfunction  hash_fn;     /**< pointer to hash function */
+    cp_compare_fn    compare_fn;  /**< pointer to compare function */
+    cp_copy_fn       copy_key; 	  /**< pointer to key copy function */
+    cp_copy_fn       copy_value;  /**< pointer to value copy function */
+	cp_destructor_fn free_key;
+	cp_destructor_fn free_value;
+
+    int mode;                     /**< operation mode (see collection.h) */
+    cp_lock *lock;				  /**< lock */
+	cp_thread txowner;			  /**< lock owner */
+	int txtype;                   /**< lock type */
+
+	unsigned long min_size;
+	int fill_factor_min;		  /**< minimal fill factor in percent */
+	int fill_factor_max;		  /**< maximal fill factor in percent */
+} cp_hashlist;
+
+/**
+ * iterator for hashlists
+ */
+typedef CPROPS_DLL struct _cp_hashlist_iterator
+{
+    cp_hashlist *list;        /**< link to the list */
+    cp_hashlist_entry **pos;   /**< current position */
+
+    int lock_type;           /**< locking mode */
+} cp_hashlist_iterator;
+
+
+/*
+ * Removes the entry with matching key and destroys it. 
+ *
+ * @param list the object
+ * @param key  Key which is searched.
+ * @param mode locking mode
+ * @retval value that was stored in the entry.
+ * @retval NULL if key was not found
+ */
+CPROPS_DLL 
+void *cp_hashlist_remove_by_option(cp_hashlist *list, void *key, int mode);
+
+/**
+ * Removes the first entry and destroys it. 
+ *
+ * @param list the object
+ * @param mode locking mode
+ * @return Element that was stored in the first entry.
+ */
+CPROPS_DLL 
+void *cp_hashlist_remove_head_by_option(cp_hashlist *list, int mode);
+
+/**
+ * Removes the last entry and destroys it. 
+ *
+ * @param list the object
+ * @param mode locking mode
+ * @return Element that was stored in the first entry.
+ */
+CPROPS_DLL 
+void *cp_hashlist_remove_tail_by_option(cp_hashlist *list, int mode);
+
+/*************/
+
+/** default constructor */
+#define cp_hashlist_create(size_hint, hash_fn, compare_fn) \
+        cp_hashlist_create_by_option(0, (size_hint), \
+									 (hash_fn), (compare_fn), \
+									 NULL, NULL, NULL, NULL)
+
+/**
+ * constructor with parameters.
+ *
+ * @param operation mode bitmap (see collection.h)
+ * @param size_hint initial size of the cp_hashtable 
+ * @param hash_fn hash method  
+ * @param compare_fn  hash compare method  
+ */
+CPROPS_DLL 
+cp_hashlist *cp_hashlist_create_by_mode(int mode, 
+										unsigned long size_hint, 
+										cp_hashfunction hash_fn, 
+										cp_compare_fn compare_fn);
+
+/**
+ * Constructor for copy mode.
+ *
+ * @param mode Bitmap of operation mode (see collection.h)
+ * @param size_hint initial  size of the cp_hashtable 
+ * @param hash_fn  hash method  
+ * @param compare_fn   hash compare method  
+ * @param copy_key   copy key method  
+ * @param copy_value copy value method  
+ */
+CPROPS_DLL 
+cp_hashlist *
+	cp_hashlist_create_by_option(int mode, unsigned long size_hint, 
+		                   		 cp_hashfunction hash_fn, 
+								 cp_compare_fn compare_fn,
+								 cp_copy_fn copy_key, 
+								 cp_destructor_fn free_key,
+								 cp_copy_fn copy_value,
+								 cp_destructor_fn free_value);
+
+/**
+ * Destroy the list with the mode stored in the list.
+ */
+CPROPS_DLL 
+void cp_hashlist_destroy(cp_hashlist *);
+
+/**
+ * Destroy the list with the mode stored in the list plus COLLECTION_MODE_DEEP.
+ */
+CPROPS_DLL 
+void cp_hashlist_destroy_deep(cp_hashlist *);
+
+/**
+ * Destroy the object with the specified mode (override default).
+ *
+ * @param list the object
+ * @param mode locking mode
+ */
+CPROPS_DLL 
+void cp_hashlist_destroy_by_option(cp_hashlist *list, int mode);
+
+/**
+ * This function does exactly what you would think it does. Before it didn't - 
+ * that was a bug. Now it does.
+ */
+CPROPS_DLL 
+void cp_hashlist_destroy_custom(cp_hashlist *list, 
+								cp_destructor_fn dk, 
+								cp_destructor_fn dv);
+
+/**
+ * iterates over the list and calls the callback function on each item.
+ * 
+ * @param list the hashlist
+ * @param dk if not NULL, this function is invoked with the key for each entry
+ * @param dv if not NULL, this function is invoked with the value for each entry
+ */
+CPROPS_DLL 
+int cp_hashlist_callback(cp_hashlist *list, 
+						 int (*cb)(void *key, void *value, void *id),
+						 void *id);
+
+/**  find out what mode your cp_hashlist is running in */
+CPROPS_DLL 
+int cp_hashlist_get_mode(cp_hashlist *list);
+
+/** set the mode on your cp_hashlist */
+CPROPS_DLL 
+int cp_hashlist_set_mode(cp_hashlist *list, int mode);
+
+/** unset mode bits on list */
+CPROPS_DLL 
+int cp_hashlist_unset_mode(cp_hashlist *list, int mode);
+
+
+/**
+ * the internal table will not be resized to less than min_size
+ */
+CPROPS_DLL 
+int cp_hashlist_set_min_size(cp_hashlist *list, unsigned long min_size);
+
+/**
+ * a resize is triggered when the table contains more items than
+ * table_size * fill_factor / 100
+ */
+CPROPS_DLL 
+int cp_hashlist_set_max_fill_factor(cp_hashlist *list, int fill_factor);
+
+/**
+ * a resize is triggered when the table contains less items than
+ * table_size * fill_factor / 100 if table_size > min_size
+ */
+CPROPS_DLL 
+int cp_hashlist_set_min_fill_factor(cp_hashlist *list, int fill_factor);
+
+
+/* **************************************************************************
+ *                                                                          *
+ *                            iterator functions                            *
+ *                                                                          *
+ ************************************************************************** */
+
+/**
+ * Create a new iterator and initialize it at the beginning.
+ *
+ * @param list list to iterate over
+ * @param lock_mode locking mode to use
+ * @return new iterator object
+ */
+CPROPS_DLL 
+cp_hashlist_iterator *cp_hashlist_create_iterator(cp_hashlist *list, int lock_mode);
+
+/**
+ * initialize the iterator at the beginning
+ *
+ * set the iterator at the beginning of the list and lock the list in the
+ * mode specified in type.
+ */
+CPROPS_DLL 
+int cp_hashlist_iterator_head(cp_hashlist_iterator *iterator);
+//int cp_hashlist_iterator_head(cp_hashlist_iterator *iterator, cp_hashlist *l, int lock_mode);
+
+CPROPS_DLL 
+int cp_hashlist_iterator_init(cp_hashlist_iterator *iterator, 
+							  cp_hashlist *list, int type);
+/**
+ * Initialize the Iterator at the end.
+ *
+ * Set the iterator at the end of the list and lock the list in the
+ * mode specified in type.
+ */
+CPROPS_DLL 
+int cp_hashlist_iterator_init_tail(cp_hashlist_iterator *iterator, cp_hashlist *l, int lock_mode);
+
+/**
+ * set iterator at list tail
+ */
+CPROPS_DLL 
+int cp_hashlist_iterator_tail(cp_hashlist_iterator *iterator);
+
+/**
+ * set iterator position at first occurence of given key
+ */
+CPROPS_DLL 
+int cp_hashlist_iterator_to_key(cp_hashlist_iterator *iterator, void *key);
+
+/**
+ * iterator destructor
+ */
+CPROPS_DLL 
+int cp_hashlist_iterator_destroy(cp_hashlist_iterator *iterator);
+
+/**
+ * Unlock the list of the Iterator.
+ *
+ * If the locking mode is COLLECTION_LOCK_NONE, do nothing.
+ */
+CPROPS_DLL 
+int cp_hashlist_iterator_release(cp_hashlist_iterator *iterator);
+
+
+/**
+ * Go to the next entry in the list and return the content.
+ * 
+ * @retval entry the next entry object.
+ * @retval NULL if reading beyond end or from empty list.
+ */
+CPROPS_DLL 
+cp_hashlist_entry *cp_hashlist_iterator_next(cp_hashlist_iterator *iterator);
+
+/**
+ * Go to the next entry in the list and return the key.
+ * 
+ * @return object of the next entry.
+ * @retval NULL if reading beyond end or from empty list.
+ */
+CPROPS_DLL 
+void *cp_hashlist_iterator_next_key(cp_hashlist_iterator *iterator);
+
+/**
+ * Go to the next entry in the list and return the content.
+ * 
+ * @return object of the next entry.
+ * @retval NULL if reading beyond end or from empty list.
+ */
+CPROPS_DLL 
+void *cp_hashlist_iterator_next_value(cp_hashlist_iterator *iterator);
+
+/**
+ * Go to the previous entry in the list and return the content.
+ * 
+ * @retval entry the previous entry object.
+ * @retval NULL if reading beyond beginning or from empty list.
+ */
+CPROPS_DLL 
+cp_hashlist_entry *cp_hashlist_iterator_prev(cp_hashlist_iterator *iterator);
+
+/**
+ * Go to the previous entry in the list and return the key.
+ * 
+ * @return object of the previous entry.
+ * @retval NULL if reading beyond beginning or from empty list.
+ */
+CPROPS_DLL 
+void *cp_hashlist_iterator_prev_key(cp_hashlist_iterator *iterator);
+
+/**
+ * Go to the previous entry in the list and return the content.
+ * 
+ * @return object of the previous entry.
+ * @retval NULL if reading beyond beginning or from empty list.
+ */
+CPROPS_DLL 
+void *cp_hashlist_iterator_prev_value(cp_hashlist_iterator *iterator);
+
+/**
+ * return the entry at the current iterator position
+ */
+CPROPS_DLL 
+cp_hashlist_entry *cp_hashlist_iterator_curr(cp_hashlist_iterator *iterator);
+
+/**
+ * return the key at the current iterator position
+ */
+CPROPS_DLL 
+void *cp_hashlist_iterator_curr_key(cp_hashlist_iterator *iterator);
+
+/**
+ * return the value at the current iterator position
+ */
+CPROPS_DLL 
+void *cp_hashlist_iterator_curr_value(cp_hashlist_iterator *iterator);
+
+
+/**
+ * add a mapping before the current iterator position
+ */
+CPROPS_DLL 
+cp_hashlist_entry *cp_hashlist_iterator_insert(cp_hashlist_iterator *iterator, 
+								  			   void *key, 
+								  			   void *value);
+/**
+ * add a mapping after the current iterator position
+ */
+CPROPS_DLL 
+cp_hashlist_entry *cp_hashlist_iterator_append(cp_hashlist_iterator *iterator, 
+											   void *key,
+											   void *value);
+
+/**
+ * remove the mapping at the current iterator position
+ */
+CPROPS_DLL 
+void *cp_hashlist_iterator_remove(cp_hashlist_iterator *iterator);
+
+
+/* ------------------------ end iterator functions ------------------------ */
+
+
+
+/**
+ * Get the number of elements in the collection.
+ * 
+ * @return number of elements in the list.
+ * @retval 0 if list is NULL
+ */
+CPROPS_DLL 
+unsigned long cp_hashlist_item_count(cp_hashlist *);
+
+/**
+ * Get the key of the entry.
+ *
+ * @note This function is fail-safe - works also on NULL entries.
+ *       In any case you should check the result!
+ *
+ * @retval key of the entry.
+ * @retval NULL if entry is NULL
+ */
+CPROPS_DLL 
+void *cp_hashlist_entry_get_key(cp_hashlist_entry *entry);
+
+/**
+ * Get the value of the entry.
+ *
+ * @note This function is fail-safe - works also on NULL entries.
+ *       In any case you should check the result!
+ *
+ * @retval value of the entry.
+ * @retval NULL if entry is NULL
+ */
+CPROPS_DLL 
+void *cp_hashlist_entry_get_value(cp_hashlist_entry *entry);
+
+/**
+ * Insert a new element (key, value) at the beginning of the list.
+ * The operation is synchronized according to the properties of the object.
+ *
+ * @pre list != NULL
+ * @pre key != NULL
+ * @return value object
+ */
+CPROPS_DLL 
+void *cp_hashlist_insert(cp_hashlist *list, void *key, void *value);
+
+/**
+ * Insert a new element (key, value) at the beginning of the list with mode.
+ * @return value object
+ */
+CPROPS_DLL 
+void *cp_hashlist_insert_by_option(cp_hashlist *list, void *key, void *item, int mode);
+
+/**
+ * Append a new element (key, value) at the end of the list.
+ * The operation is synchronized according to the properties of the object.
+ * @pre list != NULL
+ * @pre key != NULL
+ */
+CPROPS_DLL 
+void *cp_hashlist_append(cp_hashlist *list, void *key, void *value);
+
+/**
+ * Append a new element (key, value) at the end of the list with mode.
+ */
+CPROPS_DLL 
+void *cp_hashlist_append_by_option(cp_hashlist *, void *key, void *value, int mode);
+
+/**
+ * Returns the first element with matching key.
+ */
+CPROPS_DLL 
+void *cp_hashlist_get(cp_hashlist *, void *key);
+
+/**
+ * returns non-zero if list contains key
+ */
+CPROPS_DLL 
+int cp_hashlist_contains(cp_hashlist *list, void *key);
+
+/**
+ * Returns the first element of the list.
+ */
+CPROPS_DLL 
+void *cp_hashlist_get_head(cp_hashlist *);
+
+/**
+ * Returns the last element of the list.
+ */
+CPROPS_DLL 
+void *cp_hashlist_get_tail(cp_hashlist *);
+
+/**
+ * Removes the entry with matching key and destroys it (internal locking mode). 
+ *
+ * @param list the object
+ * @param key  Key which is searched.
+ * @retval value that was stored in the entry.
+ * @retval NULL if key was not found
+ */
+CPROPS_DLL 
+void *cp_hashlist_remove(cp_hashlist *list, void *key);
+
+CPROPS_DLL 
+void *cp_hashlist_remove_deep(cp_hashlist *list, void *key);
+
+
+/**
+ * Removes the entry with matching key and destroys it with locking mode.
+ *
+ * @param list the object
+ * @param key  Key which is searched.
+ * @param mode locking mode
+ * @retval value that was stored in the entry.
+ * @retval NULL if key was not found
+ */
+CPROPS_DLL 
+void *cp_hashlist_remove_by_option(cp_hashlist *list, void *key, int mode);
+
+/**
+ * Removes the first entry and destroys it. 
+ *
+ * @return Element that was stored in the first entry.
+ */
+CPROPS_DLL 
+void *cp_hashlist_remove_head(cp_hashlist *list);
+
+/**
+ * Removes the last entry and destroys it. 
+ *
+ * @pre list != NULL
+ * @retval Element that was stored in the first entry if not empty.
+ * @retval NULL if collection is empty
+ */
+CPROPS_DLL 
+void *cp_hashlist_remove_tail(cp_hashlist *list);
+
+/*
+ * Get the next entry. 
+ *
+ * @return value of the next element
+ */
+//CPROPS_DLL 
+//void *cp_hashlist_get_next(cp_hashlist *list);
+
+/**
+ * Test if object is empty.
+ *
+ * @retval true if no element contained.
+ * @retval false if at least one element is contained.
+ */
+CPROPS_DLL 
+int cp_hashlist_is_empty(cp_hashlist *list); //  { return cp_hashlist_item_count(list) == 0; }
+
+/**
+ * Locks the collection with the specified mode.
+ *
+ * This overrides the default mode stored in the object.
+ */
+CPROPS_DLL 
+int cp_hashlist_lock(cp_hashlist *list, int type);
+
+/**
+ * Unlock the object.
+ */
+CPROPS_DLL 
+int cp_hashlist_unlock(cp_hashlist *list);
+
+/**
+ * Set a read lock on the object.
+ */
+#define cp_hashlist_rdlock(list) cp_hashlist_lock((list), COLLECTION_LOCK_READ)
+
+/**
+ * Set a write lock on the object.
+ */
+#define cp_hashlist_wrlock(list) cp_hashlist_lock((list), COLLECTION_LOCK_WRITE)
+
+__END_DECLS
+
+/** @} */
+
+#endif
+


Property changes on: branches/multicore/numpy/core/cprops_thread/hashlist.h
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/multicore/numpy/core/cprops_thread/hashtable.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/hashtable.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/hashtable.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,1265 @@
+
+/**
+ * @addtogroup cp_hashtable
+ */
+/** @{ */
+
+/**
+ * @file
+ * Implementation of generic synchronized cp_hashtable. 
+ *
+ * The elements are stored in cp_list_entry objects.
+ *
+ * @copydoc collection
+ */
+/* ----------------------------------------------------------------- */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include "hashtable.h"
+#include "linked_list.h"
+#include "log.h"
+#include "common.h"
+#include "collection.h"
+#include "thread.h"
+/* #include "util.h" */
+
+#include "cp_config.h"
+#ifdef CP_HAS_STRINGS_H
+#include <strings.h>
+#endif
+
+#ifdef __OpenBSD__
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#endif /* __OpenBSD__ */
+
+#ifndef CP_HASHTABLE_MULTIPLE_VALUES
+#define CP_HASHTABLE_MULTIPLE_VALUES 1
+#endif
+
+static int table_sizes[] = 
+    {
+           5,        7,       11,       23,       47,
+          79,       97,      157,      197,      299,
+         397,      599,      797,     1297,     1597,
+        2499,     3199,     4799,     6397,     9599,
+       12799,    19199,    25597,    38399,    51199,
+	   76799,   102397,   153599,   204797,   306797,
+	  409597,   614399,   819199,  1288799,  1638397, 
+     2457599,  3276799,  4915217,  6553577,  9830393 
+    };
+
+static int table_sizes_len = 40;
+
+
+unsigned long cp_hashtable_choose_size(unsigned long size_request)
+{
+    unsigned long new_size;
+
+    if (table_sizes[table_sizes_len - 1] < size_request)
+    {
+        for (new_size = table_sizes[table_sizes_len - 1]; 
+             new_size < size_request; 
+             new_size = new_size * 2 + 1);
+    }
+    else
+    {
+        int min = -1;
+        int max = table_sizes_len - 1;
+        int pos;
+
+        while (max > min + 1)
+        {
+            pos = (max + min + 1) / 2;
+            if (table_sizes[pos] < size_request)
+                min = pos;
+            else
+                max = pos;
+        }
+
+        new_size = table_sizes[max];
+    }
+         
+    return new_size;
+}
+
+cp_hashtable *cp_hashtable_create(unsigned long size_hint, 
+                                  cp_hashfunction hash_fn, 
+                                  cp_compare_fn compare_fn)
+{
+    return cp_hashtable_create_by_option(0, size_hint, hash_fn, 
+                                         compare_fn, NULL, NULL, NULL, NULL);
+}
+
+
+cp_hashtable *
+    cp_hashtable_create_copy_mode(unsigned long size_hint, 
+                                  cp_hashfunction hash_fn, 
+                                  cp_compare_fn compare_fn, 
+                                  cp_copy_fn copy_key, 
+                                  cp_destructor_fn free_key,
+                                  cp_copy_fn copy_value,
+                                  cp_destructor_fn free_value)
+{
+    return cp_hashtable_create_by_option(COLLECTION_MODE_DEEP | 
+                                         COLLECTION_MODE_COPY, 
+                                         size_hint, 
+                                         hash_fn, 
+                                         compare_fn, 
+                                         copy_key, 
+                                         free_key,
+                                         copy_value,
+                                         free_value);
+}
+
+cp_hashtable *
+    cp_hashtable_create_by_option(int mode, unsigned long size_hint, 
+                                  cp_hashfunction hash_fn, 
+                                  cp_compare_fn compare_fn, 
+                                  cp_copy_fn copy_key, 
+                                  cp_destructor_fn free_key,
+                                  cp_copy_fn copy_value,
+                                  cp_destructor_fn free_value)
+{
+    cp_hashtable *table;
+    
+    table = (cp_hashtable *) calloc(1, sizeof(cp_hashtable));
+    if (table == NULL)
+    {
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    table->table_size = cp_hashtable_choose_size(size_hint);
+    table->items = 0;
+    table->table = (cp_hashtable_entry **) 
+		calloc(table->table_size, sizeof(cp_hashtable_entry *));
+    if (table->table == NULL) 
+    {
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    table->hash_fn = hash_fn;
+    table->compare_fn = compare_fn;
+    table->copy_key = copy_key;
+    table->copy_value = copy_value;
+    table->free_key = free_key;
+    table->free_value = free_value;
+
+    table->mode = mode;
+
+    table->min_size = size_hint;
+    table->fill_factor_min = CP_HASHTABLE_DEFAULT_MIN_FILL_FACTOR;
+    table->fill_factor_max = CP_HASHTABLE_DEFAULT_MAX_FILL_FACTOR;
+
+    table->resizing = 0;
+
+    table->lock = malloc(sizeof(cp_lock));
+    if (table->lock == NULL)
+    {
+        free(table->table);
+        free(table);
+        errno = ENOMEM;
+        return NULL;
+    }
+  
+	if (cp_lock_init(table->lock, NULL))
+	{
+		free(table->lock);
+        free(table->table);
+        free(table);
+        return NULL;
+	}
+
+    return table;
+}
+
+cp_hashtable_entry *
+	cp_hashtable_create_entry(cp_hashtable *table, 
+							  int mode, 
+							  void *key, 
+							  void *value, 
+							  long hashcode)
+{
+    cp_hashtable_entry *entry;
+
+    entry = (cp_hashtable_entry *) malloc(sizeof(cp_hashtable_entry));
+    if (entry == NULL) 
+    {
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    if (mode & COLLECTION_MODE_COPY) 
+    {
+        entry->key = table->copy_key ? (*table->copy_key)(key) : key;
+        entry->value = table->copy_value ? (*table->copy_value)(value) :value;
+    } 
+    else 
+    {
+        entry->key = key;
+        entry->value = value;    
+    }
+
+    entry->hashcode = hashcode;
+    entry->next = NULL;
+
+    return entry;
+}
+
+    
+void cp_hashtable_destroy(cp_hashtable *table)
+{
+    long i;
+    cp_hashtable_entry *entry, *next;
+    
+	table->mode |= COLLECTION_MODE_NORESIZE;
+
+    if (table->resizing) 
+    {
+		struct timeval timeout;
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 10;
+		while (table->resizing)
+			select(0, NULL, NULL, NULL, &timeout);
+    }
+        
+    for (i = 0; i < table->table_size; i++) 
+    {
+        entry = table->table[i];
+        while (entry != NULL) 
+        {
+            next = entry->next;
+            if (table->mode & COLLECTION_MODE_DEEP) 
+            {
+                if (table->free_key)
+                    (*table->free_key)(entry->key);
+                if (table->free_value)
+                    (*table->free_value)(entry->value);
+            }
+            free(entry);
+            entry = next;
+        }
+    }
+        
+    free(table->table);
+    cp_lock_destroy(table->lock);
+    free(table->lock);
+    free(table);
+}
+
+void cp_hashtable_destroy_deep(cp_hashtable *table)
+{
+    cp_hashtable_set_mode(table, COLLECTION_MODE_DEEP);
+    cp_hashtable_destroy_custom(table, table->free_key, table->free_value);
+}
+
+void cp_hashtable_destroy_custom(cp_hashtable *table, cp_destructor_fn dk, cp_destructor_fn dv)
+{
+    long i;
+    cp_hashtable_entry *entry, *next;
+
+    if (table->resizing) 
+    {
+		struct timeval timeout;
+		timeout.tv_sec = 0;
+		timeout.tv_usec = 10;
+		while (table->resizing)
+			select(0, NULL, NULL, NULL, &timeout);
+    }
+
+    for (i = 0; i < table->table_size; i++) 
+    {
+        entry = table->table[i];
+        while (entry != NULL) 
+        {
+            next = entry->next;
+            if (dk) (*dk)(entry->key);
+            if (dv) (*dv)(entry->value);
+            free(entry);
+            entry = next;
+        }
+    }
+        
+    free(table->table);
+    cp_lock_destroy(table->lock);
+    free(table->lock);
+    free(table);
+}
+
+
+void cp_hashtable_destroy_shallow(cp_hashtable *table)
+{
+    cp_hashtable_unset_mode(table, COLLECTION_MODE_DEEP);
+    cp_hashtable_destroy(table);
+}
+
+int cp_hashtable_lock_internal(cp_hashtable *table, int type)
+{
+    int rc;
+
+    switch (type)
+    {
+        case COLLECTION_LOCK_READ:
+            rc = cp_lock_rdlock(table->lock);
+            break;
+
+        case COLLECTION_LOCK_WRITE:
+            rc = cp_lock_wrlock(table->lock);
+            break;
+
+        case COLLECTION_LOCK_NONE:
+            rc = 0;
+            break;
+
+        default:
+            rc = EINVAL;
+            break;
+    }
+
+    return rc;
+}
+    
+int cp_hashtable_unlock_internal(cp_hashtable *table)
+{
+    return cp_lock_unlock(table->lock);
+}
+
+int cp_hashtable_txlock(cp_hashtable *table, int type)
+{
+	if (table->mode & COLLECTION_MODE_NOSYNC) return 0;
+	if (table->mode & COLLECTION_MODE_IN_TRANSACTION && 
+		table->txtype == COLLECTION_LOCK_WRITE)
+	{
+		cp_thread self = cp_thread_self();
+		if (cp_thread_equal(self, table->txowner)) return 0;
+	}
+	return cp_hashtable_lock_internal(table, type);
+}
+
+int cp_hashtable_txunlock(cp_hashtable *table)
+{
+	if (table->mode & COLLECTION_MODE_NOSYNC) return 0;
+	if (table->mode & COLLECTION_MODE_IN_TRANSACTION && 
+		table->txtype == COLLECTION_LOCK_WRITE)
+	{
+		cp_thread self = cp_thread_self();
+		if (cp_thread_equal(self, table->txowner)) return 0;
+	}
+	return cp_hashtable_unlock_internal(table);
+}
+
+/* lock and set the transaction indicators */
+int cp_hashtable_lock(cp_hashtable *table, int type)
+{
+	int rc;
+	if ((table->mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
+	if ((rc = cp_hashtable_lock_internal(table, type))) return rc;
+	table->txtype = type;
+	table->txowner = cp_thread_self();
+	table->mode |= COLLECTION_MODE_IN_TRANSACTION;
+	return 0;
+}
+
+/* unset the transaction indicators and unlock */
+int cp_hashtable_unlock(cp_hashtable *table)
+{
+	cp_thread self = cp_thread_self();
+	if (table->txowner == self)
+	{
+		table->txtype = 0;
+		table->txowner = 0;
+		table->mode ^= COLLECTION_MODE_IN_TRANSACTION;
+	}
+	else if (table->txtype == COLLECTION_LOCK_WRITE)
+		return -1;
+	return cp_hashtable_unlock_internal(table);
+}
+
+
+
+int cp_hashtable_set_mode(cp_hashtable *table, int mode)
+{
+    int syncbit; 
+	/* can't set NOSYNC in the middle of a transaction */
+	if ((table->mode & COLLECTION_MODE_IN_TRANSACTION) && 
+		(mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
+
+	syncbit = table->mode & COLLECTION_MODE_NOSYNC;
+    if (!syncbit)
+        cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE);
+    table->mode |= mode;
+    if (!syncbit)
+        cp_hashtable_txunlock(table);
+
+	return 0;
+}
+
+int cp_hashtable_get_mode(cp_hashtable *table)
+{
+	return table->mode;
+}
+
+int cp_hashtable_unset_mode(cp_hashtable *table, int mode)
+{
+    int syncbit = table->mode & COLLECTION_MODE_NOSYNC;
+    if (!syncbit)
+        cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE);
+    table->mode &= table->mode ^ mode;
+    if (!syncbit)
+        cp_hashtable_txunlock(table);
+	return 0;
+}
+
+/**
+ * Retrieves the value by key from normal or resizing table.
+ *
+ * @param table the object
+ * @param key    Key to search for.
+ * @param code   Hash code of the Key (saves recalculating it)
+ * @param option operation mode
+ * @param resize 0: search in the normal table, 1: search in the resize table
+ * @retval value of the entry with key.
+ * @retval NULL otherwise (no entry with given key)
+ */
+void *lookup_internal(cp_hashtable *table, void *key, long code, int option, int resize)
+{
+    cp_hashtable_entry *entry;
+    void *ret = NULL;
+
+    entry = resize ? table->resize_table[code % table->resize_len]
+                   : table->table[code % table->table_size];
+
+    while (entry != NULL && (*table->compare_fn)(key, entry->key)) 
+        entry = entry->next;
+    
+    if (entry)
+    {
+#if CP_HASHTABLE_MULTIPLE_VALUES
+        if (option & COLLECTION_MODE_MULTIPLE_VALUES)
+        {
+            cp_list *l = 
+                cp_list_create_view(table->mode, 
+                                    NULL, 
+                                    table->copy_value,
+                                    table->free_value,
+                                    table->lock);
+            cp_list_insert(l, entry->value);
+            entry = entry->next;
+            while (entry != NULL) 
+            {
+                if ((*table->compare_fn)(key, entry->key) == 0) 
+                    cp_list_append(l, entry->value);
+
+                entry = entry->next;
+            }
+
+            ret = l;
+        }
+        else 
+#endif
+        ret = entry->value;
+    }
+
+    return ret;
+}
+
+/**
+ * Retrieves the value by key.
+ *
+ * @param table the object
+ * @param key Key to search for.
+ * @param option operation mode
+ * @retval value of the entry with key.
+ * @retval NULL otherwise (no entry with given key or key == NULL)
+ */
+void *cp_hashtable_get_by_option(cp_hashtable *table, void *key, int option)
+{
+    long code;
+    void *ret;
+
+    if (table == NULL || key == NULL)
+    {
+        errno = EINVAL;
+        return NULL;
+    }
+
+    if (cp_hashtable_txlock(table, COLLECTION_LOCK_READ)) return NULL;
+
+    code = abs((*table->hash_fn)(key));
+    ret = lookup_internal(table, key, code, option, 0);
+    /* when resizing, search also there */
+    if (ret == NULL && table->resizing) 
+        ret = lookup_internal(table, key, code, option, 1);
+
+    cp_hashtable_txunlock(table);
+
+    return ret;
+}
+
+/**
+ * \<\<Thread\>\> resize a cp_hashtable.
+ *
+ * This cp_thread does a background resize of the table.
+ * It creates a new table and moves the entries to the new table.
+ * @post All items moved to the new table which replaces the old table
+ *       The old table is destroyed.
+ * @note The cp_thread locks and unlocks the table for each item.
+ * This creates some overhead, but ensures that the table can still be used
+ * during resizing.
+ */
+void *cp_hashtable_resize_thread(void *tbl)
+{
+    long i, old_size, index;
+    long new_size;
+    cp_hashtable_entry **new_table, **old_table;
+    cp_hashtable_entry **insert, *entry;
+    cp_hashtable *table = (cp_hashtable *) tbl;
+
+    new_size = table->table_size;
+    new_table = table->table;
+
+    old_size = table->resize_len;
+    old_table = table->resize_table;
+
+#ifdef __TRACE__
+    DEBUGMSG("resize %d to %d - resize thread starting\n", old_size, new_size);
+#endif
+
+    /* copy old table into new table, bucket by bucket */
+    for (i = 0; i < old_size; i++) 
+    {
+//        if (!(table->mode & COLLECTION_MODE_NOSYNC))
+        cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE);
+        entry = old_table[i];
+        while (entry != NULL) 
+        {
+            index = entry->hashcode % new_size;
+            insert = &new_table[index];
+            while (*insert != NULL)
+                insert = &(*insert)->next;
+
+            *insert = entry;
+            entry = entry->next;
+            (*insert)->next = NULL;
+        }
+        old_table[i] = NULL;
+
+//        if (!(table->mode & COLLECTION_MODE_NOSYNC))
+           cp_hashtable_txunlock(table);
+    }
+
+    /* cleanup */
+//    if (!(table->mode & COLLECTION_MODE_NOSYNC)) 
+    cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE);
+    free(table->resize_table); table->resize_table = NULL;
+    table->resizing = 0;
+//    if (!(table->mode & COLLECTION_MODE_NOSYNC)) 
+
+#ifdef __TRACE__
+    DEBUGMSG("resize %d to %d - done\n", old_size, new_size);
+#endif
+    cp_hashtable_txunlock(table);
+
+    return NULL;
+}
+
+int cp_hashtable_set_min_size(cp_hashtable *table, int min_size)
+{
+    if (cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE)) return -1;
+    table->min_size = min_size;
+    cp_hashtable_txunlock(table);
+	return 0;
+}
+
+
+int cp_hashtable_set_max_fill_factor(cp_hashtable *table, int fill_factor)
+{
+    if (cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE)) return -1;
+    table->fill_factor_max = fill_factor;
+    cp_hashtable_txunlock(table);
+	return 0;
+}
+
+int cp_hashtable_set_min_fill_factor(cp_hashtable *table, int fill_factor)
+{
+    if (cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE)) return -1;
+    table->fill_factor_min = fill_factor;
+    cp_hashtable_txunlock(table);
+	return 0;
+}
+
+
+/**
+ * Initiates a resize of the cp_hashtable which is executed in the background.
+ *
+ * @return NULL
+ */
+void *cp_hashtable_resize(cp_hashtable *table, long new_size)
+{
+    cp_hashtable_entry **new_table;
+
+    if (table->resizing) return NULL;
+
+    new_table = (cp_hashtable_entry **) malloc(new_size * sizeof(cp_hashtable_entry *));
+    if (new_table == NULL) 
+    {
+        errno = ENOMEM;
+        return NULL;
+    }
+    memset(new_table, 0, new_size * sizeof(cp_hashtable_entry *));
+
+    table->resize_table = table->table;
+    table->resize_len = table->table_size;
+    table->table = new_table;
+    table->table_size = new_size;
+    table->resizing = 1;
+
+    cp_thread_create(table->resize_thread, NULL, cp_hashtable_resize_thread, table);
+    cp_thread_detach(table->resize_thread);
+
+    return NULL;
+}
+
+/**
+ * Resizes the table to a new size.
+ * 
+ * This is invoked by the insertion code if the load * factor goes over the
+ * fill factor limits.
+ * @param table the object
+ * @param new_size desired size.
+ *        The system trys to optmize the actual size for good distribution.
+ */
+void *cp_hashtable_resize_nosync(cp_hashtable *table, unsigned long new_size)
+{
+    unsigned long old_size;
+    cp_hashtable_entry **old_table;
+    cp_hashtable_entry *entry, *next, **insert;
+    unsigned long i, index;
+
+    old_size = table->table_size;
+    old_table = table->table;
+    
+    table->table_size = cp_hashtable_choose_size(new_size);
+
+#ifdef __TRACE__
+    DEBUGMSG("resizing table (nosync): %d to %d\n", old_size, table->table_size);
+#endif
+
+    table->table = (cp_hashtable_entry **) malloc(table->table_size * sizeof(cp_hashtable_entry *));
+    memset(table->table, 0, table->table_size * sizeof(cp_hashtable_entry *));
+
+    if (table->table == NULL) 
+    {
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    for (i = 0; i < old_size; i++) 
+    {
+        entry = old_table[i];
+        while (entry != NULL) 
+        {
+            index = entry->hashcode % table->table_size;
+            next = entry->next;
+            entry->next = NULL;
+            insert = &table->table[index];
+            while (*insert != NULL) 
+                insert = &(*insert)->next;
+
+            *insert = entry;
+            
+            entry = next;
+        }
+    }
+
+    free(old_table);
+
+    return table;
+}
+ 
+/**
+ * Internal replace an existing entry with a new key, value pair.
+ *
+ * @param table the object
+ * @param key    Key to search for.
+ * @param value  new value
+ * @param code   Hash code of the Key (saves recalculating it)
+ * @param option operation mode
+ * @param resize 0: search in the normal table, 1: search in the resize table
+ * @return pointer to table of entries 
+ */
+static cp_hashtable_entry **cp_hashtable_replace_internal(cp_hashtable *table, 
+                                                          void *key, 
+                                                          void *value, 
+                                                          unsigned long code, 
+                                                          int option,
+                                                          int resize)
+{
+    cp_hashtable_entry **entry;
+    unsigned long index;
+
+    index = resize ? code % table->resize_len : code % table->table_size;
+    
+    entry = resize ? &table->resize_table[index] : &table->table[index];
+    while (*entry != NULL) 
+    {
+#if CP_HASHTABLE_MULTIPLE_VALUES
+        if (!(option & COLLECTION_MODE_MULTIPLE_VALUES) && 
+            (*table->compare_fn)(key, (*entry)->key) == 0) 
+#else
+        if ((*table->compare_fn)(key, (*entry)->key) == 0) 
+#endif
+        {
+            if (option & COLLECTION_MODE_DEEP) 
+            {
+                if (table->free_key)
+                    (*table->free_key)((*entry)->key);
+                if (table->free_value)
+                    (*table->free_value)((*entry)->value);
+                (*entry)->key = key;
+            }
+        
+            if (option & COLLECTION_MODE_COPY) 
+            {
+                (*entry)->key = table->copy_key ? (*table->copy_key)(key) : key;
+                (*entry)->value = table->copy_value ? (*table->copy_value)(value) : value;
+            }
+            else
+                (*entry)->value = value;
+
+            (*entry)->hashcode = code;
+            break;
+        }
+
+        entry = &(*entry)->next;
+    }
+
+    return entry;
+}
+
+void *cp_hashtable_put(cp_hashtable *table, void *key, void *value)
+{
+    return cp_hashtable_put_by_option(table, key, value, table->mode);
+}
+
+void *cp_hashtable_put_safe(cp_hashtable *table, void *key, void *value)
+{
+    return cp_hashtable_put_by_option(table, key, value, table->mode | COLLECTION_MODE_DEEP);
+}
+
+void *cp_hashtable_put_copy(cp_hashtable *table, void *key, void *value)
+{
+        return cp_hashtable_put_by_option(table, key, value, table->mode | COLLECTION_MODE_COPY);
+}
+
+
+/* actual insertion code */
+void *cp_hashtable_put_by_option(cp_hashtable *table, void *key, void *value, int option)
+{
+    unsigned long code;
+    cp_hashtable_entry **entry; /* defined ** for when initializing a bucket */ 
+    int syncbit;
+    void *ret = NULL;
+
+    syncbit = table->mode & COLLECTION_MODE_NOSYNC;
+    if (cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE)) return NULL;
+
+    if ((option & COLLECTION_MODE_NORESIZE) == 0)
+    {
+        if ((table->items * 100) > 
+            (table->table_size * table->fill_factor_max))
+        {
+            int new_size = cp_hashtable_choose_size(table->table_size * 2);
+            if (syncbit)
+                cp_hashtable_resize_nosync(table, new_size);
+            else
+                cp_hashtable_resize(table, new_size);
+        }
+    }
+    
+    code = abs((*table->hash_fn)(key));
+
+    entry = cp_hashtable_replace_internal(table, key, value, code, option, 0);
+
+    if (*entry == NULL && table->resizing) 
+    {
+        cp_hashtable_entry **resize_entry;
+
+        resize_entry = cp_hashtable_replace_internal(table, key, value, code, option, 1);
+        if (*resize_entry != NULL)  /* prevent write */
+            entry = resize_entry;
+
+    }
+        
+    if (*entry == NULL) 
+    {
+        /* no entry found, entry points at lookup location */
+        *entry = cp_hashtable_create_entry(table, option, key, value, code);
+        if (*entry) 
+            table->items++;
+    }
+    
+    if (*entry)
+        ret = (*entry)->value;
+
+    if (!syncbit) cp_hashtable_txunlock(table);
+
+    return ret;
+}
+
+/**
+ * Internal remove an entry from the table by key.
+ *
+ * Get the value by key and destroy the entry.
+ *
+ * @param table the object
+ * @param key    Key to search for.
+ * @param code   Hash code of the Key (saves recalculating it)
+ * @param mode   operation mode
+ * @param resize 0: search in the normal table, 1: search in the resize table
+ * @retval value of the entry with key.
+ * @retval NULL otherwise (no entry with given key)
+ */
+void *cp_hashtable_remove_internal(cp_hashtable *table, void *key, long code, int mode, int resize)
+{
+    cp_hashtable_entry **entry, *item;
+    void *value = NULL;
+
+    entry = resize ? &table->resize_table[code % table->resize_len]
+                   : &table->table[code % table->table_size];
+
+    while (*entry != NULL) 
+    {
+        if ((*table->compare_fn)(key, (*entry)->key) == 0) 
+        {
+            /* entry now points either to the table->table element or to the  */
+            /* next pointer in the parent entry                               */
+            table->items--;
+            item = *entry;
+            *entry = item->next;
+
+            value = item->value;
+            if (mode & COLLECTION_MODE_DEEP) 
+            {
+                if (table->free_key)
+                    (*table->free_key)(item->key);
+                if (table->free_value)
+                    (*table->free_value)(item->value);
+            }
+
+            free(item);
+
+#if CP_HASHTABLE_MULTIPLE_VALUES
+            if (!(mode & COLLECTION_MODE_MULTIPLE_VALUES)) 
+#endif
+            break; 
+        }
+
+        entry = &(*entry)->next;
+    }
+
+    return value;
+}
+
+/**
+ * Remove an entry from the table by key with locking mode.
+ *
+ * Get the value by key and destroy the entry.
+ *
+ * @param table the object
+ * @param key    Key to search for.
+ * @param mode   operation/locking mode
+ * @retval value of the entry with key.
+ * @retval NULL otherwise (no entry with given key)
+ */
+void *cp_hashtable_remove_by_mode(cp_hashtable *table, void *key, int mode)
+{
+    long code;
+    void *value = NULL;
+    int syncbit = table->mode & COLLECTION_MODE_NOSYNC;
+    if (cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE)) return NULL;
+
+    code = abs((*table->hash_fn)(key));
+
+    value = cp_hashtable_remove_internal(table, key, code, mode, 0);
+
+    if (table->resizing) 
+    {
+        void *resize_value;
+        resize_value = cp_hashtable_remove_internal(table, key, code, mode, 1);
+        if (value == NULL) value = resize_value;
+    }
+
+    if ((table->mode & COLLECTION_MODE_NORESIZE) == 0)
+    {
+        if (table->table_size > table->min_size &&
+            ((table->items * 100) < 
+            (table->table_size * table->fill_factor_min)))
+        {
+            int new_size = cp_hashtable_choose_size(table->table_size / 2);
+            if (syncbit)
+                cp_hashtable_resize_nosync(table, new_size);
+            else
+                cp_hashtable_resize(table, new_size);
+        }
+    }
+
+    if (!syncbit) cp_hashtable_txunlock(table);
+
+    return value;
+}
+
+int cp_hashtable_remove_all(cp_hashtable *table)
+{
+    long i;
+    cp_hashtable_entry *entry, *next;
+    int deepbit = table->mode & COLLECTION_MODE_DEEP;
+    cp_destructor_fn dk = table->free_key;
+    cp_destructor_fn dv = table->free_value;
+
+    if (cp_hashtable_txlock(table, COLLECTION_LOCK_WRITE)) return -1;
+    
+    for (i = 0; i < table->table_size; i++) 
+    {
+        if ((entry = table->table[i]) != NULL) 
+        {
+            while (entry != NULL) 
+            {
+                next = entry->next;
+                if (deepbit)
+                {
+                    if (dk) (*dk)(entry->key);
+                    if (dv) (*dv)(entry->value);
+                }
+                free(entry);
+                entry = next;
+            }
+        }
+    }
+
+    if (table->resizing) 
+    {
+        for (i = 0; i < table->resize_len; i++) 
+            if ((entry = table->resize_table[i]) != NULL) 
+                while (entry != NULL) 
+                {
+                    next = entry->next;
+                    if (deepbit)
+                    {
+                        if (dk) (*dk)(entry->key);
+                        if (dv) (*dv)(entry->value);
+                    }
+                    free(entry);
+                    entry = next;
+                }
+    }
+
+    cp_hashtable_txunlock(table);
+	return 0;
+}
+
+/* remove using current mode settings */
+void *cp_hashtable_remove(cp_hashtable *table, void *key)
+{
+    return cp_hashtable_remove_by_mode(table, key, table->mode);
+}
+
+
+/**
+ * Remove with COLLECTION_MODE_DEEP set
+ * @note here cp_hashtable_remove_by_mode returns an invalid pointer on 
+ * success, since the item has just been released. We can not use it but we 
+ * can tell it isn't null.
+ */
+int cp_hashtable_remove_deep(cp_hashtable *table, void *key)
+{
+    return cp_hashtable_remove_by_mode(table, key
+              , table->mode | COLLECTION_MODE_DEEP) != NULL;
+}
+
+int cp_hashtable_contains(cp_hashtable *table, void *key)
+{
+    int rc = 0;
+
+    if (table != NULL && key != NULL)
+    {
+        long code;
+        void *val;
+        int option;
+        if (cp_hashtable_txlock(table, COLLECTION_LOCK_READ)) return -1;
+
+        option = table->mode & COLLECTION_MODE_MULTIPLE_VALUES;
+        code = abs((*table->hash_fn)(key));
+        val = lookup_internal(table, key, code, table->mode, 0);
+        /* when resizing, search also there */
+        if (val == NULL && table->resizing) 
+            val = lookup_internal(table, key, code, table->mode, 1);
+
+        if (val != NULL)
+		{
+			rc = 1;
+			if (option) cp_list_destroy(val);
+		}
+
+        cp_hashtable_txunlock(table);
+    }
+    else
+        errno = EINVAL; //~~ and set rc = -1?
+
+    return rc;
+}
+
+
+void *cp_hashtable_get(cp_hashtable *table, void *key)
+{
+    return cp_hashtable_get_by_option(table, key, table->mode);
+}
+
+void **cp_hashtable_get_keys(cp_hashtable *table)
+{
+    long i, j;
+    void **keys;
+    cp_hashtable_entry *entry = NULL;
+    int rc = 0;
+
+    if (table == NULL)
+    {
+        errno = EINVAL;
+        return NULL;
+    }
+
+    if (cp_hashtable_txlock(table, COLLECTION_LOCK_READ)) return NULL;
+
+    keys = (void **) calloc(table->items, sizeof(void *));
+    if (keys == NULL) 
+    {
+        rc = ENOMEM;
+        goto DONE;
+    }
+    
+    for (i = 0, j = 0; i < table->table_size; i++) \
+    {
+        entry = table->table[i];
+        while (entry != NULL) 
+        {
+            keys[j++] = entry->key;
+            entry = entry->next;
+        }
+    }
+
+    if (table->resizing) 
+        for (i = 0; i < table->resize_len; i++) 
+            entry = table->resize_table[i];
+            while (entry != NULL) 
+            {
+                keys[j++] = entry->key;
+                entry = entry->next;
+            }
+            
+DONE:
+    cp_hashtable_txunlock(table);
+    if (rc) errno = rc;
+
+    return keys;
+}
+    
+
+unsigned long cp_hashtable_count(cp_hashtable *table)
+{
+    return (table) ? table->items : 0L; 
+}
+
+
+void **cp_hashtable_get_values(cp_hashtable *table)
+{
+    long i, j;
+    void **values;
+    cp_hashtable_entry *entry;
+    int rc = 0;
+
+    if (cp_hashtable_txlock(table, COLLECTION_LOCK_READ)) return NULL;
+
+    values = (void **) malloc(table->items * sizeof(void *));
+    if (values == NULL) 
+    {
+        rc = ENOMEM;
+        goto DONE;
+    }
+    
+    for (i = 0, j = 0; i < table->table_size; i++) 
+    {
+        entry = table->table[i];
+        while (entry != NULL) 
+        {
+            values[j++] = entry->value;
+            entry = entry->next;
+        }
+    }        
+
+    if (table->resizing) 
+    {
+        for (i = 0; i < table->resize_len; i++) 
+        {
+            entry = table->resize_table[i];
+            while (entry != NULL) 
+            {
+                values[j++] = entry->value;
+                entry = entry->next;
+            }
+        }
+    }
+
+DONE:
+    cp_hashtable_txunlock(table);
+    if (rc) errno = rc;
+
+    return values;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* ---   hash function implementations for primitive types & strings    --- */
+/* ------------------------------------------------------------------------ */
+
+unsigned long cp_hash_int(void *i)
+{
+    return (long) *((int *) i);
+}
+
+
+int cp_hash_compare_int(void *i, void *j)
+{
+    return *((int *) i) - *((int *) j);
+}
+
+unsigned long cp_hash_long(void *l)
+{
+    return *((long *) l);
+}
+
+
+int cp_hash_compare_long(void *i, void *j)
+{
+    long diff = *((long *) i) - *((long *) j);
+    return diff > 0 ? 1 : diff < 0 ? -1 : 0;
+}
+
+unsigned long cp_hash_addr(void *addr)
+{
+	return (unsigned long) addr;
+}
+
+int cp_hash_compare_addr(void *a1, void *a2)
+{
+	return (long) a1 - (long) a2;
+}
+
+unsigned long cp_hash_string(void *str)
+{
+    int i;
+    long res;
+    char *_str;
+    
+    if (str == NULL) return 0; 
+
+    _str = (char *) str;
+    
+    for (i = 0, res = 1; *_str != '\0'; _str++)
+        res = res * HASH_SEED + *_str;
+
+    return res;
+}
+    
+
+int cp_hash_compare_string(void *s1, void *s2)
+{
+    if (s1 == NULL && s2 == NULL) return 0;
+    if (s1 == NULL || s2 == NULL) return -1;
+    return strcmp((char *) s1, (char *) s2);
+}
+
+#define CP_CHAR_UC(x) ((x) >= 'a' && (x) <= 'z' ? ((x) - 'a' + 'A') : (x))
+        
+unsigned long cp_hash_istring(void *str)
+{
+    int i;
+    long res;
+    char *_str;
+    
+    if (str == NULL) return 0; 
+
+    _str = (char *) str;
+    
+    for (i = 0, res = 1; *_str != '\0'; _str++)
+        res = res * HASH_SEED + CP_CHAR_UC(*_str);
+
+    return res;
+}
+
+int cp_hash_compare_istring(void *s1, void *s2)
+{
+    if (s1 == NULL && s2 == NULL) return 0;
+    if (s1 == NULL || s2 == NULL) return -1;
+    return strcasecmp((char *) s1, (char *) s2);
+}
+
+void *cp_hash_copy_string(void *element)
+{
+    char *src;
+    char *dst;
+    size_t len;
+    
+    src = (char *) element;
+    len = strlen(src) + 1;
+    dst = (char *) malloc(len * sizeof(char));
+
+    if (dst == NULL) return NULL;
+
+#ifdef CP_HAS_STRLCPY
+    strlcpy(dst, src, len);
+#else
+    strcpy(dst, src);
+#endif /* CP_HAS_STRLCPY */
+    return dst;
+}
+
+unsigned long cp_hash_float(void *addr)
+{
+	unsigned long *p = (unsigned long *) addr;
+	return *p;
+}
+
+int cp_hash_compare_float(void *a1, void *a2)
+{
+	float f1 = *(float *) a1;
+	float f2 = *(float *) a2;
+	if (f1 > f2) return 1;
+	if (f1 < f2) return -1;
+	return 0;
+}
+
+unsigned long cp_hash_double(void *d)
+{
+	unsigned long *p = (unsigned long *) d;
+	if (sizeof(unsigned long) < sizeof(double))
+		return p[0] ^ p[1];
+	return *p;
+}
+
+int cp_hash_compare_double(void *a1, void *a2)
+{
+	double d1 = *(double *) a1;
+	double d2 = *(double *) a2;
+	if (d1 > d2) return 1;
+	if (d1 < d2) return -1;
+	return 0;
+}
+
+/** @} */
+


Property changes on: branches/multicore/numpy/core/cprops_thread/hashtable.c
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/multicore/numpy/core/cprops_thread/hashtable.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/hashtable.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/hashtable.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,568 @@
+#ifndef _CP_HASHTABLE_H
+#define _CP_HASHTABLE_H
+
+/*
+ * hash table implementation
+ */
+
+/**
+ * @addtogroup cp_hashtable
+ * @ingroup collection
+ * @copydoc collection
+ *
+ */
+/** @{ */
+/**
+ * @file
+ * generic synchronized hashtable. 
+ *
+ * Here is an example of using a cp_hashtable to create a lookup for 'bar'
+ * items using 'foo' keys:
+ *
+ * <code><pre>
+ * unsigned long foo_hash_code(void *fooptr) 
+ * {
+ *     return ((foo *) fooptr)->id; 
+ * }    
+ *
+ * // compare function
+ * int foo_compare(void *f1, void *f2)
+ * {
+ *     return ((foo *) f1)->id != ((foo *) f2)->id;
+ * }
+ *
+ * ...
+ * 
+ *     cp_hashtable *t;
+ *     foo *foo1, *f;
+ *     bar *bar1, *bar2;
+ *     
+ *     t = cp_hashtable_create(10, foo_hash_code, foo_compare);
+ *     if (t == NULL) 
+ *     {
+ *         perror("can\'t create cp_hashtable");
+ *         exit(1);
+ *     }
+ * 
+ *     cp_hashtable_put(foo1, bar1, t);
+ * 
+ *     ...
+ *     f = foo_create(...);
+ *     ...
+ * 
+ *     if ((bar2 = (bar *) cp_hashtable_get(f, t))) 
+ *         printf("%s maps to %s\n", foo_get_name(f), bar_get_name(bar2));
+ *     else 
+ *         printf("%s is not mapped\n", foo_get_name(f));
+ *
+ *     ...
+ * 
+ *     cp_hashtable_destroy(t);
+ * </pre></code>
+ * 
+ * Note the strcmp like semantics of the compare function. The comparison
+ * should return 0 for identical keys.
+ * <p>
+ * @see hash.h (util.collection) for function prototypes 
+ * and convenience functions.
+ * @see cp_hashtable_create, cp_hashtable_destroy, cp_hashtable_destroy_deep, cp_hashtable_put,
+ *      cp_hashtable_get, cp_hashtable_contains, cp_hashtable_remove_deep
+ */
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+#include "collection.h"
+
+/*
+ * cp_hashtable interface for members of mapping collections.
+ */
+
+#include "cp_config.h"
+
+/**
+ * 1000000001 is a prime. HASH_SEED is used by cp_hash_string(). 
+ */
+#define HASH_SEED 1000000001L
+
+#ifndef CP_HASHTABLE_DEFAULT_MIN_FILL_FACTOR
+#define CP_HASHTABLE_DEFAULT_MIN_FILL_FACTOR   5
+#endif
+
+#ifndef CP_HASHTABLE_DEFAULT_MAX_FILL_FACTOR
+#define CP_HASHTABLE_DEFAULT_MAX_FILL_FACTOR  70
+#endif
+
+/* ----------------------------------------------------------------- 
+ * Function prototypes
+ * ----------------------------------------------------------------- */
+/**
+ * the hash function takes (void *) and returns unsigned long.
+ *
+ * Create a function with the name <class_name>_hash_code()
+ */
+typedef unsigned long (*cp_hashfunction)(void *);
+
+
+/* ------------------------------------------------------------------------ 
+ * hash function prototypes for primitives and cp_strings
+ * ------------------------------------------------------------------------ */
+
+
+/**
+ * hash function for int keys
+ * @param key pointer to the int
+ * @return hash code of the key
+ */
+CPROPS_DLL 
+unsigned long cp_hash_int(void *key);
+
+
+/**
+ * comparator for int keys
+ * @param key1 pointer the first int
+ * @param key2 pointer the second int
+ * @retval 0 if key1 equals key2;
+ * @retval <0 if key1 is less than key2;
+ * @retval >0 if key1 is greater than key2
+
+ */
+CPROPS_DLL 
+int cp_hash_compare_int(void *key1, void *key2);
+
+/**
+ * hash function for long keys
+ */
+CPROPS_DLL 
+unsigned long cp_hash_long(void *key);
+
+/**
+ * comparator for long keys
+ * 
+ * @param key1 pointer the first long
+ * @param key2 pointer the second long
+ * @retval 0 if key1 equals key2;
+ * @retval <0 if key1 is less than key2;
+ * @retval >0 if key1 is greater than key2
+ */
+CPROPS_DLL 
+int cp_hash_compare_long(void *key1, void *key2);
+
+/**
+ * hash function for pointer keys
+ */
+CPROPS_DLL 
+unsigned long cp_hash_addr(void *addr);
+
+/**
+ * comparator for pointer keys
+ * 
+ * @param key1 pointer the first pointer
+ * @param key2 pointer the second pointer
+ * @retval 0 if key1 equals key2;
+ * @retval <0 if key1 is less than key2;
+ * @retval >0 if key1 is greater than key2
+ */
+CPROPS_DLL 
+int cp_hash_compare_addr(void *key1, void *key2);
+
+/**
+ * hash function for (char *) keys
+ * @param key pointer to the cp_string
+ * @return hash code of the key
+ */
+CPROPS_DLL 
+unsigned long cp_hash_string(void *key);
+
+/**
+ * case insensitive hash function for (char *) keys
+ * @param key pointer to the cp_string
+ * @return hash code of the key
+ */
+CPROPS_DLL 
+unsigned long cp_hash_istring(void *key);
+
+
+/**
+ * copy function for cp_string copy tables
+ */
+CPROPS_DLL 
+void *cp_hash_copy_string(void *element);
+
+/**
+ * comparator for (char *) keys
+ * 
+ * @param key1 pointer to the first cp_string
+ * @param key2 pointer to the second cp_string
+ * @retval 0 if key1 equals key2
+ * @retval <>0 otherwise
+ */
+CPROPS_DLL 
+int cp_hash_compare_string(void *key1, void *key2);
+
+
+/**
+ * comparator for (char *) keys
+ * 
+ * @param key1 pointer to the first cp_string
+ * @param key2 pointer to the second cp_string
+ * @retval 0 if key1 equals key2
+ * @retval <>0 otherwise
+ */
+CPROPS_DLL 
+int cp_hash_compare_istring(void *key1, void *key2);
+
+
+
+/**
+ * Internal object that implements a key, value pair plus linked list.
+ * 
+ * Entries which are stored under the same index in the hashtable are stored
+ * in a linked list. The algorithm of the hashtable has to ensure that the lists
+ * do not get too long.
+ */
+typedef CPROPS_DLL struct _cp_hashtable_entry 
+{
+    void *key;                   /**< key (original) needed for comparisons */
+    void *value;                 /**< the item value being stored */
+    unsigned long hashcode;      /**< save calculated hash-code of the key */
+    struct _cp_hashtable_entry *next; /**< link to next entry */
+} cp_hashtable_entry;
+
+/**
+ * data structure of generic synchronized cp_hashtable
+ */
+typedef CPROPS_DLL struct _cp_hashtable
+{
+    cp_hashtable_entry **table;     /**< array of pointers to entries */
+    long table_size;                /**< size of the table */
+
+    unsigned long items;            /**< number of items in the table */
+    int mode;                       /**< collection mode @see collection.h */
+    cp_hashfunction   hash_fn;      /**< pointer to hash function */
+    cp_compare_fn     compare_fn;   /**< pointer to compare function */
+    cp_copy_fn        copy_key;     /**< pointer to key copy function */
+    cp_copy_fn        copy_value;   /**< pointer to value copy function */
+	cp_destructor_fn  free_key;
+	cp_destructor_fn  free_value;
+
+    cp_lock           *lock;        /**< lock */
+	cp_thread 		  txowner;    	/**< lock owner */
+	int				  txtype;       /**< lock type */
+
+	int min_size;					/**< table resize lower limit */
+	int fill_factor_min;			/**< minimal fill factor in percent */
+	int fill_factor_max;			/**< maximal fill factor in percent */
+
+    cp_hashtable_entry **resize_table; /**< temp table for resizing */
+    int resizing;                   /**< resize running flag */
+    unsigned long resize_len;       /**< resize table length */
+    cp_thread resize_thread;        /**< run resize in a separate thread  */
+    cp_mutex *resize_lock;			/**< for synchronizing resize operation */
+} cp_hashtable;
+
+
+/**
+ * creates a new cp_hashtable.
+ *
+ * by default there is no memory management for table content; insertion, 
+ * removal and retrieval operations are synchronized; and the table will 
+ * automatically resize when the fill factor goes over 70% or under 5%.
+ * @param size_hint an estimate for the initial storage requirements. The table 
+ *
+ * handles the storage appropriately when items become too tight. 
+ * @param hashfn a hash code function. This should ideally produce different
+ * results for different keys.
+ * @param compare_fn the comparator for your key type. 
+ * 
+ * @return a pointer to the newly created cp_hashtable.
+ */
+CPROPS_DLL 
+cp_hashtable *
+	cp_hashtable_create(unsigned long size_hint, 
+						cp_hashfunction hashfn, 
+						cp_compare_fn compare_fn);
+
+/**
+ * creates a new cp_hashtable with the specified mode.
+ */
+#define cp_hashtable_create_by_mode(mode, size_hint, cp_hashfn, compare_fn) \
+        cp_hashtable_create_by_option((mode), (size_hint), (cp_hashfn), (compare_fn), NULL, NULL, NULL, NULL)
+
+/**
+ * creates a new cp_hashtable with COLLECTION_MODE_DEEP | COLLECTION_MODE_COPY.
+ * @param size_hint an estimate for the initial storage requirements. The table 
+ * handles the storage appropriately when items become too tight. 
+ * @param hashfn a hash code function. This should ideally produce different
+ * results for different keys.
+ * @param compare_fn the comparator for your key type. 
+ * 
+ * @return a pointer to the newly created cp_hashtable.
+ */
+CPROPS_DLL 
+cp_hashtable *
+	cp_hashtable_create_copy_mode(unsigned long size_hint, 
+								  cp_hashfunction hash_fn, 
+								  cp_compare_fn compare_fn, 
+             					  cp_copy_fn copy_key, 
+								  cp_destructor_fn free_key,
+								  cp_copy_fn copy_value,
+								  cp_destructor_fn free_value);    
+
+/**
+ * create a new table, fully specifying all parameters.
+ * @param size_hint   initial capacity
+ * @param hash_fn     hash function
+ * @param compare_fn  key comparison function
+ * @param copy_key    function to return new copies of keys
+ * @param copy_value  function to return new copies of values
+ * @param mode        mode flags
+ * 
+ * @return new created cp_hashtable. Returns NULL case of error.
+ */
+CPROPS_DLL 
+cp_hashtable *
+	cp_hashtable_create_by_option(int mode, unsigned long size_hint, 
+								  cp_hashfunction hash_fn, 
+								  cp_compare_fn compare_fn, 
+								  cp_copy_fn copy_key, 
+								  cp_destructor_fn free_key,
+								  cp_copy_fn copy_value,
+								  cp_destructor_fn free_value);
+
+/**
+ * deletes a cp_hashtable according to the current mode settings
+ * @param table        object to delete
+ */
+CPROPS_DLL 
+void cp_hashtable_destroy(cp_hashtable *table);
+
+/**
+ * deletes a cp_hashtable. Pointers to the keys and values are not released. Use
+ * table if the keys and values you entered in the table should not be released
+ * by the cp_hashtable.
+ * @param table        object to delete
+ */
+CPROPS_DLL 
+void cp_hashtable_destroy_shallow(cp_hashtable *table);
+
+/**
+ * deletes a cp_hashtable. Keys and values entered in the cp_hashtable are released.
+ * @param table        object to delete
+ */
+CPROPS_DLL 
+void cp_hashtable_destroy_deep(cp_hashtable *table);
+
+
+/** 
+ * Deep destroy with custom destructors for keys and values. NULL function 
+ * pointers are not invoked. 
+ */
+CPROPS_DLL 
+void cp_hashtable_destroy_custom(cp_hashtable *table, cp_destructor_fn dk, cp_destructor_fn dv);
+
+/** 
+ * by default the get, put and remove functions as well as set and unset mode
+ * perform their own locking. Other functions do not synchronize, since it is
+ * assumed they would be called in a single cp_thread context - the initialization  * and deletion functions in particular. You can of course set 
+ * COLLECTION_MODE_NOSYNC and perform your own synchronization.<p>
+ * 
+ * The current implementation uses a queued read/write lock where blocked
+ * cp_threads are guaranteed to be woken by the order in which they attempted
+ *
+ * the following macros are defined for convenience:<p>
+ * <ul>
+ * <li> cp_hashtable_rdlock(table) - get a read lock on the table </li>
+ * <li> cp_hashtable_wrlock(table) - get a write lock on the table </li>
+ * </ul>
+ * @param table        cp_hashtable to lock
+ * @param type COLLECTION_LOCK_READ or COLLECTION_LOCK_WRITE
+ */ 
+CPROPS_DLL 
+int cp_hashtable_lock(cp_hashtable *table, int type);
+
+/** unlock the table */
+CPROPS_DLL 
+int cp_hashtable_unlock(cp_hashtable *table);
+
+/** macro to get a read lock on the table
+ */
+#define cp_hashtable_rdlock(table) cp_hashtable_lock((table), COLLECTION_LOCK_READ)
+
+/** macro to get a write lock on the table */
+#define cp_hashtable_wrlock(table) cp_hashtable_lock((table), COLLECTION_LOCK_WRITE)
+
+/**
+ * returns the current operation mode. See cp_hashtable_set_mode for a list of
+ * mode bits and their effects.
+ */
+CPROPS_DLL 
+int cp_hashtable_get_mode(cp_hashtable *table);
+
+/**
+ * set the operation mode as a bit set of the following options:
+ * <ul>
+ *  <li> COLLECTION_MODE_DEEP - release memory when removing references from table    </li>
+ *  <li> COLLECTION_MODE_MULTIPLE_PUT - allow multiple values for a key    </li>
+ *  <li> COLLECTION_MODE_COPY - keep copies rather than references    </li>
+ *  <li> COLLECTION_MODE_NOSYNC - the table will not perform its own synchronization.    </li>
+ *  <li> COLLECTION_MODE_NORESIZE - the table will not resize automatically.    </li>
+ * </ul>
+ * 
+ * The parameter bits are flipped on. If the current mode is 
+ * COLLECTION_MODE_DEEP and you want to change it, call
+ * cp_hashtable_unset_mode(table, COLLECTION_MODE_DEEP).
+ */
+CPROPS_DLL 
+int cp_hashtable_set_mode(cp_hashtable *table, int mode);
+
+
+/**
+ * unset the mode bits defined by mode
+ */
+CPROPS_DLL 
+int cp_hashtable_unset_mode(cp_hashtable *table, int mode);
+
+
+/**
+ * the internal table will not be resized to less than min_size
+ */
+CPROPS_DLL 
+int cp_hashtable_set_min_size(cp_hashtable *table, int min_size);
+
+/**
+ * a resize is triggered when the table contains more items than
+ * table_size * fill_factor / 100
+ */
+CPROPS_DLL 
+int cp_hashtable_set_max_fill_factor(cp_hashtable *table, int fill_factor);
+
+/**
+ * a resize is triggered when the table contains less items than
+ * table_size * fill_factor / 100
+ */
+CPROPS_DLL 
+int cp_hashtable_set_min_fill_factor(cp_hashtable *table, int fill_factor);
+
+/**
+ * attempts to retrieve the value assigned to the key 'key'. To return
+ * multiple values the table mode must be set to COLLECTION_MODE_MULTIPLE_VALUES, 
+ * otherwise the only first value for the given key will be returned. 
+ * @retval (void*)value to the value if found
+ * @retval NULL otherwise 
+ */
+CPROPS_DLL 
+void *cp_hashtable_get(cp_hashtable *table, void *key);
+
+/** 
+ * retrieve the value or values for key 'key'. the 'mode' parameter sets the
+ * mode for the current operation.
+ */
+CPROPS_DLL 
+void *cp_hashtable_get_by_option(cp_hashtable *table, void *key, int mode);
+
+/**
+ * Internal put method. 
+ */
+CPROPS_DLL 
+void *cp_hashtable_put_by_option(cp_hashtable *table, void *key, void *value, int mode);
+
+/**
+ * the key 'key' will be assigned to the value 'value'. The new value will 
+ * override an old value if one exists. The old value will not be deallocated.
+ * If you would need the old value to be released call cp_hashtable_put_safe instead.
+ */
+CPROPS_DLL 
+void *cp_hashtable_put(cp_hashtable *table, void *key, void *value);
+
+/**
+ * same as cp_hashtable_put(table, key, value) except that an old value is released if it
+ * exists.
+ */
+CPROPS_DLL 
+void *cp_hashtable_put_safe(cp_hashtable *table, void *key, void *value);
+
+/**
+ * same as cp_hashtable_put(table, key, value) except that it inserts a copy
+ * of the key and the value object.
+ */
+CPROPS_DLL 
+void *cp_hashtable_put_copy(cp_hashtable *table, void *key, void *value);
+
+/**
+ * Attempts to remove the mapping for key from the table.
+ *
+ * @param table   the object
+ * @param key    Key to search for.
+ * @retval value retrieved by the key (that was removed)
+ * @retval NULL  if the table does not contain the requested key.
+ */
+CPROPS_DLL 
+void *cp_hashtable_remove(cp_hashtable *table, void *key);
+
+/** remove all entries with current mode */
+CPROPS_DLL 
+int cp_hashtable_remove_all(cp_hashtable *table);
+
+/**
+ * removes a mapping from the table, and deallocates the memory for the mapped
+ * key and value.
+ * 
+ * @param table   the object
+ * @param key    Key to search for.
+ * @return 1 if the operation was successful, 0 otherwise
+ */
+CPROPS_DLL 
+int cp_hashtable_remove_deep(cp_hashtable *table, void *key);
+
+/**
+ * Check if there is an entry with matching key.
+ *
+ * @param table   the object
+ * @param key    Key to search for.
+ * @return 1 if table contains key, 0 otherwise
+ */
+CPROPS_DLL 
+int cp_hashtable_contains(cp_hashtable *table, void *key);
+
+/**
+ * get an array containing all keys mapped in table table.
+ * @note It is the responsibility of the caller to free the returned array. 
+ * @note The keys themselves must not be changed or deleted (read-only).
+ */
+CPROPS_DLL 
+void **cp_hashtable_get_keys(cp_hashtable *table);
+
+/**
+ * get an array containing all values in the table.
+ * @note It is the responsibility of the caller to free the returned array. 
+ * @note The values themselves must not be changed or deleted (read-only).
+ */
+CPROPS_DLL 
+void **cp_hashtable_get_values(cp_hashtable *table);
+
+/**
+ * Get the number of entries in the collection.
+ * @return the number of key mappings currently in the table.
+ */
+CPROPS_DLL 
+unsigned long cp_hashtable_count(cp_hashtable *table);
+
+/**
+ * Check if the collection is empty.
+ * @retval true/1 if the collection is empty
+ * @retval false/0 if the collection has entries
+ */
+#define cp_hashtable_is_empty(table) (cp_hashtable_count(table) == 0)
+
+/**
+ * @return a prime greater than <code>size_request</code>
+ */
+CPROPS_DLL 
+unsigned long cp_hashtable_choose_size(unsigned long size_request);
+
+__END_DECLS
+/** @} */
+#endif
+


Property changes on: branches/multicore/numpy/core/cprops_thread/hashtable.h
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/multicore/numpy/core/cprops_thread/linked_list.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/linked_list.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/linked_list.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,1072 @@
+/**
+ * @addtogroup cp_list
+ */
+/** @{ */
+/**
+ * @file
+ * Implementation of cp_list Collection with linked elements and
+ * cp_list_iterator.
+ * 
+ * The elements are stored in cp_list_entry objects.
+ *
+ * @copydoc collection
+ */
+/* ----------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "linked_list.h"
+
+/* fwd declarations of internal locking functions */
+int cp_list_txlock(cp_list *list, int type);
+/* fwd declarations of internal locking functions */
+int cp_list_txunlock(cp_list *list);
+
+/**
+ * Creates an entry with the mode of the list.
+ *
+ * The new entry is not added to the list.
+ * If the list has copy mode, it copies the item and puts the copy into the
+ * new entry.
+ *
+ * @return entry object for the item.
+ */
+static cp_list_entry *cp_list_create_entry(cp_list *list, void *item);
+
+//static void cp_list_destroy_entry(cp_list *list, cp_list_entry *entry);
+
+/**
+ * Unsynchronized and unchecked insert a new element at the beginning
+ * of the list.
+ */
+static cp_list_entry *cp_list_insert_internal(cp_list *list, void *item);
+
+/**
+ * Unsynchronized and unchecked remove the entry from the list.
+ */
+static cp_list_entry *cp_list_remove_internal(cp_list *list, cp_list_entry *entry);
+
+/**
+ * Appends the element and returns the Entry.
+ */
+static cp_list_entry *cp_list_append_internal(cp_list *list, void *item);
+
+/**
+ * Removes the first entry from the list and returns it.
+ *
+ * Sets the references into a consistent state.
+ */
+static cp_list_entry *cp_list_remove_head_internal(cp_list *list);
+
+/**
+ * Removes the last entry from the list and returns it.
+ *
+ * Sets the references into a consistent state.
+ */
+static cp_list_entry *cp_list_remove_tail_internal(cp_list *list);
+
+
+cp_list *cp_list_create_internal(int mode, 
+								 cp_compare_fn compare_fn,
+								 cp_copy_fn copy_fn,
+								 cp_destructor_fn item_destructor,
+								 int is_view)
+{
+    cp_list *list = NULL;
+
+    list = (cp_list *) calloc(1, sizeof(cp_list));
+    if (list == NULL) 
+	{
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    list->head       = NULL;
+    list->tail       = NULL;
+    list->compare_fn = compare_fn;
+    list->copy_fn    = copy_fn;
+	list->free_fn	 = item_destructor;
+    list->mode       = mode;
+    list->items      = 0;
+
+	list->is_view    = is_view;
+
+	if (!(mode & COLLECTION_MODE_NOSYNC) && !is_view)
+	{
+		list->lock = malloc(sizeof(cp_lock));
+		if (list->lock == NULL)
+		{
+			free(list);
+			errno = ENOMEM;
+			return NULL;
+		}
+		if (cp_lock_init(list->lock, NULL))
+		{
+			free(list->lock);
+			free(list);
+			return NULL;
+		}
+	}
+
+    return list;
+}
+
+cp_list *cp_list_create()
+{
+	return 
+		cp_list_create_internal(COLLECTION_MODE_MULTIPLE_VALUES,
+				NULL, NULL, NULL, 0);
+}
+
+cp_list *cp_list_create_nosync()
+{
+	return 
+		cp_list_create_internal(COLLECTION_MODE_MULTIPLE_VALUES |
+							    COLLECTION_MODE_NOSYNC, 
+								NULL, NULL, NULL, 0);
+}
+
+cp_list *cp_list_create_list(int mode, 
+							 cp_compare_fn compare_fn, 
+							 cp_copy_fn copy_fn,
+							 cp_destructor_fn item_destructor)
+{
+	return 
+		cp_list_create_internal(mode, compare_fn, copy_fn, item_destructor, 0);
+}
+
+
+cp_list *cp_list_create_view(int mode, 
+							 cp_compare_fn compare_fn, 
+							 cp_copy_fn copy_fn,
+							 cp_destructor_fn item_destructor,
+							 cp_lock *lock)
+{
+	cp_list *list = 
+		cp_list_create_internal(mode, compare_fn, copy_fn, item_destructor, 1);
+
+	list->lock = lock; //~~ test
+
+	return list;
+}
+
+/* 
+ * locking provides some protection if the list is being destroyed while it is
+ * still in use. However if the lock causes a different thread to block the 
+ * other thread is likely to crash when releasing the lock which will possibly
+ * have been deallocated in the meanwhile. It is the applications 
+ * responsibility to assure the list isn't being accessed and destroyed in
+ * different threads simultaneously.
+ */
+void cp_list_destroy_internal(cp_list *list, cp_destructor_fn fn, int mode)
+{
+    cp_list_entry *curr, *next;
+	int shared_pool;
+
+	cp_list_txlock(list, COLLECTION_LOCK_WRITE);
+	
+	shared_pool = list->mempool && list->mempool->refcount > 1;
+		
+    curr = list->head;
+    while (curr) 
+	{
+        next = curr->next;
+        if ((mode & COLLECTION_MODE_DEEP) && fn)
+			(*fn)(curr->item);
+		if (list->mempool) 
+		{
+			if (shared_pool)
+				cp_mempool_free(list->mempool, curr);
+		}
+		else
+			free(curr);
+        curr = next;
+    }
+	cp_list_txunlock(list);
+	
+	if (list->lock && !list->is_view)
+	{
+		cp_lock_destroy(list->lock);
+		free(list->lock);
+	}
+
+	if (list->mempool) cp_mempool_destroy(list->mempool);
+
+    free(list);
+}
+
+void cp_list_destroy(cp_list *list)
+{
+    cp_list_destroy_internal(list, list->free_fn, list->mode);
+}
+
+void cp_list_destroy_by_option(cp_list *list, int option)
+{
+	cp_list_destroy_internal(list, list->free_fn, option);
+}
+
+void cp_list_destroy_custom(cp_list *list, cp_destructor_fn fn)
+{
+    cp_list_destroy_internal(list, fn, list->mode | COLLECTION_MODE_DEEP);
+}
+
+long cp_list_item_count(cp_list *list)
+{
+    return (list == NULL) ? 0 : list->items;
+}
+
+
+static cp_list_entry **cp_list_get_entry_ref(cp_list *list, void *item)
+{
+    cp_list_entry **here = &list->head;
+
+    while (*here != NULL && (*list->compare_fn)(item, (*here)->item)) 
+        here = &(*here)-> next;
+
+    return here;
+}
+
+void *cp_list_insert(cp_list *list, void *item)
+{
+    cp_list_entry *entry, **lookup;
+    void *res = NULL;
+
+    if (cp_list_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    entry = NULL;
+    if (!(list->mode & COLLECTION_MODE_MULTIPLE_VALUES)) 
+	{
+        lookup = cp_list_get_entry_ref(list, item);
+        if (lookup) entry = *lookup;
+    }
+    if (entry == NULL) entry = cp_list_insert_internal(list, item);
+    if (entry) res = entry->item;
+
+    cp_list_txunlock(list);
+    
+    return res;
+}
+
+void *cp_list_remove(cp_list *list, void *item)
+{
+    void *res = NULL;
+    cp_list_entry *here, *curr;
+	int mvalbit = list->mode & COLLECTION_MODE_MULTIPLE_VALUES;
+	int deepbit = list->mode & COLLECTION_MODE_DEEP;
+
+    if (cp_list_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    here = list->head;
+    while (here != NULL) 
+	{
+        curr = here;
+        here = here->next;
+        if ((*list->compare_fn)(item, curr->item) == 0) 
+		{
+            cp_list_remove_internal(list, curr);
+            if (deepbit && list->free_fn) (*list->free_fn)(curr->item);
+			if (list->mempool)
+				cp_mempool_free(list->mempool, curr);
+			else
+	            free(curr);
+    
+            if (!mvalbit) break;
+        }
+    }
+
+    cp_list_txunlock(list);
+
+    return res;
+}
+
+void *cp_list_insert_after(cp_list *list, void *item, void *existing)
+{
+    cp_list_entry **here, *entry;
+
+    if (cp_list_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    if (!(list->mode) & COLLECTION_MODE_MULTIPLE_VALUES) 
+	{
+        here = cp_list_get_entry_ref(list, item);
+        if (*here != NULL) 
+		{
+            cp_list_txunlock(list);
+            return (*here)->item;
+        }
+    }
+
+    entry = cp_list_create_entry(list, item);
+    if (entry == NULL) 
+	{
+        cp_list_txunlock(list);
+        return NULL;
+    }
+
+    here = cp_list_get_entry_ref(list, existing);
+
+    if (*here == NULL) /* no match - append to end of list */
+		here = &list->tail;
+
+	entry->prev = *here;
+	entry->next = (*here)->next;
+   	(*here)->next = entry;
+
+	if (entry->next) 
+		entry->next->prev = entry;
+	else
+		list->tail = entry;
+    
+    list->items++;
+    
+    cp_list_txunlock(list);
+
+    return entry->item;
+}
+
+void *cp_list_insert_before(cp_list *list, void *item, void *existing)
+{
+    cp_list_entry **here, *entry;
+
+    if (cp_list_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    if (!(list->mode) & COLLECTION_MODE_MULTIPLE_VALUES) 
+	{
+        here = cp_list_get_entry_ref(list, item);
+        if (*here != NULL) 
+		{
+            cp_list_txunlock(list);
+            return (*here)->item;
+        }
+    }
+
+    entry = cp_list_create_entry(list, item);
+    if (entry == NULL) 
+	{
+        cp_list_txunlock(list);
+        return NULL;
+    }
+
+    here = cp_list_get_entry_ref(list, existing);
+
+    if (*here == NULL) /* no match - insert at top of list */
+		here = &list->head;
+		
+	entry->next = *here;
+	entry->prev = (*here)->prev;
+	(*here)->prev = entry;
+	if (entry->prev)
+		entry->prev->next = entry;
+	else
+		list->head = entry;
+
+    list->items++;
+        
+    cp_list_txunlock(list);
+
+    return entry->item;
+}
+
+void *cp_list_search(cp_list *list, void *item)
+{
+    cp_list_entry **here;
+    void *res;
+
+    if (cp_list_txlock(list, COLLECTION_LOCK_READ)) return NULL;
+
+    here = cp_list_get_entry_ref(list, item);
+    res = *here ? (*here)->item : NULL;
+
+    cp_list_txunlock(list);
+    
+    return res;
+}
+
+int cp_list_callback(cp_list *l, int (*item_action)(void *, void *), void *id)
+{
+	int rc = 0;
+	cp_list_entry *curr;
+
+	if ((rc = cp_list_txlock(l, COLLECTION_LOCK_READ))) return rc;
+
+	for (curr = l->head; curr; curr = curr->next)
+		if ((rc = (*item_action)(curr->item, id)))
+			break;
+
+	cp_list_txunlock(l);
+
+	return rc;
+}
+
+
+void *cp_list_append(cp_list *list, void *item)
+{
+    cp_list_entry **lookup, *entry;
+    void *res = NULL;
+
+    if (cp_list_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    if (!(list->mode & COLLECTION_MODE_MULTIPLE_VALUES)) 
+	{
+        lookup = cp_list_get_entry_ref(list, item);
+        if (lookup != NULL) 
+		{
+            cp_list_txunlock(list);
+            return (*lookup)->item;
+        }
+    }
+
+    entry = cp_list_append_internal(list, item);
+    if (entry) res = entry->item;
+
+    cp_list_txunlock(list);
+
+    return res;
+}
+
+void *cp_list_get_head(cp_list *list)
+{
+    void *item = NULL;
+        
+    if (cp_list_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+    if (list->head) item = list->head->item;
+    cp_list_txunlock(list);
+
+    return item;
+}
+
+void *cp_list_get_tail(cp_list *list)
+{
+    void *item = NULL;
+        
+    if (cp_list_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+    if (list->tail) item = list->tail->item;
+    cp_list_txunlock(list);
+
+    return item;
+}
+
+
+void *cp_list_remove_head(cp_list *list)
+{
+    cp_list_entry *old_head;
+    void *res = NULL;
+    
+	if (cp_list_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+	   
+    old_head = cp_list_remove_head_internal(list);
+    if (old_head) 
+	{
+        res = old_head->item;
+		if ((list->mode & COLLECTION_MODE_DEEP) && list->free_fn)
+			(*list->free_fn)(old_head->item);
+		if (list->mempool)
+			cp_mempool_free(list->mempool, old_head);
+		else
+			free(old_head);
+    }
+
+    cp_list_txunlock(list);
+
+    return res;
+}
+
+void *cp_list_remove_tail(cp_list *list)
+{
+    cp_list_entry *old_tail;
+    void *res = NULL;
+
+    if (cp_list_txlock(list, COLLECTION_LOCK_WRITE)) return NULL;
+
+    old_tail = cp_list_remove_tail_internal(list);
+    if (old_tail) 
+	{
+        res = old_tail->item;
+		if (list->mempool)
+			cp_mempool_free(list->mempool, old_tail);
+		else
+	        free(old_tail);
+    }
+
+    cp_list_txunlock(list);
+
+    return res;
+}
+
+
+int cp_list_is_empty(cp_list *list)
+{
+    int empty = 0;
+
+    cp_list_txlock(list, COLLECTION_LOCK_READ);
+    empty = list->head == NULL;
+   cp_list_txunlock(list);
+
+    return empty;
+}
+
+int cp_list_lock_internal(cp_list *list, int mode)
+{
+    int rc;
+
+    if (mode == COLLECTION_LOCK_READ) 
+		rc = cp_lock_rdlock(list->lock);
+    else
+		rc = cp_lock_wrlock(list->lock);
+
+    return rc;
+}
+
+int cp_list_unlock_internal(cp_list *list)
+{
+    return cp_lock_unlock(list->lock);
+}
+
+int cp_list_txlock(cp_list *list, int type)
+{
+	if (list->mode & COLLECTION_MODE_NOSYNC) return 0;
+	if (list->mode & COLLECTION_MODE_IN_TRANSACTION && 
+		list->txtype == COLLECTION_LOCK_WRITE)
+	{
+		cp_thread self = cp_thread_self();
+		if (cp_thread_equal(self, list->txowner)) return 0;
+	}
+	return cp_list_lock_internal(list, type);
+}
+
+int cp_list_txunlock(cp_list *list)
+{
+	if (list->mode & COLLECTION_MODE_NOSYNC) return 0;
+	if (list->mode & COLLECTION_MODE_IN_TRANSACTION && 
+		list->txtype == COLLECTION_LOCK_WRITE)
+	{
+		cp_thread self = cp_thread_self();
+		if (cp_thread_equal(self, list->txowner)) return 0;
+	}
+	return cp_list_unlock_internal(list);
+}
+
+/* lock and set the transaction indicators */
+int cp_list_lock(cp_list *list, int type)
+{
+	int rc;
+	if ((list->mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
+	if ((rc = cp_list_lock_internal(list, type))) return rc;
+	list->txtype = type;
+	list->txowner = cp_thread_self();
+	list->mode |= COLLECTION_MODE_IN_TRANSACTION;
+	return 0;
+}
+
+/* unset the transaction indicators and unlock */
+int cp_list_unlock(cp_list *list)
+{
+	cp_thread self = cp_thread_self();
+	if (list->txowner == self)
+	{
+		list->txtype = 0;
+		list->txowner = 0;
+		list->mode ^= COLLECTION_MODE_IN_TRANSACTION;
+	}
+	else if (list->txtype == COLLECTION_LOCK_WRITE) 
+		return -1;
+
+	return cp_list_unlock_internal(list);
+}
+
+/* get the current collection mode */
+int cp_list_get_mode(cp_list *list)
+{
+    return list->mode;
+}
+
+/* set mode bits on the list mode indicator */
+int cp_list_set_mode(cp_list *list, int mode)
+{
+	int nosync;
+
+	/* can't set NOSYNC in the middle of a transaction */
+	if ((list->mode & COLLECTION_MODE_IN_TRANSACTION) && 
+		(mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
+	
+	nosync = list->mode & COLLECTION_MODE_NOSYNC;
+	if (!nosync)
+		if (cp_list_txlock(list, COLLECTION_LOCK_WRITE))
+			return -1;
+
+	list->mode |= mode;
+
+	if (!nosync)
+		cp_list_txunlock(list);
+
+	return 0;
+}
+
+/* unset mode bits on the list mode indicator. if unsetting 
+ * COLLECTION_MODE_NOSYNC and the list was not previously synchronized, the 
+ * internal synchronization structure is initalized.
+ */
+int cp_list_unset_mode(cp_list *list, int mode)
+{
+	int nosync = list->mode & COLLECTION_MODE_NOSYNC;
+
+	if (!nosync)
+		if (cp_list_txlock(list, COLLECTION_LOCK_WRITE))
+			return -1;
+	
+	/* handle the special case of unsetting COLLECTION_MODE_NOSYNC */
+	if ((mode & COLLECTION_MODE_NOSYNC) && list->lock == NULL)
+	{
+		/* list can't be locked in this case, no need to unlock on failure */
+		if ((list->lock = malloc(sizeof(cp_lock))) == NULL)
+			return -1; 
+		if (cp_lock_init(list->lock, NULL))
+			return -1;
+	}
+	
+	/* unset specified bits */
+    list->mode &= list->mode ^ mode;
+	if (!nosync)
+		cp_list_txunlock(list);
+
+	return 0;
+}
+
+/* set list to use given mempool or allocate a new one if pool is NULL */
+int cp_list_use_mempool(cp_list *list, cp_mempool *pool)
+{
+	int rc = 0;
+	
+	if ((rc = cp_list_txlock(list, COLLECTION_LOCK_WRITE))) return rc;
+	
+	if (pool)
+	{
+		if (pool->item_size < sizeof(cp_list_entry))
+		{
+			rc = EINVAL;
+			goto DONE;
+		}
+		if (list->mempool) 
+		{
+			if (list->items) 
+			{
+				rc = ENOTEMPTY;
+				goto DONE;
+			}
+			cp_mempool_destroy(list->mempool);
+		}
+		cp_mempool_inc_refcount(pool);
+		list->mempool = pool;
+	}
+	else
+	{
+		list->mempool = 
+			cp_mempool_create_by_option(COLLECTION_MODE_NOSYNC, 
+										sizeof(cp_list_entry), 0);
+		if (list->mempool == NULL) 
+		{
+			rc = ENOMEM;
+			goto DONE;
+		}
+	}
+
+DONE:
+	cp_list_txunlock(list);
+	return rc;
+}
+
+
+/* set list to use a shared memory pool */
+int cp_list_share_mempool(cp_list *list, cp_shared_mempool *pool)
+{
+	int rc;
+
+	if ((rc = cp_list_txlock(list, COLLECTION_LOCK_WRITE))) return rc;
+
+	if (list->mempool)
+	{
+		if (list->items)
+		{
+			rc = ENOTEMPTY;
+			goto DONE;
+		}
+
+		cp_mempool_destroy(list->mempool);
+	}
+
+	list->mempool = cp_shared_mempool_register(pool, sizeof(cp_list_entry));
+	if (list->mempool == NULL) 
+	{
+		rc = ENOMEM;
+		goto DONE;
+	}
+	
+DONE:
+	cp_list_txunlock(list);
+	return rc;
+}
+
+
+/****************************************************************************
+ *                                                                          *
+ *                    cp_list_iterator implementation                       *
+ *                                                                          *
+ ****************************************************************************/
+ 
+cp_list_iterator* cp_list_create_iterator(cp_list *list, int type)
+{
+    int rc = - 1;
+    cp_list_iterator *iterator = (cp_list_iterator *) malloc(sizeof(cp_list_iterator));
+    iterator->list = list;
+    iterator->pos = &list->head;
+    iterator->lock_type = type;
+
+	rc = cp_list_txlock(list, type);
+	if (rc) /* locking failed */
+	{
+		free(iterator);
+		iterator = NULL;
+	}
+
+    return iterator;
+}
+
+int cp_list_iterator_init(cp_list_iterator *iterator, cp_list *list, int type)
+{
+    iterator->list = list;
+    iterator->pos = &list->head;
+    iterator->lock_type = type;
+	return cp_list_txlock(list, type);
+}
+
+
+int cp_list_iterator_head(cp_list_iterator *iterator)
+{
+    if (iterator == NULL) return -1;
+    iterator->pos = &iterator->list->head;
+
+    return 0;
+}
+
+int cp_list_iterator_tail(cp_list_iterator *iterator)
+{
+    if (iterator == NULL) return -1;
+    iterator->pos = &iterator->list->tail;
+
+    return 0;
+}
+
+int cp_list_iterator_init_tail(cp_list_iterator *iterator, 
+							   cp_list *list, 
+							   int type)
+{
+    iterator->list = list;
+    iterator->pos = &list->tail;
+    iterator->lock_type = type;
+	return cp_list_txlock(list, type);
+}
+
+int cp_list_iterator_release(cp_list_iterator *iterator)
+{
+	int rc = 0;
+    if (iterator->lock_type != COLLECTION_LOCK_NONE) 
+		rc = cp_list_txunlock(iterator->list);
+
+    return rc;
+}
+
+int cp_list_iterator_destroy(cp_list_iterator *iterator)
+{
+    int rc = cp_list_iterator_release(iterator);
+    free(iterator);
+
+    return rc;
+}
+
+void *cp_list_iterator_next(cp_list_iterator *iterator)
+{
+    void *item = NULL;
+
+    if (*(iterator->pos)) 
+	{
+        item = (*iterator->pos)->item;
+        iterator->pos = &(*(iterator->pos))->next;
+    }
+	else if (iterator->list->head && 
+			 iterator->pos == &iterator->list->head->prev)
+	{
+		item = iterator->list->head;
+		iterator->pos = &iterator->list->head;
+	}
+
+    return item;
+}
+
+void *cp_list_iterator_prev(cp_list_iterator *iterator)
+{
+    void *item = NULL;
+
+    if (*iterator->pos) 
+	{
+        item = (*iterator->pos)->item;
+        iterator->pos = &(*iterator->pos)->prev;
+    }
+	else if (iterator->list->tail && 
+			 iterator->pos == &iterator->list->tail->next)
+	{
+		item = iterator->list->tail->item;
+		iterator->pos = &iterator->list->tail->prev;
+	}
+
+    return item;
+}
+
+void *cp_list_iterator_curr(cp_list_iterator *iterator)
+{
+    void *item = NULL;
+
+    if (*iterator->pos)
+        item = (*iterator->pos)->item;
+
+    return item;
+}
+
+void *cp_list_iterator_insert(cp_list_iterator *iterator, void *item)
+{
+	void *new_item = NULL;
+
+	if ((iterator->list->mode & COLLECTION_MODE_NOSYNC) || 
+		(iterator->lock_type == COLLECTION_LOCK_WRITE))
+	{
+		cp_list_entry *entry = cp_list_create_entry(iterator->list, item);
+		if (entry == NULL) return NULL;
+		new_item = entry->item;
+		
+		entry->next = *iterator->pos;
+
+		if (*iterator->pos)
+		{
+			entry->prev = (*iterator->pos)->prev;
+			(*iterator->pos)->prev = entry;
+			if (entry->prev)
+				entry->prev->next = entry;
+		}
+		else if (iterator->list->head == NULL) /* iterator not pointing at much - list may be empty */
+			iterator->list->head = iterator->list->tail = entry;
+		else if (iterator->pos == &iterator->list->head->prev) /* iterator moved before head */
+		{
+			entry->prev = NULL;
+			entry->next = iterator->list->head;
+			entry->next->prev = entry;
+			iterator->list->head = entry;
+		}
+		else /* iterator moved after tail */
+		{
+			entry->prev = iterator->list->tail;
+			entry->prev->next = entry;
+			iterator->list->tail = entry;
+		}
+
+		iterator->pos =  &entry->next; /* keep iterator at same position */
+		iterator->list->items++;
+	}
+	else /* mode is not NOSYNC and no LOCK_WRITE */
+		errno = EINVAL;
+
+	return new_item;
+}
+
+void *cp_list_iterator_append(cp_list_iterator *iterator, void *item)
+{
+	void *new_item = NULL;
+
+	if ((iterator->list->mode & COLLECTION_MODE_NOSYNC) || 
+		(iterator->lock_type == COLLECTION_LOCK_WRITE))
+	{
+		cp_list_entry *entry = cp_list_create_entry(iterator->list, item);
+		if (entry == NULL) return NULL;
+		new_item = entry->item;
+		
+		entry->prev = *iterator->pos;
+
+		if (*iterator->pos)
+		{
+			entry->next = (*iterator->pos)->next;
+			(*iterator->pos)->next = entry;
+			if (entry->next)
+				entry->next->prev = entry;
+		}
+		else if (iterator->list->tail == NULL) /* iterator not pointing at much - list may be empty */
+			iterator->list->tail = iterator->list->head = entry;
+		else if (iterator->pos == &iterator->list->tail->next) /* iterator moved after tail */
+		{
+			entry->next = NULL;
+			entry->prev = iterator->list->tail;
+			entry->prev->next = entry;
+			iterator->list->tail = entry;
+		}
+		else /* iterator moved before head */
+		{
+			entry->next = iterator->list->head;
+			entry->next->prev = entry;
+			iterator->list->head = entry;
+		}
+
+		iterator->pos = &entry->prev; /* keep iterator at same position */
+		iterator->list->items++;
+	}
+	else /* mode is not NOSYNC and no LOCK_WRITE */
+		errno = EINVAL;
+
+	return new_item;
+}
+
+void *cp_list_iterator_remove(cp_list_iterator *iterator)
+{
+	void *rm_item = NULL;
+
+	if ((iterator->list->mode & COLLECTION_MODE_NOSYNC) || 
+		(iterator->lock_type == COLLECTION_LOCK_WRITE))
+	{
+		if (*iterator->pos)
+		{
+			cp_list_entry *curr = *iterator->pos;
+			if (curr->prev)
+				iterator->pos = &curr->prev->next;
+			else if (curr->prev)
+				iterator->pos = &curr->next->prev;
+			else /* removing last item */
+				iterator->pos = &iterator->list->head;
+
+			cp_list_remove_internal(iterator->list, curr);
+            if (iterator->list->mode & COLLECTION_MODE_DEEP && 
+				iterator->list->free_fn) (*iterator->list->free_fn)(curr->item);
+			if (iterator->list->mempool)
+				cp_mempool_free(iterator->list->mempool, curr);
+			else
+	            free(curr);
+		}
+	}
+
+	return rm_item;
+}
+
+
+
+
+/* ----------------------------------------------------------------- */
+/** @} */
+
+static cp_list_entry *cp_list_create_entry(cp_list *list, void *item)
+{
+    cp_list_entry *entry;
+	
+	if (list->mempool)
+		entry = (cp_list_entry *) cp_mempool_calloc(list->mempool);
+	else
+		entry = (cp_list_entry *) calloc(1, sizeof(cp_list_entry));
+
+    if (entry == NULL) 
+	{
+        errno = ENOMEM;
+        return NULL;
+    }
+    entry->item = (list->mode & COLLECTION_MODE_COPY) ? (*list->copy_fn)(item) : item;
+
+    return entry;
+}
+
+static cp_list_entry *cp_list_insert_internal(cp_list *list, void *item)
+{
+    cp_list_entry *entry;
+
+    entry = cp_list_create_entry(list, item);
+    if (entry == NULL) return NULL;
+
+    entry->next = list->head;
+    list->head = entry;
+    if (entry->next) entry->next->prev = entry;
+    if (list->tail == NULL) list->tail = entry;
+
+    list->items++;
+
+    return entry;
+}
+
+static cp_list_entry *
+	cp_list_remove_internal(cp_list *list, cp_list_entry *entry)
+{
+    if (entry->prev) 
+		entry->prev->next = entry->next;
+    else
+		list->head = entry->next;
+
+    if (entry->next)
+		entry->next->prev = entry->prev;
+    else
+		list->tail = entry->prev;
+
+    list->items--;
+
+    return entry;
+}
+
+static cp_list_entry *cp_list_append_internal(cp_list *list, void *item)
+{
+    cp_list_entry *entry;
+
+    entry = cp_list_create_entry(list, item);
+    if (entry == NULL) return NULL;
+
+    entry->prev = list->tail;
+    list->tail = entry;
+
+    if (entry->prev) entry->prev->next = entry;
+
+    if (list->head == NULL) list->head = entry;
+
+    list->items++;
+
+    return entry;
+}
+
+static cp_list_entry *cp_list_remove_head_internal(cp_list *list)
+{
+    cp_list_entry *old_head;
+
+    old_head = list->head;
+    if (old_head) 
+	{
+        list->head = list->head->next;
+
+        if (list->head == NULL) 
+			list->tail = NULL;
+        else
+			list->head->prev = NULL;
+
+        list->items--;
+    }
+
+    return old_head;
+}
+
+static cp_list_entry *cp_list_remove_tail_internal(cp_list *list)
+{
+    cp_list_entry *old_tail;
+
+    old_tail = list->tail;
+    if (old_tail) 
+	{
+        list->tail = list->tail->prev;
+
+        if (list->tail == NULL) 
+			list->head = NULL;
+        else
+			list->tail->next = NULL;
+
+        list->items--;
+    }
+
+    return old_tail;
+}
+

Added: branches/multicore/numpy/core/cprops_thread/linked_list.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/linked_list.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/linked_list.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,364 @@
+#ifndef _CP_LINKEDLIST_H
+#define _CP_LINKEDLIST_H
+
+/** @{ */
+/**
+ * @file
+ *
+ * linked list definitions
+ */
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+#include "cp_config.h"
+#include "collection.h"
+#include "mempool.h"
+
+/**
+ * Internal object that references the content and links to the neighbour
+ * entries.
+ */
+typedef CPROPS_DLL struct _cp_list_entry
+{
+    void *item; /**< stored element (content) */
+    struct _cp_list_entry *next; /**< link to next entry */
+    struct _cp_list_entry *prev; /**< link to previous entry */
+} cp_list_entry;
+
+/**
+ * doubly linked list type. 
+ */
+typedef CPROPS_DLL struct _cp_list
+{
+	cp_list_entry *head;  		/**< link to beginning of list */
+	cp_list_entry *tail;  		/**< link to end of list       */
+
+	cp_compare_fn compare_fn;  	/**< comparison method 		   */
+	cp_copy_fn copy_fn; 		/**< copy method */
+	cp_destructor_fn free_fn; 	/**< item destructor */
+
+	int mode;                 	/**< operation mode (see collection.h) */
+	cp_thread txowner; 			/**< current lock owner */
+
+	long items;               	/**< number of elements in list */
+
+	int is_view; 				/**< views don't have their own lock */
+	cp_lock *lock;    			/**< lock */
+	int txtype;                 /**< lock type */
+
+	cp_mempool *mempool; 		/**< optional memory pool */
+} cp_list;
+
+/**
+ * iterator helper-class of cp_list.
+ */
+typedef CPROPS_DLL struct _cp_list_iterator
+{
+	cp_list *list;           /**< link to the list */
+	cp_list_entry **pos;     /**< current position */
+
+	int lock_type;           /**< locking mode */
+} cp_list_iterator;
+
+
+/** Default constructor */
+CPROPS_DLL 
+cp_list *cp_list_create();
+
+CPROPS_DLL 
+cp_list *cp_list_create_nosync();
+
+/**
+ * Constructor
+ *
+ * @param mode operation mode bitmap (see collection.h)
+ * @param compare_fn  compare method
+ * @param copy_fn copy method
+ */
+CPROPS_DLL 
+cp_list *cp_list_create_list(int mode, 
+							 cp_compare_fn compare_fn, 
+							 cp_copy_fn copy_fn, 
+							 cp_destructor_fn item_destructor);
+
+CPROPS_DLL 
+cp_list *cp_list_create_view(int mode, 
+							 cp_compare_fn compare_fn, 
+							 cp_copy_fn copy_fn,
+							 cp_destructor_fn item_destructor,
+							 cp_lock *lock);
+
+/**
+ * Destroy the object with the mode stored in the list.
+ */
+CPROPS_DLL 
+void cp_list_destroy(cp_list *);
+
+/**
+ * Destroy the object with the specified mode (override default).
+ */
+CPROPS_DLL 
+void cp_list_destroy_by_option(cp_list *list, int option);
+
+/**
+ * Destroy the object and all contained elements.
+ * For each element the method cp_destructor_fn is called. 
+ */
+CPROPS_DLL 
+void cp_list_destroy_custom(cp_list *list, cp_destructor_fn fn);
+
+/**
+ * Insert a new element at the beginning of the list.
+ * The operation is synchronized according to the properties of the object.
+ */
+CPROPS_DLL 
+void *cp_list_insert(cp_list *list, void *item);
+
+/**
+ * Remove the element from the list.
+ * The operation is synchronized according to the properties of the object.
+ */
+CPROPS_DLL 
+void *cp_list_remove(cp_list *list, void *item);
+
+/**
+ * Insert the element after an existing one.
+ */
+CPROPS_DLL 
+void *cp_list_insert_after(cp_list *list, void *item, void *existing);
+
+/**
+ * Insert the element before an existing one.
+ */
+CPROPS_DLL 
+void *cp_list_insert_before(cp_list *list, void *item, void *existing);
+
+/**
+ * Get the first element that equals the parameter.
+ */
+CPROPS_DLL 
+void *cp_list_search(cp_list *list, void *item);
+
+/**
+ * run a callback on each item. Stops if the callback function returns
+ * non-zero.
+ */
+CPROPS_DLL 
+int cp_list_callback(cp_list *l, int (*item_action)(void *, void *), void *id);
+
+/**
+ * Append the element at the end of the list.
+ *
+ * @retval item the appended item.
+ * @retval existing_item if multiple values not allowed and an equal item already exists. 
+ */
+CPROPS_DLL 
+void *cp_list_append(cp_list *list, void *item);
+
+/**
+ * Returns the first element of the list.
+ */
+CPROPS_DLL 
+void *cp_list_get_head(cp_list *list);
+
+/**
+ * Returns the last element of the list.
+ */
+CPROPS_DLL 
+void *cp_list_get_tail(cp_list *list);
+
+/**
+ * remove and release first entry
+ *
+ * @return previous list head
+ */
+CPROPS_DLL 
+void *cp_list_remove_head(cp_list *list);
+
+/**
+ * remove and release last entry 
+ *
+ * @return Element that was stored in the last entry.
+ */
+CPROPS_DLL 
+void *cp_list_remove_tail(cp_list *list);
+
+/**
+ * Test if object is empty.
+ *
+ * @retval true if no element contained.
+ * @retval false if at least one element is contained.
+ */
+CPROPS_DLL 
+int cp_list_is_empty(cp_list *list);
+
+/**
+ * Get the number of elements in the collection.
+ * 
+ * @return number of elements in the list.
+ * @retval 0 if list is NULL
+ */
+CPROPS_DLL 
+long cp_list_item_count(cp_list *);
+
+/**
+ * Locks the collection with the specified mode.
+ *
+ * This overrides the default mode stored in the object.
+ */
+CPROPS_DLL 
+int cp_list_lock(cp_list *list, int mode);
+
+/**
+ * Set a read lock on the object.
+ */
+#define cp_list_rdlock(list) cp_list_lock(list, COLLECTION_LOCK_READ)
+
+/**
+ * Set a write lock on the object.
+ */
+#define cp_list_wrlock(list) cp_list_lock(list, COLLECTION_LOCK_WRITE)
+
+/**
+ * Unlock the object.
+ */
+CPROPS_DLL 
+int cp_list_unlock(cp_list *list);
+	
+/* set list to use given mempool or allocate a new one if pool is NULL */
+CPROPS_DLL
+int cp_list_use_mempool(cp_list *list, cp_mempool *pool);
+
+/* set list to use a shared memory pool */
+CPROPS_DLL
+int cp_list_share_mempool(cp_list *list, cp_shared_mempool *pool);
+
+
+/**
+ * Initialize the Iterator at the first position.
+ *
+ * Set the iterator at the beginning of the list and lock the list in the
+ * mode specified in type.
+ *
+ * @param iterator the iterator object
+ * @param list the list to iterate over
+ * @param lock_mode locking mode to use
+ * @retval return-code of the aquired lock
+ * @retval 0 if no locking
+ */
+CPROPS_DLL 
+int cp_list_iterator_init(cp_list_iterator *iterator, cp_list *list, int lock_mode);
+
+/**
+ * Initialize the Iterator at the end.
+ *
+ * Set the iterator at the end of the list and lock the list in the
+ * mode specified in type.
+ *
+ * @param iterator the iterator object
+ * @param list the list to iterate over
+ * @param lock_mode locking mode to use
+ * @retval return-code of the aquired lock
+ * @retval 0 if no locking
+ */
+CPROPS_DLL 
+int cp_list_iterator_init_tail(cp_list_iterator *iterator, cp_list *list, int lock_mode);
+
+/**
+ * create a new iterator and initialize it at the beginning of the list.
+ *
+ * @param list the list to iterate over
+ * @param lock_mode locking mode to use
+ * @return new iterator object
+ */
+CPROPS_DLL 
+cp_list_iterator* cp_list_create_iterator(cp_list *list, int lock_mode);
+
+/**
+ * Move the iterator to the beginning of the list.
+ */
+CPROPS_DLL 
+int cp_list_iterator_head(cp_list_iterator *iterator);
+
+/**
+ * Move the iterator to the end of the list.
+ */
+CPROPS_DLL 
+int cp_list_iterator_tail(cp_list_iterator *iterator);
+
+CPROPS_DLL 
+int cp_list_iterator_destroy(cp_list_iterator *iterator);
+
+/**
+ * unlock the list the iterator is operating on.
+ */
+CPROPS_DLL 
+int cp_list_iterator_release(cp_list_iterator *iterator);
+
+/**
+ * Go to the next entry in the list and return the content.
+ * 
+ * @return object of the next entry.
+ * @retval NULL if reading beyond end or from empty list.
+ */
+CPROPS_DLL 
+void *cp_list_iterator_next(cp_list_iterator *iterator);
+
+/**
+ * Go to the previous entry in the list and return the content.
+ * 
+ * @return object of the previous entry.
+ * @retval NULL if reading beyond beginning or from empty list.
+ */
+CPROPS_DLL 
+void *cp_list_iterator_prev(cp_list_iterator *iterator);
+
+/**
+ * returns the value at the current iterator position
+ * 
+ * @return value at the current position.
+ * @retval NULL if list is empty.
+ */
+CPROPS_DLL 
+void *cp_list_iterator_curr(cp_list_iterator *iterator);
+
+
+/**
+ * insert item to the list just before the current iterator position. In the 
+ * special case that the iterator has been moved beyond the list end the new
+ * item is added at the end of the list. 
+ *
+ * @return the added item or NULL if the list mode is not 
+ * 		   & COLLECTION_MODE_NOSYNC and the iterator does not own a write lock
+ */
+CPROPS_DLL 
+void *cp_list_iterator_insert(cp_list_iterator *iterator, void *item);
+
+/**
+ * append item to the list just after the current iterator position. In the 
+ * special case that the iterator has been moved beyond the list head the new
+ * item is added at the head of the list. 
+ *
+ * @return the added item or NULL if the list mode is not 
+ * 		   & COLLECTION_MODE_NOSYNC and the iterator does not own a write lock
+ */
+CPROPS_DLL 
+void *cp_list_iterator_append(cp_list_iterator *iterator, void *item);
+
+/**
+ * delete the item at the current iterator position.
+ *
+ * @return the deleted item or NULL the list is empty, if the iterator points
+ * 		   beyond list limits or if the list mode is not 
+ * 		   & COLLECTION_MODE_NOSYNC and the iterator does not own a write lock
+ */
+CPROPS_DLL 
+void *cp_list_iterator_remove(cp_list_iterator *iterator);
+
+__END_DECLS
+
+/** @} */
+
+#endif


Property changes on: branches/multicore/numpy/core/cprops_thread/linked_list.h
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/multicore/numpy/core/cprops_thread/log.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/log.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/log.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,115 @@
+/** @{ */
+/**
+ * @file
+ * very simple logging facilities.
+ */
+
+#include <stdio.h>
+
+#include "common.h"
+#include "log.h"
+
+static int loglevel = LOG_LEVEL_INFO;
+
+typedef struct _error_code_legend
+{
+	int code;
+	char *msg;
+} error_code_legend;
+
+error_code_legend error_messages[] = 
+{	
+	{CP_MEMORY_ALLOCATION_FAILURE, "MEMORY ALLOCATION FAILURE"}, 
+	{CP_INVALID_FUNCTION_POINTER, "INVALID FUNCTION POINTER"}, 
+	{CP_THREAD_CREATION_FAILURE, "THREAD CREATION FAILURE"}, 
+
+	{CP_LOADLIB_FAILED, "LOADLIB FAILED"}, 
+	{CP_LOADFN_FAILED, "LOADFN FAILED"}, 
+	{CP_MODULE_NOT_LOADED, "MODULE NOT LOADED"}, 
+
+	{CP_IO_ERROR, "IO ERROR"},
+	{CP_OPEN_PORT_FAILED, "OPEN PORT FAILED"}, 
+	{CP_HTTP_FETCH_FAILED, "HTTP FETCH FAILED"}, 
+	{CP_INVALID_RESPONSE, "INVALID RESPONSE"}, 
+    {CP_HTTP_EMPTY_REQUEST, "EMPTY HTTP REQUEST"},
+    {CP_HTTP_INVALID_REQUEST_LINE, "INVALID HTTP REQUEST LINE"},
+    {CP_HTTP_INVALID_STATUS_LINE, "INVALID HTTP STATUS LINE"},
+    {CP_HTTP_UNKNOWN_REQUEST_TYPE, "UNKNOWN HTTP REQUEST TYPE"},
+    {CP_HTTP_INVALID_URI, "INVALID URI"},
+    {CP_HTTP_INVALID_URL, "INVALID URL"},
+    {CP_HTTP_VERSION_NOT_SPECIFIED, "HTTP VERSION NOT SPECIFIED"},
+    {CP_HTTP_1_1_HOST_NOT_SPECIFIED, "HTTP 1.1 HOST NOT SPECIFIED"},
+    {CP_HTTP_INCORRECT_REQUEST_BODY_LENGTH, "INCORRECT HTTP REQUEST BODY LENGTH"},
+    {CP_SSL_CTX_INITIALIZATION_ERROR, "SSL CONTEXT INITIALIZATION ERROR"},
+    {CP_SSL_HANDSHAKE_FAILED, "SSL HANDSHAKE FAILED"},
+
+	{CP_LOG_FILE_OPEN_FAILURE, "LOG FILE OPEN FAILURE"}, 
+	{CP_LOG_NOT_OPEN, "LOG NOT OPEN"}, 
+
+	{CP_INVALID_VALUE, "INVALID VALUE"},
+	{CP_MISSING_PARAMETER, "MISSING PARAMETER"},
+	{CP_BAD_PARAMETER_SET, "BAD PARAMETER SET"},
+    {CP_ITEM_EXISTS, "ITEM EXISTS"},
+    {CP_UNHANDLED_SIGNAL, "UNHANDLED SIGNAL"},
+    {CP_FILE_NOT_FOUND, "FILE NOT FOUND"},
+	{CP_METHOD_NOT_IMPLEMENTED, "METHOD NOT IMPLEMENTED"},
+
+	{CP_REGEX_COMPILATION_FAILURE, "INVALID REGULAR EXPRESSION"},
+	{CP_COMPILATION_FAILURE, "COMPILATION FAILED"},
+
+	{CP_DBMS_NO_DRIVER, "NO DRIVER"},
+	{CP_DBMS_CONNECTION_FAILURE, "DBMS CONNECTION FAILED"},
+	{CP_DBMS_QUERY_FAILED, "DBMS QUERY FAILED"},
+	{CP_DBMS_CLIENT_ERROR, "DBMS CLIENT ERROR"},
+	{CP_DBMS_STATEMENT_ERROR, "DBMS STATEMENT ERROR"},
+	{-1, NULL},
+}; 
+
+char* error_message_lookup(int code)
+{
+    error_code_legend* entry=error_messages;
+    
+    while (entry->code != -1)
+    {
+        entry++;
+    }        
+    return entry->msg;    
+}
+
+void cp_info(char *msg)
+{
+	if (loglevel > LOG_LEVEL_INFO) return;
+
+	printf("%s\n", msg);
+}
+
+void cp_warn(char *msg)
+{
+	if (loglevel > LOG_LEVEL_WARNING) return;
+
+	printf("%s\n", msg);
+}
+
+void cp_error(int code, char *msg)
+{
+	char *code_msg;
+
+	if (loglevel > LOG_LEVEL_ERROR) return;
+	code_msg = error_message_lookup(code);
+	printf("%s: %s\n", code_msg, msg);
+}
+
+void cp_fatal(int code, char *msg)
+{
+	char *code_msg;
+
+	if (loglevel > LOG_LEVEL_FATAL) return;
+	code_msg = error_message_lookup(code);
+	printf("%s: %s\n", code_msg, msg);
+	
+	/* cprops has this exit, but that is a bad idea from a library, 
+	 * so we don't. 
+	 * fixme: This probably deserves some attention in the library.
+	 */
+}
+

Added: branches/multicore/numpy/core/cprops_thread/log.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/log.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/log.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,40 @@
+#ifndef _CP_LOG_H
+#define _CP_LOG_H
+
+/** @{ */
+/**
+ * @file
+ * libcprops logging facilities<p>
+ *
+ * All of these simply print to stdout.  They should probably write to
+ * an thread-specific error buffer that can be retreived on failures.
+ * 
+ * <ul>
+ * <li> cp_info(,sg) for printouts on LOG_LEVEL_INFO
+ * <li> cp_warn(msg) for warning printouts - LOG_LEVEL_WARNING or lower
+ * <li> cp_error(code, msg) for error messages - LOG_LEVEL_ERROR or lower
+ * <li> cp_fatal(code, msg) for fatal error messages (LOG_LEVEL_FATAL)
+ * </ul>
+ */
+
+
+/** debug level */
+#define LOG_LEVEL_DEBUG				0
+/** normal log level */
+#define LOG_LEVEL_INFO				1
+/** relatively quiet - warnings only */
+#define LOG_LEVEL_WARNING			2
+/** quit - severe errors only */
+#define LOG_LEVEL_ERROR				3
+/** very quiet - report fatal errors only */
+#define LOG_LEVEL_FATAL				4
+/** no logging */
+#define LOG_LEVEL_SILENT			5
+
+void cp_info(char *msg);
+void cp_warn(char *msg);
+void cp_error(int code, char *msg);
+void cp_fatal(int code, char *msg);
+
+#endif
+


Property changes on: branches/multicore/numpy/core/cprops_thread/log.h
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/multicore/numpy/core/cprops_thread/mempool.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/mempool.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/mempool.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,472 @@
+#include "mempool.h"
+/* #include "util.h" */
+
+#include <stdlib.h>		       /* for calloc() and malloc() */
+#include <string.h>		       /* for memset() */
+#include <errno.h>		       /* for errno and EINVAL */
+
+#ifdef CP_HAS_GETPAGESIZE
+#include <unistd.h>		       /* for getpagesize() */
+#else
+int getpagesize() { return 0x2000; }
+#endif /* CP_HAS_GETPAGESIZE */
+
+#ifndef WORD_SIZE
+#define WORD_SIZE (sizeof(void *))
+#endif /* WORD_SIZE */
+
+#if defined(CP_HAS_PTHREAD_MUTEX_RECURSIVE) || defined(CP_HAS_PTHREAD_MUTEX_RECURSIVE_NP)
+#define CP_MEMPOOL_TXLOCK(pool, err_ret) { \
+    if (!((pool)->mode & COLLECTION_MODE_NOSYNC)) \
+	if (cp_mutex_lock((pool)->lock)) \
+	    return err_ret; \
+}
+#define CP_MEMPOOL_TXUNLOCK(pool, err_ret) { \
+    if (!((pool)->mode & COLLECTION_MODE_NOSYNC)) \
+	if (cp_mutex_unlock((pool)->lock)) \
+	    return err_ret; \
+}
+#else
+#define CP_MEMPOOL_TXLOCK(pool, err_ret) { \
+    if (!((pool)->mode & COLLECTION_MODE_NOSYNC)) \
+    { \
+        cp_thread self = cp_thread_self(); \
+        if (!cp_thread_equal(self, (pool)->txowner) && \
+	        cp_mutex_lock((pool)->lock)) \
+	        return err_ret; \
+        (pool)->txowner = self; \
+    } \
+}
+#define CP_MEMPOOL_TXUNLOCK(pool, err_ret) { \
+    if (!((pool)->mode & COLLECTION_MODE_NOSYNC)) \
+    { \
+        cp_thread self = cp_thread_self(); \
+        if (!cp_thread_equal(self, (pool)->txowner) && \
+	        cp_mutex_unlock((pool)->lock)) \
+	        return err_ret; \
+        (pool)->txowner = 0; \
+    } \
+}
+#endif /* CP_HAS_PTHREAD_MUTEX_RECURSIVE */
+static size_t pagesize = 0;
+
+cp_mempool *cp_mempool_create_by_option(const int mode, 
+                                    	size_t item_size, 
+                                    	size_t alloc_size)
+{
+	cp_mempool *pool = (cp_mempool *) calloc(1, sizeof(cp_mempool));
+	if (pool == NULL) return NULL;
+
+	pool->mode = mode;
+
+	if (!(mode & COLLECTION_MODE_NOSYNC))
+	{
+#if defined(PTHREAD_MUTEX_RECURSIVE) || defined(PTHREAD_MUTEX_RECURSIVE_NP)
+		pthread_mutexattr_t attr;
+#endif /* PTHREAD_MUTEX_RECURSIVE */
+		pool->lock = (cp_mutex *) malloc(sizeof(cp_mutex));
+		if (pool->lock == NULL)
+		{
+			cp_mempool_destroy(pool);
+			return NULL;
+		}
+#ifdef PTHREAD_MUTEX_RECURSIVE
+		pthread_mutexattr_init(&attr);
+		pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+		cp_mutex_init(pool->lock, &attr);
+#else
+		cp_mutex_init(pool->lock, NULL);
+#endif /* PTHREAD_MUTEX_RECURSIVE */
+	}
+
+	if (pagesize == 0) pagesize = getpagesize();
+
+	/* first, we ensure that item_size is a multiple of WORD_SIZE,
+	 * and also that it is at least sizeof(void*). The first
+	 * condition may imply the second on *most* platforms, but it
+	 * costs us very little to make sure. */
+	if (item_size < sizeof(void*)) item_size = sizeof(void*);
+	if (item_size % WORD_SIZE)
+		item_size += (WORD_SIZE) - (item_size % WORD_SIZE);
+	pool->item_size = item_size;
+	/* next, we pump up the alloc_size until it is at least big enough
+	 * to hold ten chunks plus a void pointer, or ten pages, whichever
+	 * is bigger. The reason for doing it this way rather than simply
+	 * adding sizeof(void*) to alloc_size is that we want alloc_size to
+	 * be a multiple of pagesize (this makes it faster!). */
+	if (alloc_size < item_size * 10 + sizeof(void *))
+		alloc_size = item_size * 10 + sizeof(void *);
+	if (alloc_size < pagesize * 10) alloc_size = pagesize * 10;
+	if (alloc_size % pagesize)
+		alloc_size += pagesize - (alloc_size % pagesize);
+	pool->alloc_size = alloc_size;
+
+	pool->items_per_alloc = (alloc_size - sizeof(void *)) / item_size;
+
+	pool->reuse_pool = NULL;
+	pool->alloc_pool = (char *) malloc(alloc_size);
+	if (pool->alloc_pool == NULL)
+	{
+		free(pool);
+		return NULL;
+	}
+	*(void **) pool->alloc_pool = NULL;
+
+	return pool;
+}
+
+
+cp_mempool *cp_mempool_create(const size_t item_size)
+{
+	return cp_mempool_create_by_option(COLLECTION_MODE_NOSYNC, item_size, 0);
+}
+
+
+void *cp_mempool_alloc(cp_mempool * const pool)
+{
+	void *p;
+
+	CP_MEMPOOL_TXLOCK(pool, NULL);
+
+	if (pool->reuse_pool)
+	{
+		p = pool->reuse_pool;
+		pool->reuse_pool = *(void **)p;
+	}
+	else
+	{
+		if (pool->alloc_pool_pos == pool->items_per_alloc)
+		{
+			p = malloc(pool->alloc_size);
+			if (p == NULL) return NULL;
+			*(void **) p = pool->alloc_pool;
+			pool->alloc_pool = p;
+			pool->alloc_pool_pos = 0;
+			/* if this pool is owned by a shared_mempool, report allocations */
+			if (pool->alloc_callback) 
+				(*pool->alloc_callback)(pool->callback_prm, pool, p);
+		}
+		p = pool->alloc_pool + sizeof(void *) + 
+			pool->item_size * pool->alloc_pool_pos++;
+	}
+
+	CP_MEMPOOL_TXUNLOCK(pool, NULL);
+
+	return p;
+}
+
+void *cp_mempool_calloc(cp_mempool * const pool)
+{
+	void *p = cp_mempool_alloc(pool);
+	if (p)
+		memset(p, 0, pool->item_size);
+	return p;
+}
+
+int cp_mempool_free(cp_mempool * const pool, void *data)
+{
+	CP_MEMPOOL_TXLOCK(pool, -1);
+	*(void **) data = pool->reuse_pool;
+	pool->reuse_pool = data;
+	CP_MEMPOOL_TXUNLOCK(pool, -1);
+	return 0;
+}
+
+/* increment refcount */
+int cp_mempool_inc_refcount(cp_mempool *pool)
+{
+	CP_MEMPOOL_TXLOCK(pool, -1);
+	pool->refcount++;
+	CP_MEMPOOL_TXUNLOCK(pool, -1);
+	return 0;
+}
+
+void cp_mempool_destroy(cp_mempool *pool)
+{
+	if (pool)
+	{
+		if (pool->refcount-- <= 0)
+		{
+			void *p;
+
+			while ((p = pool->alloc_pool))
+			{
+				pool->alloc_pool = *(void **) pool->alloc_pool;
+				free(p);
+			}
+		}
+	}
+}
+
+void cp_mempool_set_callback(cp_mempool *pool, void *prm, cp_mempool_callback_fn cb)
+
+{
+	pool->alloc_callback = cb;
+	pool->callback_prm = prm;
+}
+
+
+/****************************************************************************
+ *                                                                          *
+ *                         cp_shared_mempool functions                      *
+ *                                                                          *
+ ****************************************************************************/
+
+typedef struct _chunk_track
+{
+	void *mem;
+	size_t size;
+} chunk_track;
+
+chunk_track *get_chunk_track(void *mem, size_t size)
+{
+	chunk_track *t = (chunk_track *) malloc(sizeof(chunk_track));
+	if (t)
+	{
+		t->mem = mem;
+		t->size = size;
+	}
+	return t;
+}
+
+int compare_chunk_track(void *c1, void *c2)
+{
+	chunk_track *t1 = c1;
+	chunk_track *t2 = c2;
+	return (t2->size == 0 && 
+            t2->mem >= t1->mem && 
+			((char *) t2->mem - (char *) t1->mem) < t1->size) ||
+		   (t1->size == 0 && 
+            t1->mem >= t2->mem && 
+			((char *) t1->mem - (char *) t2->mem) < t2->size) ? 0 : 
+		((char *) t1->mem - (char *) t2->mem);
+}
+
+cp_mempool *shared_mempool_entry_get(cp_shared_mempool *pool, size_t size)
+{
+	shared_mempool_entry *entry = pool->reg_tbl[size % pool->reg_tbl_size];
+
+	while (entry && entry->item_size != size) entry = entry->next;
+	if (entry) return entry->pool;
+
+	return NULL;
+}
+
+cp_mempool *shared_mempool_entry_put(cp_shared_mempool *pool, 
+									 size_t size, cp_mempool *sub)
+{
+	shared_mempool_entry **entry = &pool->reg_tbl[size % pool->reg_tbl_size];
+
+	while ((*entry) && (*entry)->item_size != size) 
+		entry = &(*entry)->next;
+
+	if (*entry == NULL)
+	{
+		*entry = calloc(1, sizeof(shared_mempool_entry));
+		(*entry)->item_size = size;
+	}
+
+	(*entry)->pool = sub;
+	return sub;
+}
+
+void shared_mempool_entry_destroy(cp_shared_mempool *pool)
+{
+	int i;
+
+	for (i = 0; i < pool->reg_tbl_size; i++)
+	{
+		shared_mempool_entry *curr, *tmp;
+		curr = pool->reg_tbl[i];
+		while (curr)
+		{
+			tmp = curr;
+			curr = curr->next;
+			cp_mempool_destroy(tmp->pool);
+			free(tmp);
+		}
+	}
+
+	free(pool->reg_tbl);
+}
+
+/* cp_shared_mempool_create */
+cp_shared_mempool *cp_shared_mempool_create()
+{
+	return 
+		cp_shared_mempool_create_by_option(0, CP_SHARED_MEMPOOL_TYPE_2, 0, 0);
+}
+
+/* cp_shared_mempool_create_by_option */
+CPROPS_DLL
+cp_shared_mempool *
+	cp_shared_mempool_create_by_option(int mode, 
+									   int arbitrary_allocation_strategy,
+									   int size_hint, 
+									   int page_count)
+{
+	cp_shared_mempool *pool = 
+		(cp_shared_mempool *) calloc(1, sizeof(cp_shared_mempool));
+	if (pool == NULL) return NULL;
+
+	if (size_hint)
+		size_hint = size_hint * 2 + 1; /* choose an odd number */
+	else 
+		size_hint = 211; /* 211 is a prime */
+
+	pool->reg_tbl = calloc(size_hint, sizeof(shared_mempool_entry *));
+	if (pool->reg_tbl == NULL) goto CREATE_ERROR;
+	pool->reg_tbl_size = size_hint;
+
+	pool->mode = mode;
+
+	if ((mode & COLLECTION_MODE_NOSYNC))
+	{
+		pool->lock = (cp_mutex *) malloc(sizeof(cp_mutex));
+		if (pool->lock == NULL) goto CREATE_ERROR;
+		if ((cp_mutex_init(pool->lock, NULL))) goto CREATE_ERROR;
+	}
+
+	if (arbitrary_allocation_strategy == 0)
+		pool->gm_mode = CP_SHARED_MEMPOOL_TYPE_1;
+	else
+		pool->gm_mode = arbitrary_allocation_strategy;
+
+	pool->multiple = page_count;
+
+	pool->chunk_tracker = 
+		cp_rbtree_create_by_option(mode | COLLECTION_MODE_DEEP, 
+								   compare_chunk_track, NULL, free, NULL, NULL);
+	if (pool->chunk_tracker == NULL) goto CREATE_ERROR;
+
+	return pool;
+
+CREATE_ERROR:
+	if (pool->lock)
+	{
+		free(pool->lock);
+		pool->lock = NULL;
+	}
+	cp_shared_mempool_destroy(pool);
+	return NULL;
+}
+
+/* cp_shared_mempool destroy */
+CPROPS_DLL
+void cp_shared_mempool_destroy(cp_shared_mempool *pool)
+{
+	if (pool)
+	{
+		cp_rbtree_destroy(pool->chunk_tracker);
+		shared_mempool_entry_destroy(pool);
+		if (pool->lock)
+		{
+			cp_mutex_destroy(pool->lock);
+			free(pool->lock);
+		}
+		free(pool);
+	}
+}
+
+void cp_shared_mempool_track_alloc(cp_shared_mempool *pool, 
+								   cp_mempool *sub, void *mem)
+{
+	cp_rbtree_insert(pool->chunk_tracker, 
+					 get_chunk_track(mem, sub->alloc_size), sub);
+}
+
+/* cp_shared_mempool_register */
+cp_mempool *cp_shared_mempool_register(cp_shared_mempool *pool, size_t size)
+{
+	cp_mempool *sub;
+	if (size % WORD_SIZE) size += WORD_SIZE - (size % WORD_SIZE);
+	sub = shared_mempool_entry_get(pool, size);
+	if (sub)
+		cp_mempool_inc_refcount(sub);
+	else
+	{
+		sub = cp_mempool_create_by_option(pool->mode, size, pool->multiple);
+		cp_mempool_set_callback(sub, pool, 
+			(cp_mempool_callback_fn) cp_shared_mempool_track_alloc);
+		shared_mempool_entry_put(pool, size, sub);
+	}
+
+	return sub;
+}
+
+#if 0
+/* unregister a mempool */
+void cp_shared_mempool_unregister(cp_shared_mempool *pool, size_t size)
+{
+	cp_mempool *sub;
+	if (size % WORD_SIZE) size += WORD_SIZE - (size % WORD_SIZE);
+	sub = shared_mempool_entry_get(pool, size);
+	if (sub)
+		cp_mempool_destroy(sub);
+}
+#endif
+
+/* cp_shared_mempool_alloc */
+CPROPS_DLL
+void *cp_shared_mempool_alloc(cp_shared_mempool *pool, size_t size)
+{
+	size_t actual;
+	cp_mempool *mempool = NULL;
+
+	if (size % WORD_SIZE) size += WORD_SIZE - (size % WORD_SIZE);
+	
+	if ((mempool = shared_mempool_entry_get(pool, size)))
+		return cp_mempool_alloc(mempool);
+
+	if ((pool->gm_mode & CP_SHARED_MEMPOOL_TYPE_2))
+		actual = size;
+	else
+	{
+		actual = WORD_SIZE;
+		while (actual < size) actual <<= 1;
+	}
+	if ((mempool = cp_shared_mempool_register(pool, actual)))
+		return cp_mempool_alloc(mempool);
+
+	return NULL;
+}
+
+/* cp_shared_mempool_calloc */
+CPROPS_DLL
+void *cp_shared_mempool_calloc(cp_shared_mempool *pool, size_t size)
+{
+	size_t actual;
+	cp_mempool *mempool = NULL;
+
+	if (size % WORD_SIZE) size += WORD_SIZE - (size % WORD_SIZE);
+	
+	if ((mempool = shared_mempool_entry_get(pool, size)))
+		return cp_mempool_calloc(mempool);
+
+	if ((pool->gm_mode & CP_SHARED_MEMPOOL_TYPE_2))
+		actual = size;
+	else
+	{
+		actual = WORD_SIZE;
+		while (actual < size) actual <<= 1;
+	}
+	if ((mempool = cp_shared_mempool_register(pool, actual)))
+		return cp_mempool_calloc(mempool);
+
+	return NULL;
+}
+
+
+/* cp_shared_mempool_free */
+CPROPS_DLL
+void cp_shared_mempool_free(cp_shared_mempool *pool, void *p)
+{
+	cp_mempool *mempool;
+	chunk_track ct;
+	memset(&ct, 0, sizeof(chunk_track));
+	ct.mem = p;
+
+	if ((mempool = cp_rbtree_get(pool->chunk_tracker, &ct)))
+		cp_mempool_free(mempool, p);
+}
+

Added: branches/multicore/numpy/core/cprops_thread/mempool.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/mempool.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/mempool.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,189 @@
+/* mempool.h - a memory pool implementation
+ *
+ * cp_mempool is a memory pool for fixed allocation sizes. 
+ *
+ * cp_shared_mempool is a collection of cp_mempool objects. cp_shared_mempool
+ * allows sharing cp_mempool instances that serve the same allocation size. 
+ * Call cp_shared_mempool_register to request an allocation size and use the 
+ * returned cp_mempool. 
+ *
+ * cp_shared_mempool may also be used for aribitrary sizes allocations, but
+ * this does not necessarily improve performance. Tests on Open BSD show 
+ * significant gains, whereas tests on Linux show a performance degradation for
+ * generic allocation operations. Using cp_shared_mempool to share cp_mempool
+ * objects between cp_* data structures does not reduce performance. The test
+ * results are not conclusive and performance characteristics may also be 
+ * application specific. For best results, benchmark performance for your 
+ * application in realistic deployment scenarios before deciding whether to use
+ * cp_shared_mempool.
+ *
+ * After instantiating a cp_shared_mempool, you may set one of 
+ * CP_SHARED_MEMPOOL_TYPE_2 or CP_SHARED_MEMPOOL_TYPE_1. If TYPE_2 is set, 
+ * requests for unregistered allocation sizes will return the requested size
+ * rounded up to the machine word size, after instantiating a cp_mempool 
+ * serving the requested size if none exists. This could potentially use up
+ * large amounts of memory. If TYPE_1 is set, unregistered allocation sizes
+ * are rounded up to the next bit. E.g. a request for 513 bytes will return a
+ * chunk of 1024 bytes. This might also use up large amounts of memory. 
+ *
+ * Both cp_mempool and cp_shared_mempool represent a trade off of memory for
+ * speed and should not be used if memory is tight or if the total allocation
+ * may exceed the amount of physical memory available to the program, so as to
+ * prevent swapping. Note that even if using the provided cp_mempool_free or 
+ * cp_shared_mempool_free functions, the memory returned to the pool is kept 
+ * for future requests and is ultimately released back to the general "malloc"
+ * library only when the memory pool is destroyed. 
+ * 
+ * AUTHOR: Kyle Wheeler, Ilan Aelion
+ */
+#ifndef _CP_MEMPOOL_H
+#define _CP_MEMPOOL_H
+
+#include "common.h"
+#include "collection.h"
+
+__BEGIN_DECLS
+
+struct _cp_mempool;
+
+typedef void (*cp_mempool_callback_fn)(void *prm, 
+									   struct _cp_mempool *pool, 
+									   void *mem);
+
+typedef struct _cp_mempool
+{
+	size_t item_size;
+	size_t alloc_size;
+	size_t items_per_alloc;
+
+	char *reuse_pool;
+	char *alloc_pool;
+	size_t alloc_pool_pos;
+
+	int refcount;
+
+	cp_mempool_callback_fn alloc_callback;
+	void *callback_prm;
+
+	int mode;
+	cp_mutex *lock;
+#if !defined(CP_HAS_PTHREAD_MUTEX_RECURSIVE) && !defined(CP_HAS_PTHREAD_MUTEX_RECURSIVE_NP)
+    cp_thread txowner;
+#endif /* CP_HAS_PTHREAD_MUTEX_RECURSIVE */
+} cp_mempool;
+
+#define cp_mempool_item_size(p) ((p)->item_size)
+
+/* cp_mempool_create_by_option */
+CPROPS_DLL
+cp_mempool *cp_mempool_create_by_option(const int mode, 
+                       		            size_t chunksize, 
+                                    	size_t multiple);
+
+/* cp_mempool_create_by_option */
+CPROPS_DLL
+cp_mempool *cp_mempool_create(const size_t chunksize);
+
+/* increment refcount */
+CPROPS_DLL
+int cp_mempool_inc_refcount(cp_mempool *pool);
+
+/* cp_mempool_alloc */
+CPROPS_DLL
+void *cp_mempool_alloc(cp_mempool * const pool);
+
+/* cp_mempool_calloc */
+CPROPS_DLL
+void *cp_mempool_calloc(cp_mempool * const pool);
+
+/* cp_mempool_free */
+CPROPS_DLL
+int cp_mempool_free(cp_mempool * const pool, void *data);
+
+/* cp_mempool_destroy */
+CPROPS_DLL
+void cp_mempool_destroy(cp_mempool *pool);
+
+#include "rb.h"
+#include "hashtable.h"
+
+typedef struct _shared_mempool_entry
+{
+	size_t item_size;
+	cp_mempool *pool;
+	struct _shared_mempool_entry *next;
+} shared_mempool_entry;
+
+/* cp_shared_mempool is a generalized memory pool. It allows requesting variable
+ * block sizes. For best results, register the required block sizes in advance.
+ * requests for unregistered block sizes will return memory from a default
+ * internal list, which rounds up the block size to the next bit. For example
+ * allocating an unregisterd block of size 12 will return a 16 byte block. 
+ * In partcular large allocations could return a lot of extra memory.
+ */
+typedef CPROPS_DLL struct _cp_shared_mempool
+{
+	unsigned int reg_tbl_size;
+	unsigned int reg_tbl_count;
+
+	shared_mempool_entry **reg_tbl;
+	struct _cp_rbtree *chunk_tracker;
+
+	int mode;
+	int gm_mode;
+
+	/* lock for mempool lists */
+	cp_mutex *lock;
+
+	int multiple; /* number of pages to allocate in sub pools */
+} cp_shared_mempool;
+
+/* ``smaller'': arbitrary size allocations are rounded up to the next bit. The
+ * pool is ``smaller'' in that up to about WORD_SIZE internal memory pools are
+ * allocated to serve unregistered allocation size requests.
+ */
+#define CP_SHARED_MEMPOOL_TYPE_1 1
+/* ``faster'': arbitrary size allocations are rounded up to the word size. The 
+ * pool is ``faster'' in that typically the allocation overhead is smaller, and
+ * the number of operations required to determine which pool to use internally
+ * is smaller. On the other hand, since a large number of memory pool could be
+ * allocated internally, this may not be usable in some circumstances. 
+ */
+#define CP_SHARED_MEMPOOL_TYPE_2 2
+
+/* cp_shared_mempool_create */
+CPROPS_DLL
+cp_shared_mempool *cp_shared_mempool_create();
+
+/* cp_shared_mempool_create_by_option */
+CPROPS_DLL
+cp_shared_mempool *
+	cp_shared_mempool_create_by_option(int mode, 
+									   int arbitrary_allocation_strategy,
+									   int size_hint, 
+									   int page_count);
+
+/* cp_shared_mempool destroy */
+CPROPS_DLL
+void cp_shared_mempool_destroy(cp_shared_mempool *pool);
+
+/* cp_shared_mempool_register */
+CPROPS_DLL
+cp_mempool *cp_shared_mempool_register(cp_shared_mempool *pool, size_t size);
+
+/* cp_shared_mempool_alloc */
+CPROPS_DLL
+void *cp_shared_mempool_alloc(cp_shared_mempool *pool, size_t size);
+
+/* cp_shared_mempool_calloc */
+CPROPS_DLL
+void *cp_shared_mempool_calloc(cp_shared_mempool *pool, size_t size);
+
+/* cp_shared_mempool_free */
+CPROPS_DLL
+void cp_shared_mempool_free(cp_shared_mempool *pool, void *p);
+
+__END_DECLS
+
+#endif /* _CP_MEMPOOL_H */
+

Added: branches/multicore/numpy/core/cprops_thread/rb.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/rb.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/rb.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,969 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "collection.h"
+#include "vector.h"
+#include "rb.h"
+
+cp_rbnode *cp_rbnode_create(void *key, void *value, cp_mempool *pool)
+{
+	cp_rbnode *node;
+	
+	if (pool) 
+		node = (cp_rbnode *) cp_mempool_calloc(pool);
+	else
+		node = (cp_rbnode *) calloc(1, sizeof(cp_rbnode));
+
+	if (node == NULL) return NULL;
+
+	node->key = key;
+	node->value = value;
+
+	return node;
+}
+	
+/* implement COLLECTION_MODE_COPY if set */
+static cp_rbnode *create_rbnode(cp_rbtree *tree, void *key, void *value)
+{
+	if (tree->mode & COLLECTION_MODE_COPY)
+	{
+		void *k, *v;
+		k = tree->key_copy ? (*tree->key_copy)(key) : key;
+		if (k)
+		{
+			v = tree->value_copy ? (*tree->value_copy)(value) : value;
+			if (v)
+			{
+				if (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES)
+				{
+					cp_vector *m = cp_vector_create(1);
+					if (m == NULL) return NULL;
+					cp_vector_add_element(m, v);
+					v = m;
+				}
+				return cp_rbnode_create(k, v, tree->mempool);
+			}
+		}
+	}
+	else if (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES)
+	{
+		cp_vector *m = cp_vector_create(1);
+		if (m == NULL) return NULL;
+		cp_vector_add_element(m, value);
+		return cp_rbnode_create(key, m, tree->mempool);
+	}
+	else 
+		return cp_rbnode_create(key, value, tree->mempool);
+
+	return NULL;
+}
+
+void cp_rbtree_destroy_node_deep(cp_rbtree *owner, cp_rbnode *node)
+{
+    while (node)
+    {
+        if (node->right)
+        {
+            node = node->right;
+            node->up->right = NULL;
+        }
+        else if (node->left)
+        {
+            node = node->left;
+            node->up->left = NULL;
+        }
+        else
+        {
+            cp_rbnode *tmp = node;
+            node = node->up;
+            cp_rbtree_destroy_node(owner, tmp);
+        }
+    }
+}
+
+void cp_rbtree_destroy_node(cp_rbtree *tree, cp_rbnode *node)
+{
+	if (node)
+	{
+		if ((tree->mode & COLLECTION_MODE_DEEP))
+		{
+			if (tree->key_dtr) (*tree->key_dtr)(node->key);
+			if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES) && node->value)
+				cp_vector_destroy_custom(node->value, tree->value_dtr);
+			else if (tree->value_dtr) 
+				(*tree->value_dtr)(node->value);
+		}
+		else if ((tree->mode & COLLECTION_MODE_MULTIPLE_VALUES) && node->value)
+			cp_vector_destroy(node->value);
+		if (tree->mempool)
+			cp_mempool_free(tree->mempool, node);
+		else
+			free(node);
+	}
+}
+
+
+cp_rbtree *cp_rbtree_create(cp_compare_fn cmp)
+{
+	cp_rbtree *tree = calloc(1, sizeof(cp_rbtree));
+	if (tree == NULL) return NULL;
+
+	tree->mode = COLLECTION_MODE_NOSYNC;
+	tree->cmp = cmp;
+
+	return tree;
+}
+
+/*
+ * complete parameter create function
+ */
+cp_rbtree *
+	cp_rbtree_create_by_option(int mode, cp_compare_fn cmp, 
+							   cp_copy_fn key_copy, cp_destructor_fn key_dtr,
+							   cp_copy_fn val_copy, cp_destructor_fn val_dtr)
+{
+	cp_rbtree *tree = cp_rbtree_create(cmp);
+	if (tree == NULL) return NULL;
+	
+	tree->mode = mode;
+	tree->key_copy = key_copy;
+	tree->key_dtr = key_dtr;
+	tree->value_copy = val_copy;
+	tree->value_dtr = val_dtr;
+
+	if (!(mode & COLLECTION_MODE_NOSYNC))
+	{
+		tree->lock = malloc(sizeof(cp_lock));
+		if (tree->lock == NULL) 
+		{
+			cp_rbtree_destroy(tree);
+			return NULL;
+		}
+		if (cp_lock_init(tree->lock, NULL) != 0)
+		{
+			cp_rbtree_destroy(tree);
+			return NULL;
+		}
+	}
+
+	return tree;
+}
+
+
+void cp_rbtree_destroy(cp_rbtree *tree)
+{
+	if (tree)
+	{
+		cp_rbtree_destroy_node_deep(tree, tree->root);
+		if (tree->lock)
+		{
+			cp_lock_destroy(tree->lock);
+			free(tree->lock);
+		}
+		free(tree);
+	}
+}
+
+void cp_rbtree_destroy_custom(cp_rbtree *tree, 
+							  cp_destructor_fn key_dtr,
+							  cp_destructor_fn val_dtr)
+{
+	tree->mode |= COLLECTION_MODE_DEEP;
+	tree->key_dtr = key_dtr;
+	tree->value_dtr = val_dtr;
+	cp_rbtree_destroy(tree);
+}
+
+static int cp_rbtree_lock_internal(cp_rbtree *tree, int type)
+{
+    int rc;
+
+    switch (type)
+    {
+        case COLLECTION_LOCK_READ:
+            rc = cp_lock_rdlock(tree->lock);
+            break;
+
+        case COLLECTION_LOCK_WRITE:
+            rc = cp_lock_wrlock(tree->lock);
+            break;
+
+        case COLLECTION_LOCK_NONE:
+            rc = 0;
+            break;
+
+        default:
+            rc = EINVAL;
+            break;
+    }
+
+	/* api functions may rely on errno to report locking failure */
+	if (rc) errno = rc;
+
+    return rc;
+}
+
+static int cp_rbtree_unlock_internal(cp_rbtree *tree)
+{
+	return cp_lock_unlock(tree->lock);
+}
+
+int cp_rbtree_txlock(cp_rbtree *tree, int type)
+{
+	/* clear errno to allow client code to distinguish between a NULL return
+	 * value indicating the tree doesn't contain the requested value and NULL
+	 * on locking failure in tree operations
+	 */
+	if (tree->mode & COLLECTION_MODE_NOSYNC) return 0;
+	if (tree->mode & COLLECTION_MODE_IN_TRANSACTION && 
+		tree->txtype == COLLECTION_LOCK_WRITE)
+	{
+		cp_thread self = cp_thread_self();
+		if (cp_thread_equal(self, tree->txowner)) return 0;
+	}
+	errno = 0;
+	return cp_rbtree_lock_internal(tree, type);
+}
+
+int cp_rbtree_txunlock(cp_rbtree *tree)
+{
+	if (tree->mode & COLLECTION_MODE_NOSYNC) return 0;
+	if (tree->mode & COLLECTION_MODE_IN_TRANSACTION && 
+		tree->txtype == COLLECTION_LOCK_WRITE)
+	{
+		cp_thread self = cp_thread_self();
+		if (cp_thread_equal(self, tree->txowner)) return 0;
+	}
+	return cp_rbtree_unlock_internal(tree);
+}
+
+/* lock and set the transaction indicators */
+int cp_rbtree_lock(cp_rbtree *tree, int type)
+{
+	int rc;
+	if ((tree->mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
+	if ((rc = cp_rbtree_lock_internal(tree, type))) return rc;
+	tree->txtype = type;
+	tree->txowner = cp_thread_self();
+	tree->mode |= COLLECTION_MODE_IN_TRANSACTION;
+	return 0;
+}
+
+/* unset the transaction indicators and unlock */
+int cp_rbtree_unlock(cp_rbtree *tree)
+{
+	cp_thread self = cp_thread_self();
+	if (tree->txowner == self)
+	{
+		tree->txowner = 0;
+		tree->txtype = 0;
+		tree->mode ^= COLLECTION_MODE_IN_TRANSACTION;
+	}
+	else if (tree->txtype == COLLECTION_LOCK_WRITE)
+		return -1;
+	return cp_rbtree_unlock_internal(tree);
+}
+
+/* set mode bits on the tree mode indicator */
+int cp_rbtree_set_mode(cp_rbtree *tree, int mode)
+{
+	int rc;
+	int nosync; 
+
+	/* can't set NOSYNC in the middle of a transaction */
+	if ((tree->mode & COLLECTION_MODE_IN_TRANSACTION) && 
+		(mode & COLLECTION_MODE_NOSYNC)) return EINVAL;
+	/* COLLECTION_MODE_MULTIPLE_VALUES must be set at creation time */	
+	if (mode & COLLECTION_MODE_MULTIPLE_VALUES) return EINVAL;
+
+	if ((rc = cp_rbtree_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
+	
+	nosync = tree->mode & COLLECTION_MODE_NOSYNC;
+
+	tree->mode |= mode;
+
+	if (!nosync)
+		cp_rbtree_txunlock(tree);
+
+	return 0;
+}
+
+/* unset mode bits on the tree mode indicator. if unsetting 
+ * COLLECTION_MODE_NOSYNC and the tree was not previously synchronized, the 
+ * internal synchronization structure is initialized.
+ */
+int cp_rbtree_unset_mode(cp_rbtree *tree, int mode)
+{
+	int rc;
+	int nosync;
+
+	/* COLLECTION_MODE_MULTIPLE_VALUES can't be unset */
+	if (mode & COLLECTION_MODE_MULTIPLE_VALUES) return EINVAL;
+
+	if ((rc = cp_rbtree_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
+	
+	nosync = tree->mode & COLLECTION_MODE_NOSYNC;
+
+	/* handle the special case of unsetting COLLECTION_MODE_NOSYNC */
+	if ((mode & COLLECTION_MODE_NOSYNC) && tree->lock == NULL)
+	{
+		/* tree can't be locked in this case, no need to unlock on failure */
+		if ((tree->lock = malloc(sizeof(cp_lock))) == NULL)
+			return -1;
+		if (cp_lock_init(tree->lock, NULL))
+			return -1;
+	}
+	
+	/* unset specified bits */
+    tree->mode &= tree->mode ^ mode;
+	if (!nosync)
+		cp_rbtree_txunlock(tree);
+
+	return 0;
+}
+
+int cp_rbtree_get_mode(cp_rbtree *tree)
+{
+    return tree->mode;
+}
+
+
+static cp_rbnode *sibling(cp_rbnode *node)
+{
+	return node == node->up->left ? node->up->right : node->up->left;
+}
+
+static int is_right_child(cp_rbnode *node)
+{
+	return (node->up->right == node);
+}
+
+static int is_left_child(cp_rbnode *node)
+{
+	return (node->up->left == node);
+}
+
+/*         left rotate
+ *
+ *    (P)                (Q)
+ *   /   \              /   \
+ *  1    (Q)    ==>   (P)    3
+ *      /   \        /   \
+ *     2     3      1     2
+ *
+ */
+static void left_rotate(cp_rbtree *tree, cp_rbnode *p)
+{
+	cp_rbnode *q = p->right;
+	cp_rbnode **sup;
+	
+	if (p->up)
+		sup = is_left_child(p) ? &(p->up->left) : &(p->up->right);
+	else
+		sup = &tree->root;
+
+	p->right = q->left;
+	if (p->right) p->right->up = p;
+	q->left = p;
+	q->up = p->up;
+	p->up = q;
+	*sup = q;
+}
+
+/*           right rotate
+ *  
+ *       (P)                (Q)
+ *      /   \              /   \
+ *    (Q)    3    ==>     1    (P)  
+ *   /   \                    /   \
+ *  1     2                  2     3
+ *
+ */
+static void right_rotate(cp_rbtree *tree, cp_rbnode *p)
+{
+	cp_rbnode *q = p->left;
+	cp_rbnode **sup;
+	
+	if (p->up)
+		sup = is_left_child(p) ? &(p->up->left) : &(p->up->right);
+	else
+		sup = &tree->root;
+
+	p->left = q->right;
+	if (p->left) p->left->up = p;
+	q->right = p;
+	q->up = p->up;
+	p->up = q;
+	*sup = q;
+}
+
+
+/*
+ * newly entered node is RED; check balance recursively as required 
+ */
+static void rebalance(cp_rbtree *tree, cp_rbnode *node)
+{
+	cp_rbnode *up = node->up;
+	if (up == NULL || up->color == RB_BLACK) return;
+	if (sibling(up) && sibling(up)->color == RB_RED)
+	{
+		up->color = RB_BLACK;
+		sibling(up)->color = RB_BLACK;
+		if (up->up->up)
+		{
+			up->up->color = RB_RED;
+			rebalance(tree, up->up);
+		}
+	}
+	else
+	{
+		if (is_left_child(node) && is_right_child(up))
+		{
+			right_rotate(tree, up);
+			node = node->right;
+		}
+		else if (is_right_child(node) && is_left_child(up))
+		{
+			left_rotate(tree, up);
+			node = node->left;
+		}
+
+		node->up->color = RB_BLACK;
+		node->up->up->color = RB_RED;
+
+		if (is_left_child(node)) // && is_left_child(node->up)
+			right_rotate(tree, node->up->up);
+		else 
+			left_rotate(tree, node->up->up);
+	}
+}
+
+/* update_rbnode - implement COLLECTION_MODE_COPY, COLLECTION_MODE_DEEP and
+ * COLLECTION_MODE_MULTIPLE_VALUES when inserting a value for an existing key
+ */
+static void *
+	update_rbnode(cp_rbtree *tree, cp_rbnode *node, void *key, void *value)
+{
+	void *new_key = key;
+	void *new_value = value;
+
+	if (tree->mode & COLLECTION_MODE_COPY)
+	{
+		if (tree->key_copy) 
+		{
+			new_key = (*tree->key_copy)(key);
+			if (new_key == NULL) return NULL;
+		}
+		if (tree->value_copy)
+		{
+			new_value = (*tree->value_copy)(value);
+			if (new_value == NULL) return NULL;
+		}
+	}
+
+	if (tree->mode & COLLECTION_MODE_DEEP)
+	{
+		if (tree->key_dtr)
+			(*tree->key_dtr)(node->key);
+		if (tree->value_dtr && !(tree->mode & COLLECTION_MODE_MULTIPLE_VALUES))
+			(*tree->value_dtr)(node->value);
+	}
+		
+	node->key = new_key;
+	if (!tree->mode & COLLECTION_MODE_MULTIPLE_VALUES)
+		node->value = new_value;
+	else
+	{
+		cp_vector_add_element(node->value, new_value);
+		return node->value;
+	}
+
+	return new_value;
+}
+
+/*
+ * cp_rbtree_insert iterates through the tree, finds where the new node fits
+ * in, puts it there, then calls rebalance. 
+ *
+ * If a mapping for the given key already exists it is replaced unless 
+ * COLLECTION_MODE_MULTIPLE_VALUES is set, is which case a new mapping is 
+ * added. By default COLLECTION_MODE_MULTIPLE_VALUES is not set.
+ */
+void *cp_rbtree_insert(cp_rbtree *tree, void *key, void *value)
+{
+	void *res = NULL;
+	
+	if (cp_rbtree_txlock(tree, COLLECTION_LOCK_WRITE)) return NULL;
+
+	if (tree->root == NULL)
+	{
+		tree->root = create_rbnode(tree, key, value);
+		if (tree->root == NULL) goto DONE;
+		res = value;
+		tree->root->color = RB_BLACK;
+		tree->items++;
+	}
+	else
+	{
+		int cmp;
+		cp_rbnode **curr = &tree->root;
+		cp_rbnode *prev = NULL;
+
+		while (*curr)
+		{
+			prev = *curr;
+			cmp = (*tree->cmp)((*curr)->key, key);
+			if (cmp < 0)
+				curr = &(*curr)->right;
+			else if (cmp > 0) 
+				curr = &(*curr)->left;
+			else /* replace */
+			{
+				res = update_rbnode(tree, *curr, key, value);
+				break;
+			}
+		}
+
+		if (*curr == NULL) /* not replacing, create new node */
+		{
+			*curr = create_rbnode(tree, key, value);
+			if (*curr == NULL) goto DONE;
+			res = (*curr)->value;
+			tree->items++;
+			(*curr)->up = prev;
+			rebalance(tree, *curr);
+		}
+	}
+
+DONE:
+	cp_rbtree_txunlock(tree);
+	return res;
+}
+
+/* cp_rbtree_get - return the value mapped to the given key or NULL if none is
+ * found. If COLLECTION_MODE_MULTIPLE_VALUES is set the returned value is a
+ * cp_vector object or NULL if no mapping is found. 
+ */
+void *cp_rbtree_get(cp_rbtree *tree, void *key)
+{
+	cp_rbnode *curr;
+	void *value = NULL;
+	
+	if (cp_rbtree_txlock(tree, COLLECTION_LOCK_READ)) return NULL;
+
+	curr = tree->root;
+	while (curr)
+	{
+		int c = tree->cmp(curr->key, key);
+		if (c == 0) return curr->value;
+		curr = (c > 0) ? curr->left : curr ->right;
+	}
+
+	if (curr) value = curr->value;
+
+	cp_rbtree_txunlock(tree);
+	return value;;
+}
+	
+int cp_rbtree_contains(cp_rbtree *tree, void *key)
+{
+	return (cp_rbtree_get(tree, key) != NULL);
+}
+
+/* helper function for deletion */
+static void swap_node_content(cp_rbnode *a, cp_rbnode *b)
+{
+	void *tmpkey, *tmpval;
+
+	tmpkey = a->key;
+	a->key = b->key;
+	b->key = tmpkey;
+	
+	tmpval = a->value;
+	a->value = b->value;
+	b->value = tmpval;
+}
+
+/*
+ * helper function for cp_rbtree_delete to remove nodes with either a left 
+ * NULL branch or a right NULL branch
+ */
+static void rb_unlink(cp_rbtree *tree, cp_rbnode *node)
+{
+	if (node->left)
+	{
+		node->left->up = node->up;
+		if (node->up)
+		{
+			if (is_left_child(node))
+				node->up->left = node->left;
+			else
+				node->up->right = node->left;
+		}
+		else
+			tree->root = node->left;
+	}
+	else
+	{
+		if (node->right) node->right->up = node->up;
+		if (node->up)
+		{
+			if (is_left_child(node))
+				node->up->left = node->right;
+			else
+				node->up->right = node->right;
+		}
+		else
+			tree->root = node->right;
+	}
+}
+
+/* delete_rebalance - perform rebalancing after a deletion */
+static void delete_rebalance(cp_rbtree *tree, cp_rbnode *n)
+{
+	if (n->up)
+	{
+		cp_rbnode *sibl = sibling(n);
+
+		if (sibl->color == RB_RED)
+		{
+			n->up->color = RB_RED;
+			sibl->color = RB_BLACK;
+			if (is_left_child(n))
+				left_rotate(tree, n->up);
+			else
+				right_rotate(tree, n->up);
+			sibl = sibling(n);
+		}
+
+		if (n->up->color == RB_BLACK &&
+			sibl->color == RB_BLACK &&
+			(sibl->left == NULL || sibl->left->color == RB_BLACK) &&
+			(sibl->right == NULL || sibl->right->color == RB_BLACK))
+		{
+			sibl->color = RB_RED;
+			delete_rebalance(tree, n->up);
+		}
+		else
+		{
+			if (n->up->color == RB_RED &&
+				sibl->color == RB_BLACK &&
+				(sibl->left == NULL || sibl->left->color == RB_BLACK) &&
+				(sibl->right == NULL || sibl->right->color == RB_BLACK))
+			{
+				sibl->color = RB_RED;
+				n->up->color = RB_BLACK;
+			}
+			else
+			{
+				if (is_left_child(n) && 
+					sibl->color == RB_BLACK &&
+					sibl->left && sibl->left->color == RB_RED && 
+					(sibl->right == NULL || sibl->right->color == RB_BLACK))
+				{
+					sibl->color = RB_RED;
+					sibl->left->color = RB_BLACK;
+					right_rotate(tree, sibl);
+					
+					sibl = sibling(n);
+				}
+				else if (is_right_child(n) &&
+					sibl->color == RB_BLACK &&
+					sibl->right && sibl->right->color == RB_RED &&
+					(sibl->left == NULL || sibl->left->color == RB_BLACK))
+				{
+					sibl->color = RB_RED;
+					sibl->right->color = RB_BLACK;
+					left_rotate(tree, sibl);
+
+					sibl = sibling(n);
+				}
+
+				sibl->color = n->up->color;
+				n->up->color = RB_BLACK;
+				if (is_left_child(n))
+				{
+					sibl->right->color = RB_BLACK;
+					left_rotate(tree, n->up);
+				}
+				else
+				{
+					sibl->left->color = RB_BLACK;
+					right_rotate(tree, n->up);
+				}
+			}
+		}
+	}
+}
+
+/* cp_rbtree_delete_impl - delete one node from a red black tree */
+void *cp_rbtree_delete_impl(cp_rbtree *tree, void *key)
+{
+	void *res = NULL;
+	cp_rbnode *node; 
+	int cmp;
+
+	node = tree->root;
+	while (node)
+	{
+		cmp = (*tree->cmp)(node->key, key);
+		if (cmp < 0)
+			node = node->right;
+		else if (cmp > 0)
+			node = node->left;
+		else /* found */
+			break;
+	}
+
+	if (node) /* may be null if not found */
+	{
+		cp_rbnode *child; 
+		res = node->value;
+		tree->items--;
+
+		if (node->right && node->left)
+		{
+			cp_rbnode *surrogate = node;
+			node = node->right;
+			while (node->left) node = node->left;
+			swap_node_content(node, surrogate);
+		}
+		child = node->right ? node->right : node->left;
+
+		/* if the node was red - no rebalancing required */
+		if (node->color == RB_BLACK)
+		{
+			if (child)
+			{
+				/* single red child - paint it black */
+				if (child->color == RB_RED)
+					child->color = RB_BLACK; /* and the balance is restored */
+				else
+					delete_rebalance(tree, child);
+			}
+			else 
+				delete_rebalance(tree, node);
+		}
+
+		rb_unlink(tree, node);
+		cp_rbtree_destroy_node(tree, node);
+	}
+
+	return res;
+}
+
+/* cp_rbtree_delete - deletes the value mapped to the given key from the tree
+ * and returns the value removed. 
+ */
+void *cp_rbtree_delete(cp_rbtree *tree, void *key)
+{
+	void *res = NULL;
+
+	if (cp_rbtree_txlock(tree, COLLECTION_LOCK_WRITE)) return NULL;
+
+	res = cp_rbtree_delete_impl(tree, key);
+
+	cp_rbtree_txunlock(tree);
+	return res;
+}
+
+static int 
+	rb_scan_pre_order(cp_rbnode *node, cp_callback_fn callback, void *prm)
+{
+	int rc;
+	
+	if (node) 
+	{
+		if ((rc = (*callback)(node, prm))) return rc;
+		if ((rc = rb_scan_pre_order(node->left, callback, prm))) return rc;
+		if ((rc = rb_scan_pre_order(node->right, callback, prm))) return rc;
+	}
+
+	return 0;
+}
+
+int cp_rbtree_callback_preorder(cp_rbtree *tree, 
+								cp_callback_fn callback, 
+								void *prm)
+{
+	int rc;
+
+	if ((rc = cp_rbtree_txlock(tree, COLLECTION_LOCK_READ))) return rc;
+	rc = rb_scan_pre_order(tree->root, callback, prm);
+	cp_rbtree_txunlock(tree);
+
+	return rc;
+}
+
+static int 
+	rb_scan_in_order(cp_rbnode *node, cp_callback_fn callback, void *prm)
+{
+	int rc;
+	
+	if (node) 
+	{
+		if ((rc = rb_scan_in_order(node->left, callback, prm))) return rc;
+		if ((rc = (*callback)(node, prm))) return rc;
+		if ((rc = rb_scan_in_order(node->right, callback, prm))) return rc;
+	}
+
+	return 0;
+}
+
+int cp_rbtree_callback(cp_rbtree *tree, cp_callback_fn callback, void *prm)
+{
+	int rc;
+
+	if ((rc = cp_rbtree_txlock(tree, COLLECTION_LOCK_READ))) return rc;
+	rc = rb_scan_in_order(tree->root, callback, prm);
+	cp_rbtree_txunlock(tree);
+
+	return rc;
+}
+
+static int 
+	rb_scan_post_order(cp_rbnode *node, cp_callback_fn callback, void *prm)
+{
+	int rc;
+	
+	if (node) 
+	{
+		if ((rc = rb_scan_post_order(node->left, callback, prm))) return rc;
+		if ((rc = rb_scan_post_order(node->right, callback, prm))) return rc;
+		if ((rc = (*callback)(node, prm))) return rc;
+	}
+
+	return 0;
+}
+
+int cp_rbtree_callback_postorder(cp_rbtree *tree, 
+								 cp_callback_fn callback, 
+								 void *prm)
+{
+	int rc;
+
+	if ((rc = cp_rbtree_txlock(tree, COLLECTION_LOCK_READ))) return rc;
+	rc = rb_scan_post_order(tree->root, callback, prm);
+	cp_rbtree_txunlock(tree);
+
+	return rc;
+}
+
+int cp_rbtree_count(cp_rbtree *tree)
+{
+	return tree->items;
+}
+
+
+void cp_rbnode_print(cp_rbnode *node, int level)
+{
+	int i;
+	if (node->right) cp_rbnode_print(node->right, level + 1);
+	for (i = 0; i < level; i++) printf("  . ");
+	printf("(%d) [%s => %s]\n", node->color, (char *) node->key, (char *) node->value);
+	if (node->left) cp_rbnode_print(node->left, level + 1);
+}
+
+void cp_rbnode_multi_print(cp_rbnode *node, int level)
+{
+	int i;
+	cp_vector *v = node->value;
+	if (node->right) cp_rbnode_multi_print(node->right, level + 1);
+	
+	for (i = 0; i < level; i++) printf("  . ");
+	printf("(%d) [%s => ", node->color, (char *) node->key);
+
+	for (i = 0; i < cp_vector_size(v); i++)
+		printf("%s; ", (char *) cp_vector_element_at(v, i));
+
+	printf("]\n");
+
+	if (node->left) cp_rbnode_multi_print(node->left, level + 1);
+}
+
+void cp_rbtree_dump(cp_rbtree *tree)
+{
+	if (tree->root) 
+	{
+		if (tree->mode & COLLECTION_MODE_MULTIPLE_VALUES)
+			cp_rbnode_multi_print(tree->root, 0);
+		else
+			cp_rbnode_print(tree->root, 0);
+	}
+}
+
+/* set tree to use given mempool or allocate a new one if pool is NULL */
+int cp_rbtree_use_mempool(cp_rbtree *tree, cp_mempool *pool)
+{
+	int rc = 0;
+	
+	if ((rc = cp_rbtree_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
+	
+	if (pool)
+	{
+		if (pool->item_size < sizeof(cp_rbnode))
+		{
+			rc = EINVAL;
+			goto DONE;
+		}
+		if (tree->mempool) 
+		{
+			if (tree->items) 
+			{
+				rc = ENOTEMPTY;
+				goto DONE;
+			}
+			cp_mempool_destroy(tree->mempool);
+		}
+		cp_mempool_inc_refcount(pool);
+		tree->mempool = pool;
+	}
+	else
+	{
+		tree->mempool = 
+			cp_mempool_create_by_option(COLLECTION_MODE_NOSYNC, 
+										sizeof(cp_rbnode), 0);
+		if (tree->mempool == NULL) 
+		{
+			rc = ENOMEM;
+			goto DONE;
+		}
+	}
+
+DONE:
+	cp_rbtree_txunlock(tree);
+	return rc;
+}
+
+
+/* set tree to use a shared memory pool */
+int cp_rbtree_share_mempool(cp_rbtree *tree, cp_shared_mempool *pool)
+{
+	int rc;
+
+	if ((rc = cp_rbtree_txlock(tree, COLLECTION_LOCK_WRITE))) return rc;
+
+	if (tree->mempool)
+	{
+		if (tree->items)
+		{
+			rc = ENOTEMPTY;
+			goto DONE;
+		}
+
+		cp_mempool_destroy(tree->mempool);
+	}
+
+	tree->mempool = cp_shared_mempool_register(pool, sizeof(cp_rbnode));
+	if (tree->mempool == NULL) 
+	{
+		rc = ENOMEM;
+		goto DONE;
+	}
+	
+DONE:
+	cp_rbtree_txunlock(tree);
+	return rc;
+}
+

Added: branches/multicore/numpy/core/cprops_thread/rb.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/rb.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/rb.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,194 @@
+#ifndef _CP_RB_H
+#define _CP_RB_H
+
+/** @{ */
+/**
+ * @file
+ *
+ * red-black tree definitions. Red-black trees are self balancing binary trees. 
+ * red-black trees guarantee a O(log n) time for tree operations. An advantage
+ * over AVL trees is in that insertion and deletion require a small number of 
+ * rotations (2 or 3) at the most.
+ *
+ * First introduced by Rudolf Bayer in Symmetric Binary B-Trees: Data 
+ * Structures and Maintenance Algorithms, 1972.
+ * The 'red-black' terminology is due to Leo J. Guibas and Robert Sedgewick: 
+ * A Dichromatic Framework for Balanced Trees, 1978.
+ */
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+#include "vector.h"
+#include "mempool.h"
+
+struct _cp_rbtree;
+
+#define RB_RED    0
+#define RB_BLACK  1
+
+typedef CPROPS_DLL struct _cp_rbnode
+{
+	void *key;
+	void *value;
+
+	/* balance maintainance - color is either 'red' or 'black' */
+	int color;
+
+	struct _cp_rbnode *left;
+	struct _cp_rbnode *right;
+	struct _cp_rbnode *up;
+} cp_rbnode;
+
+/* (internal) allocate a new node */
+CPROPS_DLL
+cp_rbnode *cp_rbnode_create(void *key, void *value, struct _cp_mempool *pool);
+/* (internal) deallocate a node */
+CPROPS_DLL
+void cp_rbtree_destroy_node(struct _cp_rbtree *owner, cp_rbnode *node);
+/* (internal) deallocate a node and its subnodes */
+CPROPS_DLL
+void cp_rbtree_destroy_node_deep(struct _cp_rbtree *owner, cp_rbnode *node);
+
+/* tree wrapper object */
+typedef CPROPS_DLL struct _cp_rbtree
+{
+	cp_rbnode *root;             /* root node */
+	
+	int items;                   /* item count */
+
+	int mode;					 /* mode flags */
+	cp_compare_fn cmp;           /* key comparison function */
+	cp_copy_fn key_copy;         /* key copy function */
+	cp_destructor_fn key_dtr;    /* key destructor */
+	cp_copy_fn value_copy;       /* value copy function */
+	cp_destructor_fn value_dtr;  /* value destructor */
+
+	cp_lock *lock;
+	cp_thread txowner;           /* set if a transaction is in progress */
+	int txtype;                  /* lock type */
+
+	cp_mempool *mempool; 		 /* optional memory pool */
+} cp_rbtree;
+
+/* 
+ * default create function - equivalent to create_by_option with mode 
+ * COLLECTION_MODE_NOSYNC
+ */
+CPROPS_DLL
+cp_rbtree *cp_rbtree_create(cp_compare_fn cmp);
+/*
+ * complete parameter create function. Note that setting COLLECTION_MODE_COPY
+ * without specifying a copy function for either keys or values will result in
+ * keys or values respectively being inserted by value, with no copying 
+ * performed. Similarly, setting COLLECTION_MODE_DEEP without specifying a 
+ * destructor function for keys or values will result in no destructor call
+ * for keys or values respectively. This allows using the copy/deep mechanisms
+ * for keys only, values only or both.
+ */
+CPROPS_DLL
+cp_rbtree *
+	cp_rbtree_create_by_option(int mode, cp_compare_fn cmp, 
+							   cp_copy_fn key_copy, cp_destructor_fn key_dtr,
+							   cp_copy_fn val_copy, cp_destructor_fn val_dtr);
+/* 
+ * recursively destroy the tree structure 
+ */
+CPROPS_DLL
+void cp_rbtree_destroy(cp_rbtree *tree);
+/*
+ * recursively destroy the tree structure with the given destructor functions
+ */
+CPROPS_DLL
+void cp_rbtree_destroy_custom(cp_rbtree *tree, 
+							  cp_destructor_fn key_dtr,
+							  cp_destructor_fn val_dtr);
+
+/* insertion function */
+CPROPS_DLL
+void *cp_rbtree_insert(cp_rbtree *tree, void *key, void *value);
+/* retrieve the value mapped to the given key */
+CPROPS_DLL
+void *cp_rbtree_get(cp_rbtree *tree, void *key);
+/* return non-zero if a mapping for 'key' could be found */
+CPROPS_DLL
+int cp_rbtree_contains(cp_rbtree *tree, void *key);
+/* delete a mapping */
+CPROPS_DLL
+void *cp_rbtree_delete(cp_rbtree *tree, void *key);
+
+/* 
+ * perform a pre-order iteration over the tree, calling 'callback' on each 
+ * node
+ */
+CPROPS_DLL
+int cp_rbtree_callback_preorder(cp_rbtree *tree, 
+								cp_callback_fn callback, 
+								void *prm);
+/* 
+ * perform an in-order iteration over the tree, calling 'callback' on each 
+ * node
+ */
+CPROPS_DLL
+int cp_rbtree_callback(cp_rbtree *tree, cp_callback_fn callback, void *prm);
+/* 
+ * perform a post-order iteration over the tree, calling 'callback' on each 
+ * node
+ */
+
+CPROPS_DLL
+int cp_rbtree_callback_postorder(cp_rbtree *tree, 
+								 cp_callback_fn callback, 
+								 void *prm);
+
+/* return the number of mappings in the tree */
+CPROPS_DLL
+int cp_rbtree_count(cp_rbtree *tree);
+
+/* 
+ * lock tree for reading or writing as specified by type parameter. 
+ */
+CPROPS_DLL
+int cp_rbtree_lock(cp_rbtree *tree, int type);
+/* read lock */
+#define cp_rbtree_rdlock(tree) (cp_rbtree_lock((tree), COLLECTION_LOCK_READ))
+/* write lock */
+#define cp_rbtree_wrlock(tree) (cp_rbtree_lock((tree), COLLECTION_LOCK_WRITE))
+/* unlock */
+CPROPS_DLL
+int cp_rbtree_unlock(cp_rbtree *tree);
+
+
+/* return the table mode indicator */
+CPROPS_DLL
+int cp_rbtree_get_mode(cp_rbtree *tree);
+/* set mode bits on the tree mode indicator */
+CPROPS_DLL
+int cp_rbtree_set_mode(cp_rbtree *tree, int mode);
+/* unset mode bits on the tree mode indicator. if unsetting 
+ * COLLECTION_MODE_NOSYNC and the tree was not previously synchronized, the 
+ * internal synchronization structure is initalized.
+ */
+CPROPS_DLL
+int cp_rbtree_unset_mode(cp_rbtree *tree, int mode);
+
+
+/** print tree to stdout */
+CPROPS_DLL
+void cp_rbtree_dump(cp_rbtree *tree);
+
+/* set tree to use given mempool or allocate a new one if pool is NULL */
+CPROPS_DLL
+int cp_rbtree_use_mempool(cp_rbtree *tree, cp_mempool *pool);
+
+/* set tree to use a shared memory pool */
+CPROPS_DLL
+int cp_rbtree_share_mempool(cp_rbtree *tree, struct _cp_shared_mempool *pool);
+
+__END_DECLS
+
+/** @} */
+
+#endif
+

Added: branches/multicore/numpy/core/cprops_thread/tests/main.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/tests/main.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/tests/main.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,52 @@
+#include <time.h>
+#include <unistd.h>
+
+pid_t getpid(void);
+
+#include "thread.h"
+
+
+void* worker_task(void* blah)
+{
+    pid_t pid;
+    pid = getpid();
+// fixme: what is up with sleep?  How do we get the unix style sleep?    
+#ifdef _WINDOWS
+    _sleep(1000);
+#else
+    sleep(1);
+#endif
+    printf("hello from: %d\n", pid);
+}
+
+int main()
+{
+    time_t t1, t2;
+    float seconds;
+    pid_t pid;
+    int i;
+    cp_thread_pool* thread_pool;
+    cp_thread* thread;
+        
+    thread_pool = cp_thread_pool_create(4, 4);
+    
+    pid = getpid();
+    printf("main thread id: %d\n", pid);
+    
+    t1 = clock();
+    
+    for (i=0;i<8;i++)
+    {
+        thread = cp_thread_pool_get(thread_pool, worker_task, NULL);
+        printf("task %d started on thread %d.\n", i+1, thread);
+    }
+    
+    /* wait for all threads to finish executing */
+    cp_thread_pool_wait(thread_pool);
+    
+    t2 = clock();
+    
+    seconds = ((float)(t2-t1))/CLOCKS_PER_SEC;
+    printf("runtime: %d %d %d\n", t1, t2, CLOCKS_PER_SEC);
+	return 1;
+}


Property changes on: branches/multicore/numpy/core/cprops_thread/tests/main.c
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/multicore/numpy/core/cprops_thread/thread.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/thread.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/thread.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,703 @@
+#include <stdio.h>
+#include "thread.h"
+#include "common.h"
+#include "log.h"
+
+/**
+ * @addtogroup cp_thread
+ */
+/** @{ */
+
+#include <stdlib.h>
+#include <time.h>
+#include <errno.h>
+
+#ifdef _WINDOWS
+#define __WINDOWS_WINNT 0x0400
+#include <Windows.h>
+#endif
+
+/** internal function to return a cp_pooled_thread to the available pool */
+static int cp_thread_pool_set_available(cp_thread_pool *owner, cp_pooled_thread *pt);
+
+long cp_pooled_thread_get_id(cp_pooled_thread *pt)
+{
+	long id = 0;
+#ifdef CP_HAS_PTHREAD_GETUNIQUE_NP
+	pthread_getunique_np(*pt->worker, &id);
+#else
+	id = (long) *pt->worker;
+#endif
+
+	return id;
+}
+
+cp_pooled_thread *cp_pooled_thread_create(cp_thread_pool *owner)
+{
+	int rc;
+	cp_pooled_thread *pt = calloc(1, sizeof(cp_pooled_thread));
+
+	if (pt == NULL) 
+	{
+		cp_error(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate pooled thread");
+		errno = ENOMEM;
+		return NULL;
+	}
+	pt->worker = calloc(1, sizeof(cp_thread));
+	if (pt->worker == NULL)
+	{
+		cp_error(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate thread");
+		errno = ENOMEM;
+		return NULL;
+	}
+		
+	pt->owner = owner;
+
+	pt->suspend_lock = (cp_mutex *) malloc(sizeof(cp_mutex));
+	if (pt->suspend_lock == NULL) 
+		goto THREAD_CREATE_CANCEL;
+	if ((rc = cp_mutex_init(pt->suspend_lock, NULL)))
+	{
+		cp_error(rc, "starting up pooled thread");
+		goto THREAD_CREATE_CANCEL;
+	}
+
+	pt->suspend_cond = (cp_cond *) malloc(sizeof(cp_cond));
+	if ((rc = cp_cond_init(pt->suspend_cond, NULL)))
+	{
+		cp_error(rc, "starting up pooled thread");
+		cp_mutex_destroy(pt->suspend_lock);
+		free(pt->suspend_lock);
+		goto THREAD_CREATE_CANCEL;
+	}
+
+	pt->done = 0;
+	pt->wait = 1;
+
+	cp_thread_create(*pt->worker, NULL, cp_pooled_thread_run, pt);
+
+	pt->id = cp_pooled_thread_get_id(pt);
+	cp_thread_detach(*pt->worker); //~~ check
+
+	return pt;
+
+THREAD_CREATE_CANCEL:
+	free(pt->worker);
+	free(pt);
+	
+	return NULL;
+}
+		
+int cp_pooled_thread_stop(cp_pooled_thread *pt)
+{
+	int rc = 0;
+
+	cp_mutex_lock(pt->suspend_lock);
+	pt->action = NULL;
+	if (pt->stop_fn)
+	{
+		rc = pt->stop_prm ? (*pt->stop_fn)(pt->stop_prm) : 
+							  (*pt->stop_fn)(pt->action_prm);
+	}
+
+	pt->done = 1;
+	pt->wait = 0;
+
+	cp_cond_signal(pt->suspend_cond);
+	cp_mutex_unlock(pt->suspend_lock);
+
+//	cp_thread_join(*pt->worker, NULL); //~~ rc
+
+	return rc;
+}
+
+void cp_pooled_thread_destroy(cp_pooled_thread *t)
+{
+#ifdef __TRACE__
+	DEBUGMSG("destroying cp_pooled_thread %lX", t);
+#endif
+	cp_mutex_destroy(t->suspend_lock);
+	free(t->suspend_lock);
+	cp_cond_destroy(t->suspend_cond);
+	free(t->suspend_cond);
+	free(t->worker);
+	free(t);
+}
+
+int cp_pooled_thread_release(cp_pooled_thread *t)
+{
+	return 0;
+}
+
+int cp_pooled_thread_run_task(cp_pooled_thread *pt, 
+						      cp_thread_action action, 
+							  void *prm)
+{
+#ifdef __TRACE__
+	DEBUGMSG("cp_pooled_thread_run_task: action %lx, prm %lx\n", 
+			 (long) action, (long) prm);
+#endif
+
+	pt->action = action;
+	pt->action_prm = prm;
+
+	if (action == NULL)
+	{
+		cp_error(CP_INVALID_FUNCTION_POINTER, "missing thread function");
+		return CP_INVALID_FUNCTION_POINTER;
+	}
+
+	/* signal thread to run */
+	cp_mutex_lock(pt->suspend_lock);
+	pt->wait = 0;
+	cp_cond_signal(pt->suspend_cond);
+	cp_mutex_unlock(pt->suspend_lock);
+
+	return 0;
+}
+
+int cp_pooled_thread_run_stoppable_task(cp_pooled_thread *pt, 
+                                        cp_thread_action action, 
+                                        void *action_prm, 
+                                        cp_thread_stop_fn stop_fn,
+                                        void *stop_prm)
+{
+	pt->stop_fn = stop_fn;
+	pt->stop_prm = stop_prm;
+	return cp_pooled_thread_run_task(pt, action, action_prm);
+}
+
+void *cp_pooled_thread_run(void *prm)
+{
+	cp_pooled_thread *pt = (cp_pooled_thread *) prm;
+
+#ifdef __TRACE__
+	DEBUGMSG("cp_pooled_thread (%lx) starts", (long) pt);
+#endif
+
+	while (!pt->done && pt->owner->running)
+	{
+		cp_mutex_lock(pt->suspend_lock);
+		while (pt->wait && (!pt->done) && pt->owner->running)
+			cp_cond_wait(pt->suspend_cond, pt->suspend_lock);
+		cp_mutex_unlock(pt->suspend_lock);
+
+		if (pt->done || !pt->owner->running) break;
+#ifdef __TRACE__
+		DEBUGMSG("cp_pooled_thread_run: action is %lX, action_prm is %lX", pt->action, pt->action_prm);
+#endif
+		if (pt->action) /* run user defined function if set */
+		{
+#ifdef __TRACE__
+			DEBUGMSG("pooled thread (%lX) handles action (%lX)", (long) pt, (long) pt->action);
+#endif
+			(*pt->action)(pt->action_prm);
+		}
+		if (pt->done || !pt->owner->running) break;
+
+		pt->wait = 1;
+		/* performed work, notify pool */
+		cp_thread_pool_set_available(pt->owner, pt);
+	}
+
+#ifdef __TRACE__
+	DEBUGMSG("cp_pooled_thread (%lx) exits", (long) pt);
+#endif
+
+	cp_pooled_thread_destroy(pt);
+
+	return NULL;
+}
+
+static int cp_thread_pool_set_available(cp_thread_pool *pool, 
+		                                cp_pooled_thread *thread)
+{
+	cp_mutex_lock(pool->pool_lock);
+	cp_hashlist_remove(pool->in_use, &thread->id);
+	cp_list_append(pool->free_pool, thread);
+//	pool->size--;
+ 	cp_cond_signal(pool->pool_cond);
+	cp_mutex_unlock(pool->pool_lock);
+
+	return 0;
+}
+
+	
+int cp_thread_pool_wait(cp_thread_pool *pool)
+{
+	while (cp_hashlist_item_count(pool->in_use) && pool->running)
+	{
+		cp_mutex_lock(pool->pool_lock);
+		cp_cond_wait(pool->pool_cond, pool->pool_lock);
+
+		if (pool->running && 
+			cp_hashlist_item_count(pool->in_use)) /* wake up someone else */
+			cp_cond_signal(pool->pool_cond);
+		cp_mutex_unlock(pool->pool_lock);
+	}
+
+	return 0;
+}
+
+int cp_thread_pool_stop(cp_thread_pool *pool)
+{
+	cp_hashlist_iterator *i;
+	cp_list_iterator *j;
+	cp_pooled_thread *pt;
+
+	pool->running = 0;
+
+	i = cp_hashlist_create_iterator(pool->in_use, COLLECTION_LOCK_READ);
+	while ((pt = (cp_pooled_thread *) cp_hashlist_iterator_next_value(i)))
+		cp_pooled_thread_stop(pt);
+	cp_hashlist_iterator_destroy(i);
+
+	j = cp_list_create_iterator(pool->free_pool, COLLECTION_LOCK_READ);
+	while ((pt = (cp_pooled_thread *) cp_list_iterator_next(j)))
+		cp_pooled_thread_stop(pt);
+	cp_list_iterator_destroy(j);
+
+	return 0;
+}
+
+cp_thread_pool *cp_thread_pool_create(int min_size, int max_size)
+{
+	int rc;
+	cp_thread_pool *pool = calloc(1, sizeof(cp_thread_pool));
+	if (pool == NULL)
+		cp_fatal(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate thread pool structure");
+
+	pool->min_size = min_size;
+	pool->max_size = max_size;
+
+	pool->running = 1;
+
+	pool->free_pool = cp_list_create();
+	if (pool->free_pool == NULL)
+		cp_fatal(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate thread pool list");
+
+	pool->in_use = cp_hashlist_create(10, cp_hash_long, cp_hash_compare_long);
+	if (pool->in_use == NULL)
+		cp_fatal(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate thread pool running list");
+
+	pool->pool_lock = (cp_mutex *) malloc(sizeof(cp_mutex));
+	if (pool->pool_lock == NULL)
+	{
+		cp_error(CP_MEMORY_ALLOCATION_FAILURE, "can\'t create mutex");
+		goto THREAD_POOL_CREATE_CANCEL;
+	}
+	if ((rc = cp_mutex_init(pool->pool_lock, NULL))) 
+	{
+		cp_error(rc, "can\'t create mutex");
+		goto THREAD_POOL_CREATE_CANCEL;
+	}
+
+	pool->pool_cond = (cp_cond *) malloc(sizeof(cp_cond));
+	if (pool->pool_cond == NULL)
+	{
+		cp_error(rc, "can\'t create condition variable");
+		cp_mutex_destroy(pool->pool_lock);
+		free(pool->pool_lock);
+		goto THREAD_POOL_CREATE_CANCEL;
+	}
+	if ((rc = cp_cond_init(pool->pool_cond, NULL)))
+	{
+		cp_error(rc, "can\'t create condition variable");
+		free(pool->pool_cond);
+		cp_mutex_destroy(pool->pool_lock);
+		free(pool->pool_lock);
+		goto THREAD_POOL_CREATE_CANCEL;
+	}
+
+	for ( ; pool->size < pool->min_size; pool->size++)
+	{
+		cp_pooled_thread *pt = cp_pooled_thread_create(pool);
+		if (pt == NULL)
+		{    
+            char msg[1000];		    
+		    sprintf(msg, "can\'t create thread pool (created %d threads, minimum pool size is %d", pool->size, pool->min_size);
+			cp_fatal(CP_THREAD_CREATION_FAILURE, msg);
+		}
+		cp_list_append(pool->free_pool, pt);
+	}
+
+	return pool;
+
+THREAD_POOL_CREATE_CANCEL:
+	cp_list_destroy_custom(pool->free_pool, 
+			(cp_destructor_fn) cp_pooled_thread_destroy);
+	cp_hashlist_destroy_custom(pool->in_use, NULL, 
+			(cp_destructor_fn) cp_pooled_thread_destroy);
+	free(pool);
+	return NULL;
+}
+
+cp_thread *cp_thread_pool_get_impl(cp_thread_pool *pool, 
+                                   cp_thread_action action, 
+                                   void *action_prm, 
+                                   cp_thread_stop_fn stop_fn,
+                                   void *stop_prm,
+                                   int block)
+{
+	cp_pooled_thread *pt = NULL;
+	cp_mutex_lock(pool->pool_lock);
+		
+#ifdef __TRACE__
+	DEBUGMSG("cp_thread_pool_get_impl (%d) pool size = %d max size = %d\n", block, pool->size, pool->max_size);
+#endif
+
+	pt = cp_list_remove_head(pool->free_pool);
+	if (pt == NULL)
+	{
+		if (pool->size < pool->max_size)
+		{
+			pt = cp_pooled_thread_create(pool);
+			if (pt)
+				pool->size++;
+		}
+
+		if (pt == NULL) /* no thread available and poolsize == max */
+		{
+			if (!block)  /* asked not to block, return NULL */
+			{
+				cp_mutex_unlock(pool->pool_lock);
+				return NULL;
+			}
+
+			/* wait for a thread to be released to the pool */
+#ifdef _WINDOWS
+			cp_mutex_unlock(pool->pool_lock);
+#endif
+			while (pool->running && cp_list_is_empty(pool->free_pool))
+				cp_cond_wait(pool->pool_cond, pool->pool_lock);
+
+			if (pool->running)
+				pt = cp_list_remove_head(pool->free_pool);
+
+			if (pt == NULL) /* shouldn't be happening except for shutdown */
+			{
+				cp_mutex_unlock(pool->pool_lock);
+				return NULL;
+			}
+		}
+	}
+
+	cp_hashlist_append(pool->in_use, &pt->id, pt);
+	cp_mutex_unlock(pool->pool_lock);
+
+	cp_pooled_thread_run_stoppable_task(pt, action, action_prm, stop_fn, stop_prm);
+
+	return pt->worker;
+}
+
+cp_thread *cp_thread_pool_get(cp_thread_pool *pool, 
+						   	  cp_thread_action action, 
+					   		  void *prm)
+{
+	return cp_thread_pool_get_impl(pool, action, prm, NULL, NULL, 1);
+}
+
+cp_thread *cp_thread_pool_get_stoppable(cp_thread_pool *pool, 
+										cp_thread_action action, 
+										void *action_prm, 
+										cp_thread_stop_fn stop_fn, 
+										void *stop_prm)
+{
+	return cp_thread_pool_get_impl(pool, action, action_prm, stop_fn, stop_prm, 1);
+}
+
+cp_thread *cp_thread_pool_get_nb(cp_thread_pool *pool, 
+						  		 cp_thread_action action, 
+						  		 void *prm)
+{
+	return cp_thread_pool_get_impl(pool, action, prm, NULL, NULL, 0);
+}
+	
+cp_thread *cp_thread_pool_get_stoppable_nb(cp_thread_pool *pool, 
+						  		 		   cp_thread_action action, 
+						  		 		   void *action_prm,
+								 		   cp_thread_stop_fn stop_fn, 
+								 		   void *stop_prm)
+{
+	return cp_thread_pool_get_impl(pool, action, action_prm, stop_fn, stop_prm, 0);
+}
+
+void cp_thread_pool_destroy(cp_thread_pool *pool)
+{
+#ifdef __TRACE__
+	DEBUGMSG("stopping cp_thread_pool %lX", pool);
+#endif
+
+	if (pool->running) cp_thread_pool_stop(pool);
+
+	cp_list_destroy(pool->free_pool);
+//	cp_list_destroy_custom(pool->free_pool, 
+//				(cp_destructor_fn) cp_pooled_thread_destroy);
+	cp_hashlist_destroy(pool->in_use);
+//	cp_hashlist_destroy_custom(pool->in_use, NULL, 
+//				(cp_destructor_fn) cp_pooled_thread_destroy);
+	cp_mutex_destroy(pool->pool_lock);
+	free(pool->pool_lock);
+	cp_cond_destroy(pool->pool_cond);
+	free(pool->pool_cond);
+
+	free(pool);
+}
+
+int cp_thread_pool_count_available(cp_thread_pool *pool)
+{
+	return (pool->max_size - pool->size) + 
+			cp_list_item_count(pool->free_pool);
+}
+
+
+/* **************************************************************************
+ *                                                                          *
+ *                      thread management framework                         *
+ *                                                                          *
+ ************************************************************************** */
+
+cp_pooled_thread_client_interface *
+	cp_pooled_thread_client_interface_create
+		(cp_pooled_thread_scheduler *owner, 
+		 void *client, 
+		 int min_threads, 
+		 int max_threads,
+		 cp_pooled_thread_report_load report_load,
+		 cp_pooled_thread_shrink shrink,
+		 cp_thread_action action,
+		 void *action_prm, 
+		 cp_thread_stop_fn stop_fn, 
+		 void *stop_prm)
+{
+	cp_pooled_thread_client_interface *ci = 
+		calloc(1, sizeof(cp_pooled_thread_client_interface));
+	if (client == NULL)
+		cp_fatal(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate thread pool client interface");
+
+	ci->owner = owner;
+	ci->client = client;
+	ci->min = min_threads;
+	ci->max = max_threads;
+	ci->report_load = report_load;
+	ci->shrink = shrink;
+	ci->action = action;
+	ci->action_prm = action_prm;
+	ci->stop_fn = stop_fn;
+	ci->stop_prm = stop_prm;
+
+	cp_pooled_thread_scheduler_register_client(owner, ci);
+
+	return ci;
+}
+
+
+void cp_pooled_thread_client_interface_destroy
+	(cp_pooled_thread_client_interface *client)
+{
+	free(client);
+}
+
+cp_pooled_thread_scheduler *cp_pooled_thread_scheduler_create(cp_thread_pool *pool)
+{
+	cp_pooled_thread_scheduler *scheduler = 
+		calloc(1, sizeof(cp_pooled_thread_scheduler));
+	if (scheduler == NULL)
+		cp_fatal(CP_MEMORY_ALLOCATION_FAILURE, "can\'t allocate thread manager");
+
+	scheduler->pool = pool;
+	scheduler->client_list = cp_vector_create(20);
+
+#ifdef CP_HAS_SRANDOM
+	srandom(time(NULL));
+#else
+	srand(time(NULL));
+#endif
+
+	return scheduler;
+}
+
+void cp_pooled_thread_scheduler_destroy(cp_pooled_thread_scheduler *scheduler)
+{
+	cp_vector_destroy(scheduler->client_list);
+	free(scheduler);
+}
+
+void cp_pooled_thread_scheduler_register_client
+		(cp_pooled_thread_scheduler *scheduler, 
+		 cp_pooled_thread_client_interface *client)
+{
+	cp_vector_add_element(scheduler->client_list, client);
+}
+
+cp_pooled_thread_client_interface *
+	choose_random_client(cp_pooled_thread_scheduler *scheduler)
+{
+	int index = 
+#ifdef CP_HAS_RANDOM
+		random() 
+#else
+		rand()
+#endif
+		% (cp_vector_size(scheduler->client_list));
+	return (cp_pooled_thread_client_interface *) 
+		cp_vector_element_at(scheduler->client_list, index);
+}
+
+#define SCHEDULER_THRESHOLD 1
+
+void cp_pooled_thread_client_get_nb(cp_pooled_thread_client_interface *c)
+{
+	if (cp_thread_pool_get_nb(c->owner->pool, c->action, c->action_prm))
+		c->count++; 
+}
+
+void cp_pooled_thread_client_get(cp_pooled_thread_client_interface *c)
+{
+	c->count++;
+	cp_thread_pool_get(c->owner->pool, c->action, c->action_prm);
+}
+
+void cp_pooled_thread_client_get_stoppable_nb(cp_pooled_thread_client_interface *c)
+{
+	if (cp_thread_pool_get_stoppable_nb(c->owner->pool, c->action, c->action_prm, c->stop_fn, c->stop_prm))
+		c->count++; 
+}
+
+void cp_pooled_thread_client_get_stoppable(cp_pooled_thread_client_interface *c)
+{
+	c->count++;
+	cp_thread_pool_get_stoppable(c->owner->pool, c->action, c->action_prm, c->stop_fn, c->stop_prm);
+}
+
+#if 0 //~~ for future optimization
+void cp_pooled_thread_client_negociate(cp_pooled_thread_client_interface *c)
+{
+	int curr_load = (*c->report_load)(c);
+	cp_pooled_thread_scheduler *scheduler = c->owner;
+	Vector *clients = scheduler->client_list;
+	int i, min, imin, max, imax, cval, max_count;
+	cp_pooled_thread_client_interface *other;
+
+	int clen = cp_vector_size(clients);
+
+	if (clen == 0) return; //~~ warning for bad usage
+
+	min = INT_MAX;
+	max = -1;
+	max_count = -1;
+
+	for (i = 0; i < clen; i++)
+	{
+		other = (cp_pooled_thread_client_interface *) cp_vector_element_at(clients, i);
+		cval = (*other->report_load)(other);
+
+		if (other->count < other->min) //~~ what's with the switching
+			cp_thread_pool_get_nb(other->owner->pool, other->action, other->prm);
+
+		DEBUGMSG("negociate: pool %d: load = %d, %d <= %d <= %d", i, cval, other->min, other->count, other->max);
+		if (cval > max) { max = cval; imax = i; }
+		if (cval < min || (cval == min && other->count > max_count)) { min = cval; imin = i; max_count = other->count; }
+	}
+	DEBUGMSG("negociate: min = %d, max = %d", min, max);
+	if (abs(max - min) > SCHEDULER_THRESHOLD)
+	{
+		cp_pooled_thread_client_interface *maxc = cp_vector_element_at(clients, imax);
+		cp_pooled_thread_client_interface *minc = cp_vector_element_at(clients, imin);
+
+		if (cp_thread_pool_count_available(scheduler->pool) == 0 &&
+			minc->count > minc->min)
+		{
+			DEBUGMSG("negociate: shrinking min pool (%d)", imin);
+			(*minc->shrink)(minc);
+		}
+			
+		DEBUGMSG("negociate: get_nb for max pool (%d)", imax);
+		if (cp_thread_pool_get_nb(maxc->owner->pool, maxc->action, maxc->prm))
+			maxc->count++;
+	}
+}
+		
+#endif
+
+void cp_pooled_thread_client_negociate(cp_pooled_thread_client_interface *c)
+{
+	int curr_load;
+	if (c->owner->bypass) return;
+
+	curr_load = (*c->report_load)(c);
+
+#ifdef __TRACE__
+	DEBUGMSG("negociate for client %lx - load == %d\n", (long) c, curr_load);
+#endif
+	/* if needed, try get idle thread from pool */
+	if (curr_load > SCHEDULER_THRESHOLD && c->count < c->max) 
+	{
+		cp_thread *t = 
+			cp_thread_pool_get_nb(c->owner->pool, c->action, c->action_prm);
+		if (t) /* got a thread, return */
+		{
+#ifdef __TRACE__
+	DEBUGMSG("negociate: got thread from pool");
+#endif
+			c->count++;
+			return;
+		}
+	}
+
+	/* 
+	 * following code runs if 
+	 * 
+	 * (1) no threads needed - check if someone else (other client) needs one
+	 * 
+ 	 * or
+	 * 
+	 * (2) thread needed but no idle threads in pool, ask someone else
+	 */
+	{
+		int other_load;
+		int *inc; /* the thread count to be incremented on switch */
+		cp_thread *t;
+		cp_pooled_thread_client_interface *load, *unload;
+		cp_pooled_thread_client_interface *other = 
+			choose_random_client(c->owner);
+
+		other_load = (*other->report_load)(other);
+		if (abs(curr_load - other_load) < SCHEDULER_THRESHOLD) return; 
+		if (curr_load > other_load) /* other releases thread */
+		{
+			if (c->count >= c->max || 
+				other->count <= other->min) return; /* no switch */
+#ifdef __TRACE__
+			DEBUGMSG("negociate: switching a thread to this pool");
+#endif
+			inc = &c->count;
+			other->count--;
+			load = c;
+			unload = other;
+		}
+		else /* client releases thread */
+		{
+			if (c->count <= c->min ||
+				other->count >= other->max) return; /* no switch */
+#ifdef __TRACE__
+			DEBUGMSG("negociate: switching a thread to other pool");
+#endif
+			inc = &other->count;
+			c->count--;
+			load = other;
+			unload = c;
+		}
+#ifdef __TRACE__
+		DEBUGMSG("negociate: shrinking unload pool");
+#endif
+		(*unload->shrink)(unload);
+		t = cp_thread_pool_get_nb(load->owner->pool, //~~ get_nb?
+							   load->action, load->action_prm); 
+
+		if (t) (*inc)++; //~~ maybe better to get blocking and be sure?
+	}
+}
+
+/** @} */
+

Added: branches/multicore/numpy/core/cprops_thread/thread.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/thread.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/thread.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,374 @@
+#ifndef _CP_THREAD_H
+#define _CP_THREAD_H
+
+/**
+ * @addtogroup cp_thread
+ */
+/** @{ */
+/** 
+ * @file
+ * definitions for the thread management framework. the
+ * current implementation is based on the POSIX thread api. 
+ */
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+#include "cp_config.h"
+/* synchronization api abstraction (a bunch of pthread-like macros basically)
+ * is in collection.h
+ */
+#include "collection.h"
+#include "linked_list.h"
+#include "hashlist.h"
+#include "vector.h"
+
+/** a thread function */
+typedef void *(*cp_thread_action) (void *);
+
+
+/** a stop function for client threads */
+typedef int (*cp_thread_stop_fn)(void *);
+
+/**
+ * cp_pooled_thread is a thread that lives in a thread_pool. The struct holds 
+ * synchronization elements used to control the thread and actuation settings, 
+ * i.e. a thread function and a parameter to be passed for the next starting 
+ * thread. The pool initializes a bunch of threads and sets them in 'wait'. 
+ *
+ * When a client requests threads from the pool, the next available thread is
+ * signalled out of 'wait', and runs the thread function requested by the 
+ * client (see cp_thread_pool_get_impl). When the client thread function is 
+ * done, the cp_pooled_thread returns to the thread pool and becomes available 
+ * to pool clients. The cp_pooled_thread only exits when the pool exits, unless
+ * explicitly stopped (eg pthread_exit) by client code. 
+ */ 
+typedef CPROPS_DLL struct _cp_pooled_thread
+{
+	long id;						///< integral (implementation specific) thread id
+	struct _cp_thread_pool *owner;	///< the pool this thread belongs to
+	cp_thread *worker;				///< the actual thread
+	cp_thread_action action;		///< thread function for the next assignment
+	void *action_prm;				///< parameter for the next assignment
+	cp_thread_stop_fn stop_fn;		///< called on cp_pooled_thread_stop
+	void *stop_prm;					///< if not set, stop_fn invoked w/ action_prm
+
+	cp_mutex *suspend_lock;			///< lock for framework scheduling
+	cp_cond *suspend_cond;			///< condition variable for framework scheduling
+
+	int done;						///< done flag
+	int wait;						///< wait flag
+} cp_pooled_thread;
+
+/** return a thread id for this thread */
+CPROPS_DLL
+long cp_pooled_thread_get_id(cp_pooled_thread *thread);
+
+/** thread constructor function */
+CPROPS_DLL
+cp_pooled_thread *cp_pooled_thread_create(struct _cp_thread_pool *owner);
+
+/** thread destructor */
+CPROPS_DLL
+void cp_pooled_thread_destroy(cp_pooled_thread *t);
+
+/** signal a thread to stop */
+CPROPS_DLL
+int cp_pooled_thread_stop(cp_pooled_thread *t);
+
+/** retrieve an integer type thread id for this thread */
+CPROPS_DLL
+long cp_pooled_thread_get_id(cp_pooled_thread *t);
+
+/** sets the action and prm for this thread, then invokes 'action' */
+CPROPS_DLL
+int cp_pooled_thread_run_task(cp_pooled_thread *pt, 
+							  cp_thread_action action, 
+							  void *prm);
+
+/** perform action with stop function */
+CPROPS_DLL
+int cp_pooled_thread_run_stoppable_task(cp_pooled_thread *pt, 
+									  	cp_thread_action action,
+									  	void *action_prm,
+									  	cp_thread_stop_fn stop_fn,
+									  	void *stop_prm);
+
+/** framework thread function */
+CPROPS_DLL
+void *cp_pooled_thread_run(void *prm);
+	
+
+/** 
+ * cp_thread_pool holds a list of free threads (in wait mode). The list grows 
+ * up to max_size, after which subsequent calls to cp_thread_pool_get will 
+ * block, and calls to cp_thread_pool_get_nb will return NULL - until clients 
+ * return their threads to the pool. 
+ */
+typedef CPROPS_DLL struct _cp_thread_pool
+{
+	int size;				///< current size
+
+	int min_size;			///< initial size
+	int max_size;			///< size limit
+
+	int running;
+
+	cp_mutex *pool_lock;	///< to sync thread assignment and release
+	cp_cond *pool_cond;		///< to sync thread assignment and release
+
+	cp_list *free_pool;		///< holder for unused threads
+	cp_hashlist *in_use;	///< holder for running threads
+} cp_thread_pool;
+
+/** cp_thread_pool constructor */
+CPROPS_DLL
+cp_thread_pool *cp_thread_pool_create(int min_size, int max_size);
+
+/** cp_thread_pool destructor */
+CPROPS_DLL
+void cp_thread_pool_destroy(cp_thread_pool *pool);
+
+/** wait for threads to finish processing client requests */
+CPROPS_DLL
+int cp_thread_pool_wait(cp_thread_pool *pool);
+
+/** signal all threads in this pool to stop */
+CPROPS_DLL
+int cp_thread_pool_stop(cp_thread_pool *pool);
+
+/** 
+ * request a thread from the pool. If no threads are available, this function
+ * will block until a thread becomes available.
+ */
+CPROPS_DLL 
+cp_thread *cp_thread_pool_get(cp_thread_pool *pool, 
+						   	  cp_thread_action action, 
+						   	  void *prm);
+
+/** 
+ * request a thread from the pool. If no threads are available, this function
+ * will block until a thread becomes available.
+ */
+CPROPS_DLL 
+cp_thread *cp_thread_pool_get_stoppable(cp_thread_pool *pool, 
+						   		  		cp_thread_action action, 
+						   		  		void *action_prm, 
+										cp_thread_stop_fn stop_fn,
+										void *stop_prm);
+
+/** 
+ * request a thread from the pool - non-blocking version. Returns a pointer 
+ * to the requested thread if one is available or NULL if the pool is empty. 
+ */
+CPROPS_DLL 
+cp_thread *cp_thread_pool_get_nb(cp_thread_pool *pool, 
+							  	 cp_thread_action action, 
+							  	 void *prm);
+/** 
+ * request a thread from the pool - non-blocking version. Returns a pointer 
+ * to the requested thread if one is available or NULL if the pool is empty. 
+ */
+CPROPS_DLL 
+cp_thread *cp_thread_pool_get_stoppable_nb(cp_thread_pool *pool, 
+							  	  cp_thread_action action, 
+							  	  void *action_prm,
+								  cp_thread_stop_fn stop_fn,
+								  void *stop_prm);
+
+/** returns the number of available threads in the pool. */
+CPROPS_DLL 
+int cp_thread_pool_count_available(cp_thread_pool *pool);
+
+/* **************************************************************************
+ *                                                                          *
+ *                      thread management framework                         *
+ *                                                                          *
+ ************************************************************************** */
+
+
+/**
+ * Definitions for thread management framework follow. The framework is based
+ * on the cp_thread_pool and cp_pooled_thread types. 
+ * <br>
+ * The pooled thread scheduler interface is meant for use by clients who 
+ * require a variable number of threads. Each such component should create 
+ * an instance of cp_pooled_thread_client_interface and use the api functions
+ * to get threads from the underlying cp_thread_pool. Here is some example
+ * code. 
+ * <p><tt><code><pre>
+ * cp_pooled_thread_scheduler *main_scheduler; 
+ * 
+ * ...
+ *
+ * component_a_start(component_a *a, ...)
+ * {
+ *     a->scheduler_interface = 
+ *         cp_pooled_thread_client_interface_create(main_scheduler, a, 2, 10, 
+ *             component_a_report_load, component_a_stop_thread, 
+ *             component_a_thread_run, a);
+ * 
+ *     ...
+ * 
+ *     for (i = 0; i < a->scheduler_interface->min; i++)
+ *         cp_pooled_thread_client_get(a->scheduler_interface);
+ * }
+ *
+ * component_b_start(component_b *b, ...)
+ * {
+ *     b->scheduler_interface = 
+ *         cp_pooled_thread_client_interface_create(main_scheduler, b, 2, 10, 
+ *             component_a_report_load, component_a_stop_thread, 
+ *             component_a_thread_run, b);
+ * 
+ *     ...
+ * 
+ *     for (i = 0; i < b->scheduler_interface->min; i++)
+ *         cp_pooled_thread_client_get(b->scheduler_interface);
+ * }
+ * 
+ * </tt></code></pre><br>
+ * In this example, the threads for component_a and component_b will be 
+ * managed jointly, since their cp_pooled_thread_client_interface *'s have the 
+ * same cp_pooled_thread_scheduler *. <p>
+ * 
+ * 
+ * See cp_pooled_thread_client_negociate for details. 
+ */
+typedef CPROPS_DLL struct cp_pooled_thread_scheduler
+{
+	cp_thread_pool *pool; ///< pool to operate on
+	cp_vector *client_list; ///< list of clients
+	int bypass; ///< when bypass flag set 'negociate' function becomes nop
+} cp_pooled_thread_scheduler;
+
+CPROPS_DLL struct _cp_pooled_thread_client_interface;
+
+typedef int (*cp_pooled_thread_report_load) //~~ change prm to void *client
+	(struct _cp_pooled_thread_client_interface *s);
+typedef void (*cp_pooled_thread_shrink) //~~ change prm to void *client
+	(struct _cp_pooled_thread_client_interface *);
+
+/**
+ * cp_pooled_thread_client_interface acts as the link to the 
+ * cp_pooled_thread_scheduler for clients that require a variable number of 
+ * threads. This interface holds 3 functions pointers that must be supplied
+ * by a client: <br>
+ * <li> report_load - should return the number of open requests the client has
+ * to handle
+ * <li> shrink - will be called by the framework to stop one client thread 
+ * <li> action - the thread function for this client
+ */
+typedef CPROPS_DLL struct _cp_pooled_thread_client_interface
+{
+	int max;	///< thread count upper limit 
+	int min;	///< thread count bottom limit
+
+	int count;	///< actual number of threads serving this client
+
+	void *client;	///< pointer to client
+	cp_pooled_thread_scheduler *owner;	///< pointer to thread_pool_scheduler
+	cp_pooled_thread_report_load report_load; ///< client function to report load
+	cp_pooled_thread_shrink shrink; ///< client function to stop 1 thread
+	cp_thread_action action; ///< client thread function 
+	void *action_prm; ///< parameter to client thread function (usually == client)
+	cp_thread_stop_fn stop_fn; ///< stop callback 
+	void *stop_prm; ///< parameter to stop callback - if NULL action_prm will be used
+} cp_pooled_thread_client_interface;
+
+/** cp_pooled_thread_client_interface constructor */
+CPROPS_DLL
+cp_pooled_thread_client_interface *
+	cp_pooled_thread_client_interface_create
+		(cp_pooled_thread_scheduler *owner, 
+		 void *client, 
+		 int min_threads, 
+		 int max_threads,
+		 cp_pooled_thread_report_load report_load,
+		 cp_pooled_thread_shrink shrink,
+		 cp_thread_action action,
+		 void *action_prm,
+		 cp_thread_stop_fn stop_fn,
+		 void *stop_prm);
+
+/** cp_pooled_thread_client_interface destructor */
+CPROPS_DLL
+void cp_pooled_thread_client_interface_destroy
+	(cp_pooled_thread_client_interface *client);
+
+/**
+ * threads should call negociate when a change in the number of threads a 
+ * client owns is required. 
+ * Two possible scheduling approaches are -
+ * 
+ * (1) centralized:
+ *     Clients report their load factor to the thread manager. The thread 
+ *     manager grants requests for new threads to clients with higher loads
+ *     first. 
+ * 
+ * (2) distributed:
+ *     clients negociate with other clients requesting a thread based on their
+ *     load factors. The client with the lower load factor releases a thread 
+ *     to the client with the higher load factor. 
+ * 
+ * The distributed approach saves some bookkeeping over head in the thread 
+ * manager, reduces the number steps involved in acquiring a new thread or
+ * releasing an unused one, and makes a dedicated synchronization thread 
+ * unnecessary. <p>
+ * 
+ * In the current implementation, the scheduler will randomly choose one 
+ * other client to negociate with. If the load factors are different enough, 
+ * one thread will be switched to the busier client.
+ */
+CPROPS_DLL
+void cp_pooled_thread_client_negociate(cp_pooled_thread_client_interface *c);
+
+/** cp_pooled_thread_scheduler constructor */
+CPROPS_DLL
+cp_pooled_thread_scheduler *cp_pooled_thread_scheduler_create(cp_thread_pool *pool);
+
+/** cp_pooled_thread_scheduler destructor */
+CPROPS_DLL
+void cp_pooled_thread_scheduler_destroy(cp_pooled_thread_scheduler *scheduler);
+
+/** register client as a client of this scheduler */
+CPROPS_DLL
+void cp_pooled_thread_scheduler_register_client
+		(cp_pooled_thread_scheduler *scheduler, 
+		 cp_pooled_thread_client_interface *client);
+
+/** 
+ * convenience to abstract cp_thread_pool based implementation, see 
+ * cp_pooled_thread_get and cp_pooled_thread_get_nb
+ */
+CPROPS_DLL 
+void cp_pooled_thread_client_get(cp_pooled_thread_client_interface *c);
+
+/** 
+ * convenience to abstract cp_thread_pool based implementation, see 
+ * cp_pooled_thread_get and cp_pooled_thread_get_nb
+ */
+CPROPS_DLL 
+void cp_pooled_thread_client_get_stoppable(cp_pooled_thread_client_interface *c);
+
+/** 
+ * convenience to abstract cp_thread_pool based implementation, see 
+ * cp_pooled_thread_get and cp_pooled_thread_get_nb
+ */
+CPROPS_DLL 
+void cp_pooled_thread_client_get_nb(cp_pooled_thread_client_interface *c);
+
+/** 
+ * convenience to abstract cp_thread_pool based implementation, see 
+ * cp_pooled_thread_get and cp_pooled_thread_get_nb
+ */
+CPROPS_DLL 
+void cp_pooled_thread_client_get_stoppable_nb(cp_pooled_thread_client_interface *c);
+
+__END_DECLS
+
+/** @} */
+
+#endif /* _CP_THREAD */
+


Property changes on: branches/multicore/numpy/core/cprops_thread/thread.h
___________________________________________________________________
Name: svn:executable
   + *

Added: branches/multicore/numpy/core/cprops_thread/vector.c
===================================================================
--- branches/multicore/numpy/core/cprops_thread/vector.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/vector.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,164 @@
+/**
+ * cp_vector is a 'safe array' implementation
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "log.h"
+#include "common.h"
+
+#include "vector.h"
+
+cp_vector *cp_vector_create_by_option(int size, 
+									  int mode, 
+									  cp_copy_fn copy_item,
+									  cp_destructor_fn free_item)
+{
+	cp_vector *v = calloc(1, sizeof(cp_vector));
+	if (v == NULL) 
+	{
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	v->mem = calloc(size, sizeof(void *));
+	if (v->mem == NULL)
+	{
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	v->size = size;
+	v->mode = mode;
+	v->copy_item = copy_item;
+	v->free_item = free_item;
+	v->head = v->tail = 0;
+
+	return v;
+}
+
+cp_vector *cp_vector_create(int size)
+{
+	return cp_vector_create_by_option(size, 0, NULL, NULL);
+}
+
+cp_vector *cp_vector_wrap(void **data, int len, int mode)
+{
+	cp_vector *v = calloc(1, sizeof(cp_vector));
+	if (v == NULL) return NULL;
+
+	v->mem = data;
+	v->size = len;
+	v->mode = mode;
+	v->head = len;
+	v->tail = 0;
+
+	return v;
+}
+
+void cp_vector_destroy(cp_vector *v)
+{
+	if (v)
+	{
+		if ((v->mode & COLLECTION_MODE_DEEP) && v->free_item != NULL)
+		{
+			int i;
+			int n = cp_vector_size(v);
+			void *item;
+			for (i = 0; i < n; i++)
+			{
+				item = cp_vector_element_at(v, i);
+				if (item) (*v->free_item)(item);
+			}
+		}
+		free(v->mem);
+		free(v);
+	}
+}
+
+void cp_vector_destroy_custom(cp_vector *v, cp_destructor_fn dtr)
+{
+	if (v)
+	{
+		int i;
+		int n = cp_vector_size(v);
+
+		if (dtr)
+		{
+			for (i = 0; i < n; i++)
+				if (v->mem[i]) (*dtr)(v->mem[i]);
+		}
+	
+		free(v->mem);
+		free(v);
+	}
+}
+
+void *cp_vector_element_at(cp_vector *v, int index)
+{
+	return index >= 0 && index <= cp_vector_size(v) ? v->mem[index] : NULL;
+}
+
+void *cp_vector_set_element(cp_vector *v, int index, void *element)
+{
+	if (index < 0)
+	{
+		errno = EINVAL;
+		return NULL;
+	}
+
+	if (index >= v->head)
+		v->head = index + 1;
+
+	if (v->head >= v->size)
+	{
+		v->size = index + 2;
+		v->mem = realloc(v->mem, v->size * sizeof(void *));
+	}
+
+	if ((v->mode & COLLECTION_MODE_DEEP) && 
+			v->mem[index] != NULL && v->free_item != NULL)
+		(*v->free_item)(v->mem[index]);
+
+	if ((v->mode & COLLECTION_MODE_COPY) && element != NULL && v->copy_item != NULL)
+		v->mem[index] = (*v->copy_item)(element);
+	else
+		v->mem[index] = element;
+	
+	return element;
+}
+
+void *cp_vector_add_element(cp_vector *v, void *element)
+{
+	void *addr = NULL;
+
+	if (v->head + 1 >= v->tail + v->size)
+	{
+		void **newptr = realloc(v->mem, 2 * v->size * sizeof(void *));
+		if (newptr == NULL) return NULL;
+		v->mem = newptr;
+		if (v->head < v->tail)
+		{
+			memcpy(v->mem, &v->mem[v->size], v->head * sizeof(void *));
+			v->head += v->size;
+		}
+		v->size *= 2;
+	}
+			
+	if (v->mode & COLLECTION_MODE_COPY)
+		v->mem[v->head] = (*v->copy_item)(element);
+	else
+		v->mem[v->head] = element;
+	addr = v->mem[v->head];
+	v->head = (v->head + 1) % v->size;
+
+	return addr;
+}
+
+int cp_vector_size(cp_vector *v)
+{
+	return (v->head - v->tail + v->size) % v->size;
+}
+

Added: branches/multicore/numpy/core/cprops_thread/vector.h
===================================================================
--- branches/multicore/numpy/core/cprops_thread/vector.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/cprops_thread/vector.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,58 @@
+#ifndef _CP_VECTOR_H
+#define _CP_VECTOR_H
+
+#include "common.h"
+
+__BEGIN_DECLS
+
+#include "cp_config.h"
+#include "collection.h"
+
+/**
+ * A simple 'safe array' implementation.
+ */
+typedef CPROPS_DLL struct _cp_vector
+{
+    void **mem;            		 /**< Pointer to memory               */
+    int size;              		 /**< size of vector (element count)  */
+    int head;              		 /**< index of 1st element            */
+    int tail;              		 /**< index of Nth element            */
+
+	int mode;              		 /**< collection mode                 */
+	cp_copy_fn copy_item;        /**< item copy function              */
+	cp_destructor_fn free_item;  /**< item destructor function        */
+	cp_lock *lock;         		 /**< rwlock                          */
+} cp_vector;
+
+CPROPS_DLL
+cp_vector *cp_vector_create_by_option(int size, 
+									  int mode, 
+									  cp_copy_fn copy_item,
+									  cp_destructor_fn free_item);
+CPROPS_DLL
+cp_vector *cp_vector_create(int size);
+CPROPS_DLL
+cp_vector *cp_vector_wrap(void **data, int len, int mode);
+CPROPS_DLL
+void cp_vector_destroy(cp_vector *v);
+CPROPS_DLL
+void cp_vector_destroy_custom(cp_vector *v, cp_destructor_fn dtr);
+CPROPS_DLL
+void *cp_vector_add_element(cp_vector *v, void *element);
+CPROPS_DLL
+void *cp_vector_element_at(cp_vector *v, int index);
+CPROPS_DLL
+void *cp_vector_set_element(cp_vector *v, int index, void *element);
+CPROPS_DLL
+void cp_vector_remove_element(cp_vector *v, int index);
+CPROPS_DLL
+int cp_vector_size(cp_vector *v);
+
+/* ----------------------------------------------------------------- */
+
+__END_DECLS
+
+/** @} */
+
+#endif /* _COLLECTION_VECTOR_H */
+


Property changes on: branches/multicore/numpy/core/cprops_thread/vector.h
___________________________________________________________________
Name: svn:executable
   + *

Modified: branches/multicore/numpy/core/include/numpy/ndarrayobject.h
===================================================================
--- branches/multicore/numpy/core/include/numpy/ndarrayobject.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/include/numpy/ndarrayobject.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -91,8 +91,12 @@
 #error Must use Python with unicode enabled.
 #endif
 
-
-typedef signed char npy_byte;
+/* FIXME: changed npy_byte from signed to unsigned to get it to compile on windows...
+ *        This is JUST FOR TESTING AS IT ISN'T REALLY WHAT WE WANT.  Figure out
+ *        how deal with noprefix.h declaring bytes as a signed byte where a windows.h
+ *        header has declared it as a unsigned byte later...
+ */
+typedef unsigned char npy_byte;
 typedef unsigned char npy_ubyte;
 typedef unsigned short npy_ushort;
 typedef unsigned int npy_uint;

Added: branches/multicore/numpy/core/include/numpy/ufuncthreadapi.h
===================================================================
--- branches/multicore/numpy/core/include/numpy/ufuncthreadapi.h	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/include/numpy/ufuncthreadapi.h	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,23 @@
+#ifndef ufuncthreadapi_h
+#define ufuncthreadapi_h
+
+/* Data structure to hold information about thread settings. */
+
+typedef struct {
+    
+    /* Should ufuncs divide their work between multiple threads */
+    int use_threads;        
+        
+    /* Number of threads to use in threaded operations */
+    int thread_count;  
+    
+    /* Minimum number of elements in an array before threading is used */
+    int element_threshold; 
+
+} UFuncThreadSettings;
+
+
+static PyObject *
+ufunc_setthreading(PyObject *dummy, PyObject *args);
+
+#endif

Modified: branches/multicore/numpy/core/setup.py
===================================================================
--- branches/multicore/numpy/core/setup.py	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/setup.py	2007-04-10 17:54:59 UTC (rev 3692)
@@ -129,7 +129,7 @@
         incl_dir = os.path.dirname(target)
         if incl_dir not in config.numpy_include_dirs:
             config.numpy_include_dirs.append(incl_dir)
-
+        
         config.add_data_files((header_dir,target))
         return target
 
@@ -196,18 +196,47 @@
                          depends = deps,
                          )
 
+    # fixme: later, get this from the configuration.
+    vector_threads = 1
+    
+    umath_include_dirs = []
+    umath_library_dirs = []
+    umath_libraries = []
+
+    if vector_threads==1:
+        cprops_macros = []
+        
+        # update the umath includes/libraries to use the threading library.
+        umath_include_dirs.append('cprops_thread')
+        umath_library_dirs.append('cprops_thread')
+        umath_libraries.append('cprops')
+        
+        if sys.platform == 'win32':
+            # fixme: is this only for gcc, or does msvc need it as well?
+            umath_libraries.append('iberty') # needed for random, srandom
+            umath_libraries.append('wsock32') # needed for select
+
+        config.add_library('cprops', join('cprops_thread', '*.c'),
+                           macros=cprops_macros,
+                           include_dirs='cprops_thread')
+    
     config.add_extension('umath',
                          sources = [generate_config_h,
+                                    
                                     join('src','umathmodule.c.src'),
                                     generate_umath_c,
                                     generate_ufunc_api,
                                     join('src','scalartypes.inc.src'),
                                     join('src','arraytypes.inc.src'),
                                     ],
-                         depends = [join('src','ufuncobject.c'),
+                         depends = [join('src','ufuncthreadapi.c'),
+                                    join('src','ufuncobject.c'),
                                     generate_umath_py,
                                     join(codegen_dir,'generate_ufunc_api.py'),
                                     ]+deps,
+                         include_dirs = umath_include_dirs,
+                         library_dirs = umath_library_dirs,
+                         libraries = umath_libraries,
                          )
 
     config.add_extension('_sort',

Modified: branches/multicore/numpy/core/src/ufuncobject.c
===================================================================
--- branches/multicore/numpy/core/src/ufuncobject.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/src/ufuncobject.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -24,6 +24,7 @@
 
 */
 
+#include "thread.h"
 
 typedef double (DoubleBinaryFunc)(double x, double y);
 typedef float (FloatBinaryFunc)(float x, float y);
@@ -32,7 +33,7 @@
 typedef void (CdoubleBinaryFunc)(cdouble *x, cdouble *y, cdouble *res);
 typedef void (CfloatBinaryFunc)(cfloat *x, cfloat *y, cfloat *res);
 typedef void (ClongdoubleBinaryFunc)(clongdouble *x, clongdouble *y, \
-				     clongdouble *res);
+                     clongdouble *res);
 
 #define USE_USE_DEFAULTS 1
 
@@ -41,59 +42,59 @@
 static void
 PyUFunc_ff_f_As_dd_d(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i, n=dimensions[0];
-	register intp is1=steps[0],is2=steps[1],os=steps[2];
-	char *ip1=args[0], *ip2=args[1], *op=args[2];
+    register intp i, n=dimensions[0];
+    register intp is1=steps[0],is2=steps[1],os=steps[2];
+    char *ip1=args[0], *ip2=args[1], *op=args[2];
 
-	for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
-		*(float *)op = (float)((DoubleBinaryFunc *)func) \
-			((double)*(float *)ip1, (double)*(float *)ip2);
-	}
+    for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
+        *(float *)op = (float)((DoubleBinaryFunc *)func) \
+            ((double)*(float *)ip1, (double)*(float *)ip2);
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_ff_f(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i, n=dimensions[0];
-	register intp is1=steps[0],is2=steps[1],os=steps[2];
-	char *ip1=args[0], *ip2=args[1], *op=args[2];
+    register intp i, n=dimensions[0];
+    register intp is1=steps[0],is2=steps[1],os=steps[2];
+    char *ip1=args[0], *ip2=args[1], *op=args[2];
 
 
-	for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
-		*(float *)op = ((FloatBinaryFunc *)func)(*(float *)ip1,
-							 *(float *)ip2);
-	}
+    for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
+        *(float *)op = ((FloatBinaryFunc *)func)(*(float *)ip1,
+                             *(float *)ip2);
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_dd_d(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i, n=dimensions[0];
-	register intp is1=steps[0],is2=steps[1],os=steps[2];
-	char *ip1=args[0], *ip2=args[1], *op=args[2];
+    register intp i, n=dimensions[0];
+    register intp is1=steps[0],is2=steps[1],os=steps[2];
+    char *ip1=args[0], *ip2=args[1], *op=args[2];
 
 
-	for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
-		*(double *)op = ((DoubleBinaryFunc *)func)\
-			(*(double *)ip1, *(double *)ip2);
-	}
+    for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
+        *(double *)op = ((DoubleBinaryFunc *)func)\
+            (*(double *)ip1, *(double *)ip2);
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_gg_g(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i, n=dimensions[0];
-	register intp is1=steps[0],is2=steps[1],os=steps[2];
-	char *ip1=args[0], *ip2=args[1], *op=args[2];
+    register intp i, n=dimensions[0];
+    register intp is1=steps[0],is2=steps[1],os=steps[2];
+    char *ip1=args[0], *ip2=args[1], *op=args[2];
 
-	for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
-		*(longdouble *)op = \
-			((LongdoubleBinaryFunc *)func)(*(longdouble *)ip1,
-						       *(longdouble *)ip2);
-	}
+    for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
+        *(longdouble *)op = \
+            ((LongdoubleBinaryFunc *)func)(*(longdouble *)ip1,
+                               *(longdouble *)ip2);
+    }
 }
 
 
@@ -101,94 +102,94 @@
 static void
 PyUFunc_FF_F_As_DD_D(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i,n=dimensions[0],is1=steps[0],is2=steps[1],os=steps[2];
-	char *ip1=args[0], *ip2=args[1], *op=args[2];
-	cdouble x, y, r;
+    register intp i,n=dimensions[0],is1=steps[0],is2=steps[1],os=steps[2];
+    char *ip1=args[0], *ip2=args[1], *op=args[2];
+    cdouble x, y, r;
 
-	for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
-		x.real = ((float *)ip1)[0]; x.imag = ((float *)ip1)[1];
-		y.real = ((float *)ip2)[0]; y.imag = ((float *)ip2)[1];
-		((CdoubleBinaryFunc *)func)(&x, &y, &r);
-		((float *)op)[0] = (float)r.real;
-		((float *)op)[1] = (float)r.imag;
-	}
+    for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
+        x.real = ((float *)ip1)[0]; x.imag = ((float *)ip1)[1];
+        y.real = ((float *)ip2)[0]; y.imag = ((float *)ip2)[1];
+        ((CdoubleBinaryFunc *)func)(&x, &y, &r);
+        ((float *)op)[0] = (float)r.real;
+        ((float *)op)[1] = (float)r.imag;
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_DD_D(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0];
-	char *ip1=args[0], *ip2=args[1], *op=args[2];
-	cdouble x,y,r;
+    register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0];
+    char *ip1=args[0], *ip2=args[1], *op=args[2];
+    cdouble x,y,r;
 
-	for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
-		x.real = ((double *)ip1)[0]; x.imag = ((double *)ip1)[1];
-		y.real = ((double *)ip2)[0]; y.imag = ((double *)ip2)[1];
-		((CdoubleBinaryFunc *)func)(&x, &y, &r);
-		((double *)op)[0] = r.real;
-		((double *)op)[1] = r.imag;
-	}
+    for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
+        x.real = ((double *)ip1)[0]; x.imag = ((double *)ip1)[1];
+        y.real = ((double *)ip2)[0]; y.imag = ((double *)ip2)[1];
+        ((CdoubleBinaryFunc *)func)(&x, &y, &r);
+        ((double *)op)[0] = r.real;
+        ((double *)op)[1] = r.imag;
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_FF_F(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0];
-	char *ip1=args[0], *ip2=args[1], *op=args[2];
-	cfloat x,y,r;
+    register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0];
+    char *ip1=args[0], *ip2=args[1], *op=args[2];
+    cfloat x,y,r;
 
-	for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
-		x.real = ((float *)ip1)[0]; x.imag = ((float *)ip1)[1];
-		y.real = ((float *)ip2)[0]; y.imag = ((float *)ip2)[1];
-		((CfloatBinaryFunc *)func)(&x, &y, &r);
-		((float *)op)[0] = r.real;
-		((float *)op)[1] = r.imag;
-	}
+    for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
+        x.real = ((float *)ip1)[0]; x.imag = ((float *)ip1)[1];
+        y.real = ((float *)ip2)[0]; y.imag = ((float *)ip2)[1];
+        ((CfloatBinaryFunc *)func)(&x, &y, &r);
+        ((float *)op)[0] = r.real;
+        ((float *)op)[1] = r.imag;
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_GG_G(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0];
-	char *ip1=args[0], *ip2=args[1], *op=args[2];
-	clongdouble x,y,r;
+    register intp i, is1=steps[0],is2=steps[1],os=steps[2],n=dimensions[0];
+    char *ip1=args[0], *ip2=args[1], *op=args[2];
+    clongdouble x,y,r;
 
-	for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
-		x.real = ((longdouble *)ip1)[0];
-		x.imag = ((longdouble *)ip1)[1];
-		y.real = ((longdouble *)ip2)[0];
-		y.imag = ((longdouble *)ip2)[1];
-		((ClongdoubleBinaryFunc *)func)(&x, &y, &r);
-		((longdouble *)op)[0] = r.real;
-		((longdouble *)op)[1] = r.imag;
-	}
+    for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
+        x.real = ((longdouble *)ip1)[0];
+        x.imag = ((longdouble *)ip1)[1];
+        y.real = ((longdouble *)ip2)[0];
+        y.imag = ((longdouble *)ip2)[1];
+        ((ClongdoubleBinaryFunc *)func)(&x, &y, &r);
+        ((longdouble *)op)[0] = r.real;
+        ((longdouble *)op)[1] = r.imag;
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_OO_O(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i, is1=steps[0],is2=steps[1],os=steps[2], \
-		n=dimensions[0];
-	char *ip1=args[0], *ip2=args[1], *op=args[2];
-	PyObject *tmp;
-	PyObject *x1, *x2;
+    register intp i, is1=steps[0],is2=steps[1],os=steps[2], \
+        n=dimensions[0];
+    char *ip1=args[0], *ip2=args[1], *op=args[2];
+    PyObject *tmp;
+    PyObject *x1, *x2;
 
-	for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
-		x1 = *((PyObject **)ip1);
-		x2 = *((PyObject **)ip2);
-		if ((x1 == NULL) || (x2 == NULL)) goto done;
-		if ( (void *) func == (void *) PyNumber_Power)
-			tmp = ((ternaryfunc)func)(x1, x2, Py_None);
-		else
-			tmp = ((binaryfunc)func)(x1, x2);
-		if (PyErr_Occurred()) goto done;
+    for(i=0; i<n; i++, ip1+=is1, ip2+=is2, op+=os) {
+        x1 = *((PyObject **)ip1);
+        x2 = *((PyObject **)ip2);
+        if ((x1 == NULL) || (x2 == NULL)) goto done;
+        if ( (void *) func == (void *) PyNumber_Power)
+            tmp = ((ternaryfunc)func)(x1, x2, Py_None);
+        else
+            tmp = ((binaryfunc)func)(x1, x2);
+        if (PyErr_Occurred()) goto done;
                 Py_XDECREF(*((PyObject **)op));
-		*((PyObject **)op) = tmp;
-	}
+        *((PyObject **)op) = tmp;
+    }
  done:
         return;
 }
@@ -238,47 +239,47 @@
 static void
 PyUFunc_f_f_As_d_d(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i, n=dimensions[0];
-	char *ip1=args[0], *op=args[1];
-	for(i=0; i<n; i++, ip1+=steps[0], op+=steps[1]) {
-		*(float *)op = (float)((DoubleUnaryFunc *)func)((double)*(float *)ip1);
-	}
+    register intp i, n=dimensions[0];
+    char *ip1=args[0], *op=args[1];
+    for(i=0; i<n; i++, ip1+=steps[0], op+=steps[1]) {
+        *(float *)op = (float)((DoubleUnaryFunc *)func)((double)*(float *)ip1);
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_d_d(char **args, intp *dimensions, intp *steps, void *func)
 {
-	intp i;
-	char *ip1=args[0], *op=args[1];
-	for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
-		*(double *)op = ((DoubleUnaryFunc *)func)(*(double *)ip1);
-	}
+    intp i;
+    char *ip1=args[0], *op=args[1];
+    for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
+        *(double *)op = ((DoubleUnaryFunc *)func)(*(double *)ip1);
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_f_f(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i;
-	intp n=dimensions[0];
-	char *ip1=args[0], *op=args[1];
-	for(i=0; i<n; i++, ip1+=steps[0], op+=steps[1]) {
-		*(float *)op = ((FloatUnaryFunc *)func)(*(float *)ip1);
-	}
+    register intp i;
+    intp n=dimensions[0];
+    char *ip1=args[0], *op=args[1];
+    for(i=0; i<n; i++, ip1+=steps[0], op+=steps[1]) {
+        *(float *)op = ((FloatUnaryFunc *)func)(*(float *)ip1);
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_g_g(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i;
-	intp n=dimensions[0];
-	char *ip1=args[0], *op=args[1];
-	for(i=0; i<n; i++, ip1+=steps[0], op+=steps[1]) {
-		*(longdouble *)op = ((LongdoubleUnaryFunc *)func)\
+    register intp i;
+    intp n=dimensions[0];
+    char *ip1=args[0], *op=args[1];
+    for(i=0; i<n; i++, ip1+=steps[0], op+=steps[1]) {
+        *(longdouble *)op = ((LongdoubleUnaryFunc *)func)\
                         (*(longdouble *)ip1);
-	}
+    }
 }
 
 
@@ -286,30 +287,30 @@
 static void
 PyUFunc_F_F_As_D_D(char **args, intp *dimensions, intp *steps, void *func)
 {
-	register intp i; cdouble x, res;
-	intp n=dimensions[0];
-	char *ip1=args[0], *op=args[1];
-	for(i=0; i<n; i++, ip1+=steps[0], op+=steps[1]) {
-		x.real = ((float *)ip1)[0]; x.imag = ((float *)ip1)[1];
-		((CdoubleUnaryFunc *)func)(&x, &res);
-		((float *)op)[0] = (float)res.real;
-		((float *)op)[1] = (float)res.imag;
-	}
+    register intp i; cdouble x, res;
+    intp n=dimensions[0];
+    char *ip1=args[0], *op=args[1];
+    for(i=0; i<n; i++, ip1+=steps[0], op+=steps[1]) {
+        x.real = ((float *)ip1)[0]; x.imag = ((float *)ip1)[1];
+        ((CdoubleUnaryFunc *)func)(&x, &res);
+        ((float *)op)[0] = (float)res.real;
+        ((float *)op)[1] = (float)res.imag;
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_F_F(char **args, intp *dimensions, intp *steps, void *func)
 {
-	intp i; cfloat x, res;
-	char *ip1=args[0], *op=args[1];
-	for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
-		x.real = ((float *)ip1)[0];
-		x.imag = ((float *)ip1)[1];
-		((CfloatUnaryFunc *)func)(&x, &res);
-		((float *)op)[0] = res.real;
-		((float *)op)[1] = res.imag;
-	}
+    intp i; cfloat x, res;
+    char *ip1=args[0], *op=args[1];
+    for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
+        x.real = ((float *)ip1)[0];
+        x.imag = ((float *)ip1)[1];
+        ((CfloatUnaryFunc *)func)(&x, &res);
+        ((float *)op)[0] = res.real;
+        ((float *)op)[1] = res.imag;
+    }
 }
 
 
@@ -317,15 +318,15 @@
 static void
 PyUFunc_D_D(char **args, intp *dimensions, intp *steps, void *func)
 {
-	intp i; cdouble x, res;
-	char *ip1=args[0], *op=args[1];
-	for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
-		x.real = ((double *)ip1)[0];
-		x.imag = ((double *)ip1)[1];
-		((CdoubleUnaryFunc *)func)(&x, &res);
-		((double *)op)[0] = res.real;
-		((double *)op)[1] = res.imag;
-	}
+    intp i; cdouble x, res;
+    char *ip1=args[0], *op=args[1];
+    for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
+        x.real = ((double *)ip1)[0];
+        x.imag = ((double *)ip1)[1];
+        ((CdoubleUnaryFunc *)func)(&x, &res);
+        ((double *)op)[0] = res.real;
+        ((double *)op)[1] = res.imag;
+    }
 }
 
 
@@ -333,32 +334,32 @@
 static void
 PyUFunc_G_G(char **args, intp *dimensions, intp *steps, void *func)
 {
-	intp i; clongdouble x, res;
-	char *ip1=args[0], *op=args[1];
-	for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
-		x.real = ((longdouble *)ip1)[0];
-		x.imag = ((longdouble *)ip1)[1];
-		((ClongdoubleUnaryFunc *)func)(&x, &res);
-		((double *)op)[0] = res.real;
-		((double *)op)[1] = res.imag;
-	}
+    intp i; clongdouble x, res;
+    char *ip1=args[0], *op=args[1];
+    for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
+        x.real = ((longdouble *)ip1)[0];
+        x.imag = ((longdouble *)ip1)[1];
+        ((ClongdoubleUnaryFunc *)func)(&x, &res);
+        ((double *)op)[0] = res.real;
+        ((double *)op)[1] = res.imag;
+    }
 }
 
 /*UFUNC_API*/
 static void
 PyUFunc_O_O(char **args, intp *dimensions, intp *steps, void *func)
 {
-	intp i; PyObject *tmp, *x1;
-	char *ip1=args[0], *op=args[1];
+    intp i; PyObject *tmp, *x1;
+    char *ip1=args[0], *op=args[1];
 
-	for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
-		x1 = *(PyObject **)ip1;
-		if (x1 == NULL) goto done;
-		tmp = ((unaryfunc)func)(x1);
-		if ((tmp==NULL) || PyErr_Occurred()) goto done;
+    for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
+        x1 = *(PyObject **)ip1;
+        if (x1 == NULL) goto done;
+        tmp = ((unaryfunc)func)(x1);
+        if ((tmp==NULL) || PyErr_Occurred()) goto done;
                 Py_XDECREF(*((PyObject **)op));
-		*((PyObject **)op) = tmp;
-	}
+        *((PyObject **)op) = tmp;
+    }
  done:
         return;
 }
@@ -367,27 +368,27 @@
 static void
 PyUFunc_O_O_method(char **args, intp *dimensions, intp *steps, void *func)
 {
-	intp i; PyObject *tmp, *meth, *arglist, *x1;
-	char *ip1=args[0], *op=args[1];
+    intp i; PyObject *tmp, *meth, *arglist, *x1;
+    char *ip1=args[0], *op=args[1];
 
-	for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
-		x1 = *(PyObject **)ip1;
-		if (x1 == NULL) goto done;
-		meth = PyObject_GetAttrString(x1, (char *)func);
-		if (meth != NULL) {
-			arglist = PyTuple_New(0);
+    for(i=0; i<*dimensions; i++, ip1+=steps[0], op+=steps[1]) {
+        x1 = *(PyObject **)ip1;
+        if (x1 == NULL) goto done;
+        meth = PyObject_GetAttrString(x1, (char *)func);
+        if (meth != NULL) {
+            arglist = PyTuple_New(0);
                         if (arglist == NULL) {
                             Py_DECREF(meth);
                             goto done;
                         }
-			tmp = PyEval_CallObject(meth, arglist);
-			Py_DECREF(arglist);
-			Py_DECREF(meth);
+            tmp = PyEval_CallObject(meth, arglist);
+            Py_DECREF(arglist);
+            Py_DECREF(meth);
                         if ((tmp==NULL) || PyErr_Occurred()) goto done;
                         Py_XDECREF(*((PyObject **)op));
-			*((PyObject **)op) = tmp;
-		}
-	}
+            *((PyObject **)op) = tmp;
+        }
+    }
  done:
         return;
 
@@ -403,8 +404,8 @@
 static void
 PyUFunc_On_Om(char **args, intp *dimensions, intp *steps, void *func)
 {
-	intp i, j;
-	intp n=dimensions[0];
+    intp i, j;
+    intp n=dimensions[0];
         PyUFunc_PyFuncData *data = (PyUFunc_PyFuncData *)func;
         int nin = data->nin, nout=data->nout;
         int ntot;
@@ -416,9 +417,9 @@
         ntot = nin+nout;
 
         for (j=0; j < ntot; j++) ptrs[j] = args[j];
-	for(i=0; i<n; i++) {
-		arglist = PyTuple_New(nin);
-		if (arglist == NULL) return;
+    for(i=0; i<n; i++) {
+        arglist = PyTuple_New(nin);
+        if (arglist == NULL) return;
                 for (j=0; j < nin; j++) {
                         in = *((PyObject **)ptrs[j]);
                         if (in == NULL) {Py_DECREF(arglist); return;}
@@ -426,16 +427,16 @@
                         Py_INCREF(in);
                 }
                 result = PyEval_CallObject(tocall, arglist);
-		Py_DECREF(arglist);
+        Py_DECREF(arglist);
                 if (result == NULL) return;
                 if PyTuple_Check(result) {
                         if (nout != PyTuple_Size(result)) {
                                 Py_DECREF(result);
-				return;
-			}
+                return;
+            }
                         for (j=0; j < nout; j++) {
                                 op = (PyObject **)ptrs[j+nin];
-				Py_XDECREF(*op);
+                Py_XDECREF(*op);
                                 *op = PyTuple_GET_ITEM(result, j);
                                 Py_INCREF(*op);
                         }
@@ -443,12 +444,12 @@
                 }
                 else {
                         op = (PyObject **)ptrs[nin];
-			Py_XDECREF(*op);
+            Py_XDECREF(*op);
                         *op = result;
-		}
+        }
                 for (j=0; j < ntot; j++) ptrs[j] += steps[j];
-	}
-	return;
+    }
+    return;
 }
 
 
@@ -475,43 +476,43 @@
 static int
 _error_handler(int method, PyObject *errobj, char *errtype, int retstatus, int *first)
 {
-	PyObject *pyfunc, *ret, *args;
-	char *name=PyString_AS_STRING(PyTuple_GET_ITEM(errobj,0));
-	char msg[100];
+    PyObject *pyfunc, *ret, *args;
+    char *name=PyString_AS_STRING(PyTuple_GET_ITEM(errobj,0));
+    char msg[100];
 
-	ALLOW_C_API_DEF
+    ALLOW_C_API_DEF
 
-	ALLOW_C_API
+    ALLOW_C_API
 
-	switch(method) {
-	case UFUNC_ERR_WARN:
-		snprintf(msg, 100, "%s encountered in %s", errtype, name);
-		if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) goto fail;
-		break;
-	case UFUNC_ERR_RAISE:
-		PyErr_Format(PyExc_FloatingPointError,
-			     "%s encountered in %s",
-			     errtype, name);
-		goto fail;
-	case UFUNC_ERR_CALL:
-		pyfunc = PyTuple_GET_ITEM(errobj, 1);
+    switch(method) {
+    case UFUNC_ERR_WARN:
+        snprintf(msg, 100, "%s encountered in %s", errtype, name);
+        if (PyErr_Warn(PyExc_RuntimeWarning, msg) < 0) goto fail;
+        break;
+    case UFUNC_ERR_RAISE:
+        PyErr_Format(PyExc_FloatingPointError,
+                 "%s encountered in %s",
+                 errtype, name);
+        goto fail;
+    case UFUNC_ERR_CALL:
+        pyfunc = PyTuple_GET_ITEM(errobj, 1);
 
-		if (pyfunc == Py_None) {
-			PyErr_Format(PyExc_NameError,
-				     "python callback specified for %s (in " \
-				     " %s) but no function found.",
-				     errtype, name);
-			goto fail;
-		}
-		args = Py_BuildValue("NN", PyString_FromString(errtype),
+        if (pyfunc == Py_None) {
+            PyErr_Format(PyExc_NameError,
+                     "python callback specified for %s (in " \
+                     " %s) but no function found.",
+                     errtype, name);
+            goto fail;
+        }
+        args = Py_BuildValue("NN", PyString_FromString(errtype),
                                      PyInt_FromLong((long) retstatus));
-		if (args == NULL) goto fail;
-		ret = PyObject_CallObject(pyfunc, args);
-		Py_DECREF(args);
-		if (ret == NULL) goto fail;
-		Py_DECREF(ret);
+        if (args == NULL) goto fail;
+        ret = PyObject_CallObject(pyfunc, args);
+        Py_DECREF(args);
+        if (ret == NULL) goto fail;
+        Py_DECREF(ret);
 
-		break;
+        break;
         case UFUNC_ERR_PRINT:
                 if (*first) {
                         fprintf(stderr, "Warning: %s encountered in %s\n", errtype, name);
@@ -535,13 +536,13 @@
                         Py_DECREF(ret);
                 }
                 break;
-	}
-	DISABLE_C_API
-	return 0;
+    }
+    DISABLE_C_API
+    return 0;
 
  fail:
-	DISABLE_C_API
-	return -1;
+    DISABLE_C_API
+    return -1;
 }
 
 
@@ -549,31 +550,31 @@
 static int
 PyUFunc_getfperr(void)
 {
-	int retstatus;
-	UFUNC_CHECK_STATUS(retstatus);
-	return retstatus;
+    int retstatus;
+    UFUNC_CHECK_STATUS(retstatus);
+    return retstatus;
 }
 
 #define HANDLEIT(NAME, str) {if (retstatus & UFUNC_FPE_##NAME) { \
-			handle = errmask & UFUNC_MASK_##NAME;\
-			if (handle && \
-			    _error_handler(handle >> UFUNC_SHIFT_##NAME, \
-					   errobj, str, retstatus, first) < 0) \
-				return -1;		      \
-			}}
+            handle = errmask & UFUNC_MASK_##NAME;\
+            if (handle && \
+                _error_handler(handle >> UFUNC_SHIFT_##NAME, \
+                       errobj, str, retstatus, first) < 0) \
+                return -1;            \
+            }}
 
 /*UFUNC_API*/
 static int
 PyUFunc_handlefperr(int errmask, PyObject *errobj, int retstatus, int *first)
 {
-	int handle;
-	if (errmask && retstatus) {
-		HANDLEIT(DIVIDEBYZERO, "divide by zero");
-		HANDLEIT(OVERFLOW, "overflow");
-		HANDLEIT(UNDERFLOW, "underflow");
-		HANDLEIT(INVALID, "invalid value");
-	}
-	return 0;
+    int handle;
+    if (errmask && retstatus) {
+        HANDLEIT(DIVIDEBYZERO, "divide by zero");
+        HANDLEIT(OVERFLOW, "overflow");
+        HANDLEIT(UNDERFLOW, "underflow");
+        HANDLEIT(INVALID, "invalid value");
+    }
+    return 0;
 }
 
 #undef HANDLEIT
@@ -583,11 +584,11 @@
 static int
 PyUFunc_checkfperr(int errmask, PyObject *errobj, int *first)
 {
-	int retstatus;
+    int retstatus;
 
-	/* 1. check hardware flag --- this is platform dependent code */
-	retstatus = PyUFunc_getfperr();
-	return PyUFunc_handlefperr(errmask, errobj, retstatus, first);
+    /* 1. check hardware flag --- this is platform dependent code */
+    retstatus = PyUFunc_getfperr();
+    return PyUFunc_handlefperr(errmask, errobj, retstatus, first);
 }
 
 
@@ -596,7 +597,7 @@
 static void
 PyUFunc_clearfperr()
 {
-	PyUFunc_getfperr();
+    PyUFunc_getfperr();
 }
 
 
@@ -614,26 +615,26 @@
 _lowest_type(char intype)
 {
         switch(intype) {
-	/* case PyArray_BYTE */
-	case PyArray_SHORT:
+    /* case PyArray_BYTE */
+    case PyArray_SHORT:
         case PyArray_INT:
         case PyArray_LONG:
-	case PyArray_LONGLONG:
-		return PyArray_BYTE;
-	/* case PyArray_UBYTE */
+    case PyArray_LONGLONG:
+        return PyArray_BYTE;
+    /* case PyArray_UBYTE */
         case PyArray_USHORT:
         case PyArray_UINT:
-	case PyArray_ULONG:
-	case PyArray_ULONGLONG:
-		return PyArray_UBYTE;
-	/* case PyArray_FLOAT:*/
+    case PyArray_ULONG:
+    case PyArray_ULONGLONG:
+        return PyArray_UBYTE;
+    /* case PyArray_FLOAT:*/
         case PyArray_DOUBLE:
-	case PyArray_LONGDOUBLE:
-		return PyArray_FLOAT;
-	/* case PyArray_CFLOAT:*/
+    case PyArray_LONGDOUBLE:
+        return PyArray_FLOAT;
+    /* case PyArray_CFLOAT:*/
         case PyArray_CDOUBLE:
-	case PyArray_CLONGDOUBLE:
-		return PyArray_CFLOAT;
+    case PyArray_CLONGDOUBLE:
+        return PyArray_CFLOAT;
         default:
                 return intype;
         }
@@ -654,14 +655,15 @@
                         PyUFuncGenericFunction *function, void **data, 
                         int nargs, int nin)
 {
+
         PyUFunc_Loop1d *funcdata;
         int i;
         funcdata = (PyUFunc_Loop1d *)PyCObject_AsVoidPtr(obj);
         while (funcdata != NULL) {
                 for (i=0; i<nin; i++) {
-			if (!PyArray_CanCoerceScalar(arg_types[i],
-						     funcdata->arg_types[i],
-						     scalars[i])) 
+            if (!PyArray_CanCoerceScalar(arg_types[i],
+                             funcdata->arg_types[i],
+                             scalars[i])) 
                                 break;
                 }
                 if (i==nin) { /* match found */
@@ -776,19 +778,19 @@
         }
 
         if (userdef > 0) { /* search in the user-defined functions */
-		PyObject *key, *obj;
+        PyObject *key, *obj;
                 PyUFunc_Loop1d *funcdata;
-		obj = NULL;
-		key = PyInt_FromLong((long) userdef);
-		if (key == NULL) goto fail;
-		obj = PyDict_GetItem(self->userloops, key);
-		Py_DECREF(key);
-		if (obj == NULL) {
-			PyErr_SetString(PyExc_TypeError,
-					"user-defined type used in ufunc" \
-					" with no registered loops");
+        obj = NULL;
+        key = PyInt_FromLong((long) userdef);
+        if (key == NULL) goto fail;
+        obj = PyDict_GetItem(self->userloops, key);
+        Py_DECREF(key);
+        if (obj == NULL) {
+            PyErr_SetString(PyExc_TypeError,
+                    "user-defined type used in ufunc" \
+                    " with no registered loops");
                         goto fail;
-		}
+        }
                 /* extract the correct function
                    data and argtypes
                 */
@@ -803,7 +805,7 @@
                         else if (rtypenums[0] == funcdata->arg_types[self->nin]) {
                                 i = nargs;
                         }
-			else i = -1;
+            else i = -1;
                         if (i == nargs) {
                                 *function = funcdata->func;
                                 *data = funcdata->data;
@@ -831,7 +833,7 @@
                 else if (rtypenums[0] == self->types[j*nargs+self->nin]) {
                         i = nargs;
                 }
-		else i = -1;
+        else i = -1;
                 if (i == nargs) {
                         *function = self->functions[j];
                         *data = self->data[j];
@@ -862,40 +864,40 @@
 static int
 select_types(PyUFuncObject *self, int *arg_types,
              PyUFuncGenericFunction *function, void **data,
-	     PyArray_SCALARKIND *scalars,
+         PyArray_SCALARKIND *scalars,
              PyObject *typetup)
 {
-	int i, j;
-	char start_type;
-	int userdef=-1;
+    int i, j;
+    char start_type;
+    int userdef=-1;
 
-	if (self->userloops) {
-		for (i=0; i<self->nin; i++) {
-			if (PyTypeNum_ISUSERDEF(arg_types[i])) {
-				userdef = arg_types[i];
-				break;
-			}
-		}
-	}
+    if (self->userloops) {
+        for (i=0; i<self->nin; i++) {
+            if (PyTypeNum_ISUSERDEF(arg_types[i])) {
+                userdef = arg_types[i];
+                break;
+            }
+        }
+    }
         
         if (typetup != NULL)
                 return extract_specified_loop(self, arg_types, function, data,
                                               typetup, userdef);
                         
-	if (userdef > 0) {
-		PyObject *key, *obj;
+    if (userdef > 0) {
+        PyObject *key, *obj;
                 int ret;
-		obj = NULL;
-		key = PyInt_FromLong((long) userdef);
-		if (key == NULL) return -1;
-		obj = PyDict_GetItem(self->userloops, key);
-		Py_DECREF(key);
-		if (obj == NULL) {
-			PyErr_SetString(PyExc_TypeError,
-					"user-defined type used in ufunc" \
-					" with no registered loops");
-			return -1;
-		}
+        obj = NULL;
+        key = PyInt_FromLong((long) userdef);
+        if (key == NULL) return -1;
+        obj = PyDict_GetItem(self->userloops, key);
+        Py_DECREF(key);
+        if (obj == NULL) {
+            PyErr_SetString(PyExc_TypeError,
+                    "user-defined type used in ufunc" \
+                    " with no registered loops");
+            return -1;
+        }
                 /* extract the correct function
                    data and argtypes
                 */
@@ -904,43 +906,43 @@
                                               self->nin);
                 Py_DECREF(obj);
                 return ret;
-	}
+    }
 
-	start_type = arg_types[0];
-	/* If the first argument is a scalar we need to place
-	   the start type as the lowest type in the class
-	*/
-	if (scalars[0] != PyArray_NOSCALAR) {
-		start_type = _lowest_type(start_type);
-	}
+    start_type = arg_types[0];
+    /* If the first argument is a scalar we need to place
+       the start type as the lowest type in the class
+    */
+    if (scalars[0] != PyArray_NOSCALAR) {
+        start_type = _lowest_type(start_type);
+    }
 
-	i = 0;
-	while (i<self->ntypes && start_type > self->types[i*self->nargs])
-		i++;
+    i = 0;
+    while (i<self->ntypes && start_type > self->types[i*self->nargs])
+        i++;
 
-	for(;i<self->ntypes; i++) {
-		for(j=0; j<self->nin; j++) {
-			if (!PyArray_CanCoerceScalar(arg_types[j],
-						     self->types[i*self->nargs+j],
-						     scalars[j]))
-				break;
-		}
-		if (j == self->nin) break;
-	}
-	if(i>=self->ntypes) {
-		PyErr_SetString(PyExc_TypeError, _types_msg);
-		return -1;
-	}
-	for(j=0; j<self->nargs; j++)
-		arg_types[j] = self->types[i*self->nargs+j];
+    for(;i<self->ntypes; i++) {
+        for(j=0; j<self->nin; j++) {
+            if (!PyArray_CanCoerceScalar(arg_types[j],
+                             self->types[i*self->nargs+j],
+                             scalars[j]))
+                break;
+        }
+        if (j == self->nin) break;
+    }
+    if(i>=self->ntypes) {
+        PyErr_SetString(PyExc_TypeError, _types_msg);
+        return -1;
+    }
+    for(j=0; j<self->nargs; j++)
+        arg_types[j] = self->types[i*self->nargs+j];
 
         if (self->data)
                 *data = self->data[i];
         else
                 *data = NULL;
-	*function = self->functions[i];
+    *function = self->functions[i];
 
-	return 0;
+    return 0;
 }
 
 #if USE_USE_DEFAULTS==1
@@ -955,37 +957,37 @@
 {
         PyObject *retval;
 
-	*errobj = NULL;
-	if (!PyList_Check(ref) || (PyList_GET_SIZE(ref)!=3)) {
-		PyErr_Format(PyExc_TypeError, "%s must be a length 3 list.",
-			     UFUNC_PYVALS_NAME);
-		return -1;
-	}
+    *errobj = NULL;
+    if (!PyList_Check(ref) || (PyList_GET_SIZE(ref)!=3)) {
+        PyErr_Format(PyExc_TypeError, "%s must be a length 3 list.",
+                 UFUNC_PYVALS_NAME);
+        return -1;
+    }
 
-	*bufsize = PyInt_AsLong(PyList_GET_ITEM(ref, 0));
-	if ((*bufsize == -1) && PyErr_Occurred()) return -1;
-	if ((*bufsize < PyArray_MIN_BUFSIZE) ||	\
-	    (*bufsize > PyArray_MAX_BUFSIZE) || \
-	    (*bufsize % 16 != 0)) {
-		PyErr_Format(PyExc_ValueError,
-			     "buffer size (%d) is not in range "
+    *bufsize = PyInt_AsLong(PyList_GET_ITEM(ref, 0));
+    if ((*bufsize == -1) && PyErr_Occurred()) return -1;
+    if ((*bufsize < PyArray_MIN_BUFSIZE) || \
+        (*bufsize > PyArray_MAX_BUFSIZE) || \
+        (*bufsize % 16 != 0)) {
+        PyErr_Format(PyExc_ValueError,
+                 "buffer size (%d) is not in range "
                              "(%"INTP_FMT" - %"INTP_FMT") or not a multiple of 16",
-			     *bufsize, (intp) PyArray_MIN_BUFSIZE,
-			     (intp) PyArray_MAX_BUFSIZE);
-		return -1;
-	}
+                 *bufsize, (intp) PyArray_MIN_BUFSIZE,
+                 (intp) PyArray_MAX_BUFSIZE);
+        return -1;
+    }
 
-	*errmask = PyInt_AsLong(PyList_GET_ITEM(ref, 1));
-	if (*errmask < 0) {
-		if (PyErr_Occurred()) return -1;
-		PyErr_Format(PyExc_ValueError,		\
-			     "invalid error mask (%d)",
-			     *errmask);
-		return -1;
-	}
+    *errmask = PyInt_AsLong(PyList_GET_ITEM(ref, 1));
+    if (*errmask < 0) {
+        if (PyErr_Occurred()) return -1;
+        PyErr_Format(PyExc_ValueError,      \
+                 "invalid error mask (%d)",
+                 *errmask);
+        return -1;
+    }
         
-	retval = PyList_GET_ITEM(ref, 2);
-	if (retval != Py_None && !PyCallable_Check(retval)) {
+    retval = PyList_GET_ITEM(ref, 2);
+    if (retval != Py_None && !PyCallable_Check(retval)) {
                 PyObject *temp;
                 temp = PyObject_GetAttrString(retval, "write");
                 if (temp == NULL || !PyCallable_Check(temp)) {
@@ -996,14 +998,14 @@
                         return -1;
                 }
                 Py_DECREF(temp);
-	}
+    }
         
-	*errobj = Py_BuildValue("NO",
-				PyString_FromString(name),
-				retval);
-	if (*errobj == NULL) return -1;
+    *errobj = Py_BuildValue("NO",
+                PyString_FromString(name),
+                retval);
+    if (*errobj == NULL) return -1;
 
-	return 0;
+    return 0;
 }
 
 
@@ -1016,28 +1018,28 @@
         PyObject *ref=NULL;
 
         #if USE_USE_DEFAULTS==1
-	if (PyUFunc_NUM_NODEFAULTS != 0) {
+    if (PyUFunc_NUM_NODEFAULTS != 0) {
         #endif
-		if (PyUFunc_PYVALS_NAME == NULL) {
-			PyUFunc_PYVALS_NAME = \
-				PyString_InternFromString(UFUNC_PYVALS_NAME);
-		}
-		thedict = PyThreadState_GetDict();
-		if (thedict == NULL) {
-			thedict = PyEval_GetBuiltins();
-		}
-		ref = PyDict_GetItem(thedict, PyUFunc_PYVALS_NAME);
+        if (PyUFunc_PYVALS_NAME == NULL) {
+            PyUFunc_PYVALS_NAME = \
+                PyString_InternFromString(UFUNC_PYVALS_NAME);
+        }
+        thedict = PyThreadState_GetDict();
+        if (thedict == NULL) {
+            thedict = PyEval_GetBuiltins();
+        }
+        ref = PyDict_GetItem(thedict, PyUFunc_PYVALS_NAME);
         #if USE_USE_DEFAULTS==1
-	}
+    }
         #endif
-	if (ref == NULL) {
-		*errmask = UFUNC_ERR_DEFAULT;
-		*errobj = Py_BuildValue("NO",
-					PyString_FromString(name),
-					Py_None);
-		*bufsize = PyArray_BUFSIZE;
-		return 0;
-	}
+    if (ref == NULL) {
+        *errmask = UFUNC_ERR_DEFAULT;
+        *errobj = Py_BuildValue("NO",
+                    PyString_FromString(name),
+                    Py_None);
+        *bufsize = PyArray_BUFSIZE;
+        return 0;
+    }
         return _extract_pyvals(ref, name, bufsize, errmask, errobj);
 }
 
@@ -1049,42 +1051,42 @@
 static int
 _create_copies(PyUFuncLoopObject *loop, int *arg_types, PyArrayObject **mps)
 {
-	int nin = loop->ufunc->nin;
-	int i;
-	intp size;
-	PyObject *new;
-	PyArray_Descr *ntype;
-	PyArray_Descr *atype;
+    int nin = loop->ufunc->nin;
+    int i;
+    intp size;
+    PyObject *new;
+    PyArray_Descr *ntype;
+    PyArray_Descr *atype;
 
-	for (i=0; i<nin; i++) {
-		size = PyArray_SIZE(mps[i]);
-		/* if the type of mps[i] is equivalent to arg_types[i] */
-		/* then set arg_types[i] equal to type of
-		   mps[i] for later checking....
-		*/
-		if (PyArray_TYPE(mps[i]) != arg_types[i]) {
-			ntype = mps[i]->descr;
-			atype = PyArray_DescrFromType(arg_types[i]);
-			if (PyArray_EquivTypes(atype, ntype)) {
-				arg_types[i] = ntype->type_num;
-			}
-			Py_DECREF(atype);
-		}
-		if (size < loop->bufsize) {
-			if (!(PyArray_ISBEHAVED_RO(mps[i])) ||		\
-			    PyArray_TYPE(mps[i]) != arg_types[i]) {
-				ntype = PyArray_DescrFromType(arg_types[i]);
-				new = PyArray_FromAny((PyObject *)mps[i],
-						      ntype, 0, 0,
-						      FORCECAST | ALIGNED, NULL);
-				if (new == NULL) return -1;
-				Py_DECREF(mps[i]);
-				mps[i] = (PyArrayObject *)new;
-			}
-		}
-	}
+    for (i=0; i<nin; i++) {
+        size = PyArray_SIZE(mps[i]);
+        /* if the type of mps[i] is equivalent to arg_types[i] */
+        /* then set arg_types[i] equal to type of
+           mps[i] for later checking....
+        */
+        if (PyArray_TYPE(mps[i]) != arg_types[i]) {
+            ntype = mps[i]->descr;
+            atype = PyArray_DescrFromType(arg_types[i]);
+            if (PyArray_EquivTypes(atype, ntype)) {
+                arg_types[i] = ntype->type_num;
+            }
+            Py_DECREF(atype);
+        }
+        if (size < loop->bufsize) {
+            if (!(PyArray_ISBEHAVED_RO(mps[i])) ||      \
+                PyArray_TYPE(mps[i]) != arg_types[i]) {
+                ntype = PyArray_DescrFromType(arg_types[i]);
+                new = PyArray_FromAny((PyObject *)mps[i],
+                              ntype, 0, 0,
+                              FORCECAST | ALIGNED, NULL);
+                if (new == NULL) return -1;
+                Py_DECREF(mps[i]);
+                mps[i] = (PyArrayObject *)new;
+            }
+        }
+    }
 
-	return 0;
+    return 0;
 }
 
 #define _GETATTR_(str, rstr) if (strcmp(name, #str) == 0) { \
@@ -1117,11 +1119,11 @@
 {
         int nargs, i;
         int arg_types[NPY_MAXARGS];
-	PyArray_SCALARKIND scalars[NPY_MAXARGS];
+    PyArray_SCALARKIND scalars[NPY_MAXARGS];
         PyArray_SCALARKIND maxarrkind, maxsckind, new;
-	PyUFuncObject *self=loop->ufunc;
-	Bool allscalars=TRUE;
-	PyTypeObject *subtype=&PyArray_Type;
+    PyUFuncObject *self=loop->ufunc;
+    Bool allscalars=TRUE;
+    PyTypeObject *subtype=&PyArray_Type;
         PyObject *context=NULL;
         PyObject *obj;
         int flexible=0;
@@ -1131,7 +1133,7 @@
         nargs = PyTuple_Size(args);
         if ((nargs < self->nin) || (nargs > self->nargs)) {
                 PyErr_SetString(PyExc_ValueError,
-				"invalid number of arguments");
+                "invalid number of arguments");
                 return -1;
         }
 
@@ -1154,26 +1156,26 @@
                 if (!object && PyTypeNum_ISOBJECT(arg_types[i])) {
                         object = 1;
                 }
-		/*
-		fprintf(stderr, "array %d has reference %d\n", i,
-		                (mps[i])->ob_refcnt);
-		*/
+        /*
+        fprintf(stderr, "array %d has reference %d\n", i,
+                        (mps[i])->ob_refcnt);
+        */
 
-		/* Scalars are 0-dimensional arrays
-		   at this point
-		*/
+        /* Scalars are 0-dimensional arrays
+           at this point
+        */
 
                 /* We need to keep track of whether or not scalars
                    are mixed with arrays of different kinds.
                 */
 
-		if (mps[i]->nd > 0) {
+        if (mps[i]->nd > 0) {
                         scalars[i] = PyArray_NOSCALAR;
-			allscalars=FALSE;
+            allscalars=FALSE;
                         new = PyArray_ScalarKind(arg_types[i], NULL);
                         maxarrkind = NPY_MAX(new, maxarrkind);
-		}
-		else {
+        }
+        else {
                         scalars[i] = PyArray_ScalarKind(arg_types[i], &(mps[i]));
                         maxsckind = NPY_MAX(scalars[i], maxsckind);
                 }
@@ -1184,50 +1186,50 @@
                 return nargs;
         }
 
-	/* If everything is a scalar, or scalars mixed with arrays of 
+    /* If everything is a scalar, or scalars mixed with arrays of 
            different kinds of lesser types then use normal coercion rules */
-	if (allscalars || (maxsckind > maxarrkind)) {
-		for (i=0; i<self->nin; i++) {
-			scalars[i] = PyArray_NOSCALAR;
-		}
-	}
+    if (allscalars || (maxsckind > maxarrkind)) {
+        for (i=0; i<self->nin; i++) {
+            scalars[i] = PyArray_NOSCALAR;
+        }
+    }
 
         /* Select an appropriate function for these argument types. */
         if (select_types(loop->ufunc, arg_types, &(loop->function),
                          &(loop->funcdata), scalars, typetup) == -1)
-		return -1;
+        return -1;
 
         /* FAIL with NotImplemented if the other object has
-	   the __r<op>__ method and has __array_priority__ as
-	   an attribute (signalling it can handle ndarray's)
-	   and is not already an ndarray
-	*/
-        if ((arg_types[1] == PyArray_OBJECT) &&				\
+       the __r<op>__ method and has __array_priority__ as
+       an attribute (signalling it can handle ndarray's)
+       and is not already an ndarray
+    */
+        if ((arg_types[1] == PyArray_OBJECT) &&             \
             (loop->ufunc->nin==2) && (loop->ufunc->nout == 1)) {
-		PyObject *_obj = PyTuple_GET_ITEM(args, 1);
-                if (!PyArray_CheckExact(_obj) &&			\
-		    PyObject_HasAttrString(_obj, "__array_priority__") && \
-		    _has_reflected_op(_obj, loop->ufunc->name)) {
+        PyObject *_obj = PyTuple_GET_ITEM(args, 1);
+                if (!PyArray_CheckExact(_obj) &&            \
+            PyObject_HasAttrString(_obj, "__array_priority__") && \
+            _has_reflected_op(_obj, loop->ufunc->name)) {
                         loop->notimplemented = 1;
                         return nargs;
                 }
         }
 
-	/* Create copies for some of the arrays if they are small
+    /* Create copies for some of the arrays if they are small
            enough and not already contiguous */
-	if (_create_copies(loop, arg_types, mps) < 0) return -1;
+    if (_create_copies(loop, arg_types, mps) < 0) return -1;
 
-	/* Create Iterators for the Inputs */
-	for (i=0; i<self->nin; i++) {
-                loop->iters[i] = (PyArrayIterObject *)		\
-			PyArray_IterNew((PyObject *)mps[i]);
+    /* Create Iterators for the Inputs */
+    for (i=0; i<self->nin; i++) {
+                loop->iters[i] = (PyArrayIterObject *)      \
+            PyArray_IterNew((PyObject *)mps[i]);
                 if (loop->iters[i] == NULL) return -1;
-	}
+    }
 
         /* Broadcast the result */
         loop->numiter = self->nin;
         if (PyArray_Broadcast((PyArrayMultiIterObject *)loop) < 0)
-		return -1;
+        return -1;
 
         /* Get any return arguments */
         for (i=self->nin; i<nargs; i++) {
@@ -1238,35 +1240,35 @@
                 }
                 Py_INCREF(mps[i]);
                 if (!PyArray_Check((PyObject *)mps[i])) {
-			PyObject *new;
-			if (PyArrayIter_Check(mps[i])) {
-				new = PyObject_CallMethod((PyObject *)mps[i],
-							  "__array__", NULL);
-				Py_DECREF(mps[i]);
-				mps[i] = (PyArrayObject *)new;
-			}
-			else {
-				PyErr_SetString(PyExc_TypeError,
-						"return arrays must be "\
-						"of ArrayType");
-				Py_DECREF(mps[i]);
+            PyObject *new;
+            if (PyArrayIter_Check(mps[i])) {
+                new = PyObject_CallMethod((PyObject *)mps[i],
+                              "__array__", NULL);
+                Py_DECREF(mps[i]);
+                mps[i] = (PyArrayObject *)new;
+            }
+            else {
+                PyErr_SetString(PyExc_TypeError,
+                        "return arrays must be "\
+                        "of ArrayType");
+                Py_DECREF(mps[i]);
                                 mps[i] = NULL;
-				return -1;
-			}
+                return -1;
+            }
                 }
                 if (mps[i]->nd != loop->nd ||
-		    !PyArray_CompareLists(mps[i]->dimensions,
-					  loop->dimensions, loop->nd)) {
+            !PyArray_CompareLists(mps[i]->dimensions,
+                      loop->dimensions, loop->nd)) {
                         PyErr_SetString(PyExc_ValueError,
                                         "invalid return array shape");
-			Py_DECREF(mps[i]);
+            Py_DECREF(mps[i]);
                         mps[i] = NULL;
                         return -1;
                 }
                 if (!PyArray_ISWRITEABLE(mps[i])) {
                         PyErr_SetString(PyExc_ValueError,
                                         "return array is not writeable");
-			Py_DECREF(mps[i]);
+            Py_DECREF(mps[i]);
                         mps[i] = NULL;
                         return -1;
                 }
@@ -1275,7 +1277,7 @@
         /* construct any missing return arrays and make output iterators */
 
         for (i=self->nin; i<self->nargs; i++) {
-		PyArray_Descr *ntype;
+        PyArray_Descr *ntype;
 
                 if (mps[i] == NULL) {
                         mps[i] = (PyArrayObject *)PyArray_New(subtype,
@@ -1287,42 +1289,42 @@
                         if (mps[i] == NULL) return -1;
                 }
 
-		/* reset types for outputs that are equivalent
-		    -- no sense casting uselessly
-		*/
-		else {
-  		  if (mps[i]->descr->type_num != arg_types[i]) {
-			  PyArray_Descr *atype;
-			  ntype = mps[i]->descr;
-			  atype = PyArray_DescrFromType(arg_types[i]);
-			  if (PyArray_EquivTypes(atype, ntype)) {
-				  arg_types[i] = ntype->type_num;
-			  }
-			  Py_DECREF(atype);
-		  }
+        /* reset types for outputs that are equivalent
+            -- no sense casting uselessly
+        */
+        else {
+          if (mps[i]->descr->type_num != arg_types[i]) {
+              PyArray_Descr *atype;
+              ntype = mps[i]->descr;
+              atype = PyArray_DescrFromType(arg_types[i]);
+              if (PyArray_EquivTypes(atype, ntype)) {
+                  arg_types[i] = ntype->type_num;
+              }
+              Py_DECREF(atype);
+          }
 
-		/* still not the same -- or will we have to use buffers?*/
-		  if (mps[i]->descr->type_num != arg_types[i] ||
-		      !PyArray_ISBEHAVED_RO(mps[i])) {
-			  if (loop->size < loop->bufsize) {
-				  PyObject *new;
-				  /* Copy the array to a temporary copy
-				     and set the UPDATEIFCOPY flag
-				  */
-				  ntype = PyArray_DescrFromType(arg_types[i]);
-				  new = PyArray_FromAny((PyObject *)mps[i],
-							ntype, 0, 0,
-							FORCECAST | ALIGNED |
-							UPDATEIFCOPY, NULL);
-				  if (new == NULL) return -1;
-				  Py_DECREF(mps[i]);
-				  mps[i] = (PyArrayObject *)new;
-			  }
-		  }
-		}
+        /* still not the same -- or will we have to use buffers?*/
+          if (mps[i]->descr->type_num != arg_types[i] ||
+              !PyArray_ISBEHAVED_RO(mps[i])) {
+              if (loop->size < loop->bufsize) {
+                  PyObject *new;
+                  /* Copy the array to a temporary copy
+                     and set the UPDATEIFCOPY flag
+                  */
+                  ntype = PyArray_DescrFromType(arg_types[i]);
+                  new = PyArray_FromAny((PyObject *)mps[i],
+                            ntype, 0, 0,
+                            FORCECAST | ALIGNED |
+                            UPDATEIFCOPY, NULL);
+                  if (new == NULL) return -1;
+                  Py_DECREF(mps[i]);
+                  mps[i] = (PyArrayObject *)new;
+              }
+          }
+        }
 
-                loop->iters[i] = (PyArrayIterObject *)		\
-			PyArray_IterNew((PyObject *)mps[i]);
+                loop->iters[i] = (PyArrayIterObject *)      \
+            PyArray_IterNew((PyObject *)mps[i]);
                 if (loop->iters[i] == NULL) return -1;
         }
 
@@ -1336,20 +1338,20 @@
         /* Determine looping method needed */
         loop->meth = NO_UFUNCLOOP;
 
-	if (loop->size == 0) return nargs;
+    if (loop->size == 0) return nargs;
 
 
         for (i=0; i<self->nargs; i++) {
-		loop->needbuffer[i] = 0;
+        loop->needbuffer[i] = 0;
                 if (arg_types[i] != mps[i]->descr->type_num ||
-		    !PyArray_ISBEHAVED_RO(mps[i])) {
+            !PyArray_ISBEHAVED_RO(mps[i])) {
                         loop->meth = BUFFER_UFUNCLOOP;
-			loop->needbuffer[i] = 1;
+            loop->needbuffer[i] = 1;
                 }
                 if (!loop->obj && mps[i]->descr->type_num == PyArray_OBJECT) {
-			loop->obj = 1;
-		}
+            loop->obj = 1;
         }
+        }
 
         if (loop->meth == NO_UFUNCLOOP) {
 
@@ -1360,201 +1362,201 @@
 
                 for (i=0; i<self->nargs; i++) {
                         if (!(loop->iters[i]->contiguous)) {
-				/* may still have uniform stride
-				   if (broadcated result) <= 1-d */
-				if (mps[i]->nd != 0 &&			\
-				    (loop->iters[i]->nd_m1 > 0)) {
-					loop->meth = NOBUFFER_UFUNCLOOP;
-					break;
-				}
-			}
+                /* may still have uniform stride
+                   if (broadcated result) <= 1-d */
+                if (mps[i]->nd != 0 &&          \
+                    (loop->iters[i]->nd_m1 > 0)) {
+                    loop->meth = NOBUFFER_UFUNCLOOP;
+                    break;
                 }
-		if (loop->meth == ONE_UFUNCLOOP) {
-			for (i=0; i<self->nargs; i++) {
-				loop->bufptr[i] = mps[i]->data;
-			}
-		}
+            }
+                }
+        if (loop->meth == ONE_UFUNCLOOP) {
+            for (i=0; i<self->nargs; i++) {
+                loop->bufptr[i] = mps[i]->data;
+            }
         }
+        }
 
         loop->numiter = self->nargs;
 
-	/* Fill in steps */
-	if (loop->meth != ONE_UFUNCLOOP) {
-		int ldim;
-		intp minsum;
-		intp maxdim;
-		PyArrayIterObject *it;
-		intp stride_sum[NPY_MAXDIMS];
-		int j;
+    /* Fill in steps */
+    if (loop->meth != ONE_UFUNCLOOP) {
+        int ldim;
+        intp minsum;
+        intp maxdim;
+        PyArrayIterObject *it;
+        intp stride_sum[NPY_MAXDIMS];
+        int j;
 
-		/* Fix iterators */
+        /* Fix iterators */
 
-		/* Optimize axis the iteration takes place over
+        /* Optimize axis the iteration takes place over
 
-		The first thought was to have the loop go 
-		over the largest dimension to minimize the number of loops
-		
-		However, on processors with slow memory bus and cache,
-		the slowest loops occur when the memory access occurs for
-		large strides. 
-		
-		Thus, choose the axis for which strides of the last iterator is 
-		smallest but non-zero.
-		 */
+        The first thought was to have the loop go 
+        over the largest dimension to minimize the number of loops
+        
+        However, on processors with slow memory bus and cache,
+        the slowest loops occur when the memory access occurs for
+        large strides. 
+        
+        Thus, choose the axis for which strides of the last iterator is 
+        smallest but non-zero.
+         */
 
-		for (i=0; i<loop->nd; i++) {
-			stride_sum[i] = 0;
-			for (j=0; j<loop->numiter; j++) {
-				stride_sum[i] += loop->iters[j]->strides[i];
-			}
-		}
+        for (i=0; i<loop->nd; i++) {
+            stride_sum[i] = 0;
+            for (j=0; j<loop->numiter; j++) {
+                stride_sum[i] += loop->iters[j]->strides[i];
+            }
+        }
 
-		ldim = loop->nd - 1;
-		minsum = stride_sum[loop->nd-1];
-		for (i=loop->nd - 2; i>=0; i--) {
-			if (stride_sum[i] < minsum ) {
-				ldim = i;
-				minsum = stride_sum[i];
-			}
-		}
+        ldim = loop->nd - 1;
+        minsum = stride_sum[loop->nd-1];
+        for (i=loop->nd - 2; i>=0; i--) {
+            if (stride_sum[i] < minsum ) {
+                ldim = i;
+                minsum = stride_sum[i];
+            }
+        }
 
-		maxdim = loop->dimensions[ldim];
-		loop->size /= maxdim;
-		loop->bufcnt = maxdim;
-		loop->lastdim = ldim;
+        maxdim = loop->dimensions[ldim];
+        loop->size /= maxdim;
+        loop->bufcnt = maxdim;
+        loop->lastdim = ldim;
 
-		/* Fix the iterators so the inner loop occurs over the
-		   largest dimensions -- This can be done by
-		   setting the size to 1 in that dimension
-		   (just in the iterators)
-		 */
+        /* Fix the iterators so the inner loop occurs over the
+           largest dimensions -- This can be done by
+           setting the size to 1 in that dimension
+           (just in the iterators)
+         */
 
-		for (i=0; i<loop->numiter; i++) {
-			it = loop->iters[i];
-			it->contiguous = 0;
-			it->size /= (it->dims_m1[ldim]+1);
-			it->dims_m1[ldim] = 0;
-			it->backstrides[ldim] = 0;
+        for (i=0; i<loop->numiter; i++) {
+            it = loop->iters[i];
+            it->contiguous = 0;
+            it->size /= (it->dims_m1[ldim]+1);
+            it->dims_m1[ldim] = 0;
+            it->backstrides[ldim] = 0;
 
-			/* (won't fix factors because we
-			   don't use PyArray_ITER_GOTO1D
-			   so don't change them) */
+            /* (won't fix factors because we
+               don't use PyArray_ITER_GOTO1D
+               so don't change them) */
 
-			/* Set the steps to the strides in that dimension */
-			loop->steps[i] = it->strides[ldim];
-		}
+            /* Set the steps to the strides in that dimension */
+            loop->steps[i] = it->strides[ldim];
+        }
 
-		/* fix up steps where we will be copying data to
-		   buffers and calculate the ninnerloops and leftover
-		   values -- if step size is already zero that is not changed...
-		*/
-		if (loop->meth == BUFFER_UFUNCLOOP) {
-			loop->leftover = maxdim % loop->bufsize;
-			loop->ninnerloops = (maxdim / loop->bufsize) + 1;
-			for (i=0; i<self->nargs; i++) {
-				if (loop->needbuffer[i] && loop->steps[i]) {
-					loop->steps[i] = mps[i]->descr->elsize;
-				}
-				/* These are changed later if casting is needed */
-			}
-		}
-	}
-	else { /* uniformly-strided case ONE_UFUNCLOOP */
-		for (i=0; i<self->nargs; i++) {
-			if (PyArray_SIZE(mps[i]) == 1)
-				loop->steps[i] = 0;
-			else
-				loop->steps[i] = mps[i]->strides[mps[i]->nd-1];
-		}
-	}
+        /* fix up steps where we will be copying data to
+           buffers and calculate the ninnerloops and leftover
+           values -- if step size is already zero that is not changed...
+        */
+        if (loop->meth == BUFFER_UFUNCLOOP) {
+            loop->leftover = maxdim % loop->bufsize;
+            loop->ninnerloops = (maxdim / loop->bufsize) + 1;
+            for (i=0; i<self->nargs; i++) {
+                if (loop->needbuffer[i] && loop->steps[i]) {
+                    loop->steps[i] = mps[i]->descr->elsize;
+                }
+                /* These are changed later if casting is needed */
+            }
+        }
+    }
+    else { /* uniformly-strided case ONE_UFUNCLOOP */
+        for (i=0; i<self->nargs; i++) {
+            if (PyArray_SIZE(mps[i]) == 1)
+                loop->steps[i] = 0;
+            else
+                loop->steps[i] = mps[i]->strides[mps[i]->nd-1];
+        }
+    }
 
 
-	/* Finally, create memory for buffers if we need them */
+    /* Finally, create memory for buffers if we need them */
 
-	/* buffers for scalars are specially made small -- scalars are
-	   not copied multiple times */
-	if (loop->meth == BUFFER_UFUNCLOOP) {
-		int cnt = 0, cntcast = 0; /* keeps track of bytes to allocate */
-		int scnt = 0, scntcast = 0;
-		char *castptr;
-		char *bufptr;
-		int last_was_scalar=0;
-		int last_cast_was_scalar=0;
-		int oldbufsize=0;
-		int oldsize=0;
-		int scbufsize = 4*sizeof(double);
-		int memsize;
+    /* buffers for scalars are specially made small -- scalars are
+       not copied multiple times */
+    if (loop->meth == BUFFER_UFUNCLOOP) {
+        int cnt = 0, cntcast = 0; /* keeps track of bytes to allocate */
+        int scnt = 0, scntcast = 0;
+        char *castptr;
+        char *bufptr;
+        int last_was_scalar=0;
+        int last_cast_was_scalar=0;
+        int oldbufsize=0;
+        int oldsize=0;
+        int scbufsize = 4*sizeof(double);
+        int memsize;
                 PyArray_Descr *descr;
 
-		/* compute the element size */
-		for (i=0; i<self->nargs;i++) {
-			if (!loop->needbuffer) continue;
-			if (arg_types[i] != mps[i]->descr->type_num) {
-				descr = PyArray_DescrFromType(arg_types[i]);
-				if (loop->steps[i])
-					cntcast += descr->elsize;
-				else
-					scntcast += descr->elsize;
-				if (i < self->nin) {
-					loop->cast[i] = \
-						PyArray_GetCastFunc(mps[i]->descr,
-								    arg_types[i]);
-				}
-				else {
-					loop->cast[i] =	PyArray_GetCastFunc \
-						(descr, mps[i]->descr->type_num);
-				}
-				Py_DECREF(descr);
-				if (!loop->cast[i]) return -1;
-			}
-			loop->swap[i] = !(PyArray_ISNOTSWAPPED(mps[i]));
-			if (loop->steps[i])
-				cnt += mps[i]->descr->elsize;
-			else
-				scnt += mps[i]->descr->elsize;
-		}
-		memsize = loop->bufsize*(cnt+cntcast) + scbufsize*(scnt+scntcast);
- 		loop->buffer[0] = PyDataMem_NEW(memsize);
+        /* compute the element size */
+        for (i=0; i<self->nargs;i++) {
+            if (!loop->needbuffer) continue;
+            if (arg_types[i] != mps[i]->descr->type_num) {
+                descr = PyArray_DescrFromType(arg_types[i]);
+                if (loop->steps[i])
+                    cntcast += descr->elsize;
+                else
+                    scntcast += descr->elsize;
+                if (i < self->nin) {
+                    loop->cast[i] = \
+                        PyArray_GetCastFunc(mps[i]->descr,
+                                    arg_types[i]);
+                }
+                else {
+                    loop->cast[i] = PyArray_GetCastFunc \
+                        (descr, mps[i]->descr->type_num);
+                }
+                Py_DECREF(descr);
+                if (!loop->cast[i]) return -1;
+            }
+            loop->swap[i] = !(PyArray_ISNOTSWAPPED(mps[i]));
+            if (loop->steps[i])
+                cnt += mps[i]->descr->elsize;
+            else
+                scnt += mps[i]->descr->elsize;
+        }
+        memsize = loop->bufsize*(cnt+cntcast) + scbufsize*(scnt+scntcast);
+        loop->buffer[0] = PyDataMem_NEW(memsize);
 
-		/* fprintf(stderr, "Allocated buffer at %p of size %d, cnt=%d, cntcast=%d\n", loop->buffer[0], loop->bufsize * (cnt + cntcast), cnt, cntcast); */
+        /* fprintf(stderr, "Allocated buffer at %p of size %d, cnt=%d, cntcast=%d\n", loop->buffer[0], loop->bufsize * (cnt + cntcast), cnt, cntcast); */
 
-		if (loop->buffer[0] == NULL) {PyErr_NoMemory(); return -1;}
-		if (loop->obj) memset(loop->buffer[0], 0, memsize);
-		castptr = loop->buffer[0] + loop->bufsize*cnt + scbufsize*scnt;
-		bufptr = loop->buffer[0];
+        if (loop->buffer[0] == NULL) {PyErr_NoMemory(); return -1;}
+        if (loop->obj) memset(loop->buffer[0], 0, memsize);
+        castptr = loop->buffer[0] + loop->bufsize*cnt + scbufsize*scnt;
+        bufptr = loop->buffer[0];
                 loop->objfunc = 0;
-		for (i=0; i<self->nargs; i++) {
-			if (!loop->needbuffer[i]) continue;
-			loop->buffer[i] = bufptr + (last_was_scalar ? scbufsize : \
-						    loop->bufsize)*oldbufsize;
-			last_was_scalar = (loop->steps[i] == 0);
-			bufptr = loop->buffer[i];
-			oldbufsize = mps[i]->descr->elsize;
-			/* fprintf(stderr, "buffer[%d] = %p\n", i, loop->buffer[i]); */
-			if (loop->cast[i]) {
-				PyArray_Descr *descr;
-				loop->castbuf[i] = castptr + (last_cast_was_scalar ? scbufsize : \
-							      loop->bufsize)*oldsize;
-				last_cast_was_scalar = last_was_scalar;
-				/* fprintf(stderr, "castbuf[%d] = %p\n", i, loop->castbuf[i]); */
-				descr = PyArray_DescrFromType(arg_types[i]);
-				oldsize = descr->elsize;
-				Py_DECREF(descr);
-				loop->bufptr[i] = loop->castbuf[i];
-				castptr = loop->castbuf[i];
-				if (loop->steps[i])
-					loop->steps[i] = oldsize;
-			}
-			else {
-				loop->bufptr[i] = loop->buffer[i];
-			}
+        for (i=0; i<self->nargs; i++) {
+            if (!loop->needbuffer[i]) continue;
+            loop->buffer[i] = bufptr + (last_was_scalar ? scbufsize : \
+                            loop->bufsize)*oldbufsize;
+            last_was_scalar = (loop->steps[i] == 0);
+            bufptr = loop->buffer[i];
+            oldbufsize = mps[i]->descr->elsize;
+            /* fprintf(stderr, "buffer[%d] = %p\n", i, loop->buffer[i]); */
+            if (loop->cast[i]) {
+                PyArray_Descr *descr;
+                loop->castbuf[i] = castptr + (last_cast_was_scalar ? scbufsize : \
+                                  loop->bufsize)*oldsize;
+                last_cast_was_scalar = last_was_scalar;
+                /* fprintf(stderr, "castbuf[%d] = %p\n", i, loop->castbuf[i]); */
+                descr = PyArray_DescrFromType(arg_types[i]);
+                oldsize = descr->elsize;
+                Py_DECREF(descr);
+                loop->bufptr[i] = loop->castbuf[i];
+                castptr = loop->castbuf[i];
+                if (loop->steps[i])
+                    loop->steps[i] = oldsize;
+            }
+            else {
+                loop->bufptr[i] = loop->buffer[i];
+            }
                         if (!loop->objfunc && loop->obj) {
                                 if (arg_types[i] == PyArray_OBJECT) {
                                         loop->objfunc = 1;
                                 }
                         }
-		}
-	}
+        }
+    }
         return nargs;
 }
 
@@ -1563,10 +1565,10 @@
 {
         if (self->ufunc) {
                 Py_XDECREF(self->it);
-		Py_XDECREF(self->rit);
+        Py_XDECREF(self->rit);
                 Py_XDECREF(self->ret);
-		Py_XDECREF(self->errobj);
-		Py_XDECREF(self->decref);
+        Py_XDECREF(self->errobj);
+        Py_XDECREF(self->decref);
                 if (self->buffer) PyDataMem_FREE(self->buffer);
                 Py_DECREF(self->ufunc);
         }
@@ -1576,44 +1578,44 @@
 static void
 ufuncloop_dealloc(PyUFuncLoopObject *self)
 {
-	int i;
+    int i;
 
-	if (self->ufunc != NULL) {
-		for (i=0; i<self->ufunc->nargs; i++)
-			Py_XDECREF(self->iters[i]);
-		if (self->buffer[0]) PyDataMem_FREE(self->buffer[0]);
-		Py_XDECREF(self->errobj);
-		Py_DECREF(self->ufunc);
-	}
+    if (self->ufunc != NULL) {
+        for (i=0; i<self->ufunc->nargs; i++)
+            Py_XDECREF(self->iters[i]);
+        if (self->buffer[0]) PyDataMem_FREE(self->buffer[0]);
+        Py_XDECREF(self->errobj);
+        Py_DECREF(self->ufunc);
+    }
         _pya_free(self);
 }
 
 static PyUFuncLoopObject *
 construct_loop(PyUFuncObject *self, PyObject *args, PyObject *kwds, PyArrayObject **mps)
 {
-	PyUFuncLoopObject *loop;
-	int i;
+    PyUFuncLoopObject *loop;
+    int i;
         PyObject *typetup=NULL;
         PyObject *extobj=NULL;
         char *name;
 
-	if (self == NULL) {
-		PyErr_SetString(PyExc_ValueError, "function not supported");
-		return NULL;
-	}
+    if (self == NULL) {
+        PyErr_SetString(PyExc_ValueError, "function not supported");
+        return NULL;
+    }
         if ((loop = _pya_malloc(sizeof(PyUFuncLoopObject)))==NULL) {
                 PyErr_NoMemory(); return loop;
         }
 
-	loop->index = 0;
-	loop->ufunc = self;
+    loop->index = 0;
+    loop->ufunc = self;
         Py_INCREF(self);
-	loop->buffer[0] = NULL;
+    loop->buffer[0] = NULL;
         for (i=0; i<self->nargs; i++) {
                 loop->iters[i] = NULL;
                 loop->cast[i] = NULL;
         }
-	loop->errobj = NULL;
+    loop->errobj = NULL;
         loop->notimplemented = 0;
         loop->first = 1;
 
@@ -1659,16 +1661,16 @@
                                     &(loop->errobj)) < 0) goto fail;
         }
         
-	/* Setup the arrays */
-	if (construct_arrays(loop, args, mps, typetup) < 0) goto fail;
+    /* Setup the arrays */
+    if (construct_arrays(loop, args, mps, typetup) < 0) goto fail;
 
-	PyUFunc_clearfperr();
+    PyUFunc_clearfperr();
 
-	return loop;
+    return loop;
 
  fail:
         ufuncloop_dealloc(loop);
-	return NULL;
+    return NULL;
 }
 
 
@@ -1676,34 +1678,34 @@
 static void
 _printbytebuf(PyUFuncLoopObject *loop, int bufnum)
 {
-	int i;
+    int i;
 
- 	fprintf(stderr, "Printing byte buffer %d\n", bufnum);
+    fprintf(stderr, "Printing byte buffer %d\n", bufnum);
         for (i=0; i<loop->bufcnt; i++) {
-	 	fprintf(stderr, "  %d\n", *(((byte *)(loop->buffer[bufnum]))+i));
-	}
+        fprintf(stderr, "  %d\n", *(((byte *)(loop->buffer[bufnum]))+i));
+    }
 }
 
 static void
 _printlongbuf(PyUFuncLoopObject *loop, int bufnum)
 {
-	int i;
+    int i;
 
- 	fprintf(stderr, "Printing long buffer %d\n", bufnum);
+    fprintf(stderr, "Printing long buffer %d\n", bufnum);
         for (i=0; i<loop->bufcnt; i++) {
-	 	fprintf(stderr, "  %ld\n", *(((long *)(loop->buffer[bufnum]))+i));
-	}
+        fprintf(stderr, "  %ld\n", *(((long *)(loop->buffer[bufnum]))+i));
+    }
 }
 
 static void
 _printlongbufptr(PyUFuncLoopObject *loop, int bufnum)
 {
-	int i;
+    int i;
 
- 	fprintf(stderr, "Printing long buffer %d\n", bufnum);
+    fprintf(stderr, "Printing long buffer %d\n", bufnum);
         for (i=0; i<loop->bufcnt; i++) {
-	 	fprintf(stderr, "  %ld\n", *(((long *)(loop->bufptr[bufnum]))+i));
-	}
+        fprintf(stderr, "  %ld\n", *(((long *)(loop->bufptr[bufnum]))+i));
+    }
 }
 
 
@@ -1711,12 +1713,12 @@
 static void
 _printcastbuf(PyUFuncLoopObject *loop, int bufnum)
 {
-	int i;
+    int i;
 
- 	fprintf(stderr, "Printing long buffer %d\n", bufnum);
+    fprintf(stderr, "Printing long buffer %d\n", bufnum);
         for (i=0; i<loop->bufcnt; i++) {
-	 	fprintf(stderr, "  %ld\n", *(((long *)(loop->castbuf[bufnum]))+i));
-	}
+        fprintf(stderr, "  %ld\n", *(((long *)(loop->castbuf[bufnum]))+i));
+    }
 }
 
 */
@@ -1739,267 +1741,386 @@
    arguments are parsed and placed in mps in construct_loop (construct_arrays)
 */
 
+typedef struct
+{
+    PyUFuncLoopObject* loop;
+    int total_threads;
+    int id;
+} thread_parm;
+
+void *ufunc_thread(void *arg)
+{
+    int i;
+    thread_parm *p = (thread_parm*) arg;
+    PyUFuncLoopObject *loop = p->loop;
+    char *args[3];
+    
+    /* Calculate the number of elements each thread should do */
+    intp size = loop->size/p->total_threads;
+    
+    /* offset the starting point of this computation loop in each
+       of the arrays involved in the operation.
+    */       
+    for (i=0; i<3;i++)
+    {
+        args[i] = (char**) (loop->bufptr[i] + 
+                            p->id * size * loop->steps[i]);
+        /*printf("%u, %u\n", loop->bufptr[i], args[i]);*/
+    }   
+     
+    /* If this is the last computational thread, it may have a
+       few extra elements at the end of the array to clean up.
+       Set the size to take care of these last elements.
+    */    
+    if (p->id+1 == p->total_threads) 
+    {
+        size = (loop->size - p->id*size)   ;
+    }    
+    /*
+    printf("thread,size,step: %d %d\n", p->id, size); 
+    printf("thread,size,step: %d %d %d\n", loop->steps[0], loop->steps[1], loop->steps[2]); 
+    */
+    loop->function(args, &size, loop->steps, loop->funcdata); 
+    return (NULL);
+}
+
 /*UFUNC_API*/
 static int
 PyUFunc_GenericFunction(PyUFuncObject *self, PyObject *args, PyObject *kwds,
-			PyArrayObject **mps)
+            PyArrayObject **mps)
 {
-	PyUFuncLoopObject *loop;
-	int i;
-        NPY_BEGIN_THREADS_DEF
+    /* thread pool for used for caluclations. */
 
-        if (!(loop = construct_loop(self, args, kwds, mps))) return -1;
-        if (loop->notimplemented) {ufuncloop_dealloc(loop); return -2;}
+    thread_parm *thread_parms;
+    PyUFuncLoopObject *loop;
+    int i;
 
-	NPY_LOOP_BEGIN_THREADS
+    /* Get the global thread count setting */
+    int use_threads=thread_settings.use_threads;
+    int thread_count=thread_settings.thread_count;
+    int element_threshold=thread_settings.element_threshold;
+    
 
-	switch(loop->meth) {
-	case ONE_UFUNCLOOP:
-		/* Everything is contiguous, notswapped, aligned,
-		   and of the right type.  -- Fastest.
-		   Or if not contiguous, then a single-stride
-		   increment moves through the entire array.
-		*/
-                /*fprintf(stderr, "ONE...%d\n", loop->size);*/
-		loop->function((char **)loop->bufptr, &(loop->size),
-			       loop->steps, loop->funcdata);
-		UFUNC_CHECK_ERROR(loop);
-		break;
-	case NOBUFFER_UFUNCLOOP: 
-		/* Everything is notswapped, aligned and of the
-		   right type but not contiguous. -- Almost as fast.
-		*/
-		/*fprintf(stderr, "NOBUFFER...%d\n", loop->size);*/
-		while (loop->index < loop->size) {
-			for (i=0; i<self->nargs; i++)
-				loop->bufptr[i] = loop->iters[i]->dataptr;
-			
-			loop->function((char **)loop->bufptr, &(loop->bufcnt),
-				       loop->steps, loop->funcdata);
-			UFUNC_CHECK_ERROR(loop);
+    static cp_thread_pool* thread_pool=NULL;
+    cp_pooled_thread* thread;
+    
+    if (thread_pool == NULL)
+    {
+        /* create a thread pool if it doesn't already exist. 
+           fixme: This should actually be quite a bit larger than thread_count
+                  to accomodate mutliple "high level" calling threads.
+        */
+        thread_pool = cp_thread_pool_create(1, 20);
+    }
 
-			/* Adjust loop pointers */
-			
-			for (i=0; i<self->nargs; i++) {
-				PyArray_ITER_NEXT(loop->iters[i]);
-			}
-			loop->index++;
-		}
-		break;
-	case BUFFER_UFUNCLOOP: {
-		PyArray_CopySwapNFunc *copyswapn[NPY_MAXARGS];
-		PyArrayIterObject **iters=loop->iters;
-		int *swap=loop->swap;
-		char **dptr=loop->dptr;
-		int mpselsize[NPY_MAXARGS];
-		intp laststrides[NPY_MAXARGS];
-		int fastmemcpy[NPY_MAXARGS];
-		int *needbuffer=loop->needbuffer;
-		intp index=loop->index, size=loop->size;
-		int bufsize;
-		intp bufcnt;
-		int copysizes[NPY_MAXARGS];
-		char **bufptr = loop->bufptr;
-		char **buffer = loop->buffer;
-		char **castbuf = loop->castbuf;
-		intp *steps = loop->steps;
-		char *tptr[NPY_MAXARGS];
-		int ninnerloops = loop->ninnerloops;
-		Bool pyobject[NPY_MAXARGS];
-		int datasize[NPY_MAXARGS];
+    NPY_BEGIN_THREADS_DEF
+
+    if (!(loop = construct_loop(self, args, kwds, mps))) return -1;
+    if (loop->notimplemented) {ufuncloop_dealloc(loop); return -2;}
+
+    //printf("%u, %u, %u\n", loop->bufptr[0], loop->bufptr[1], loop->bufptr[2]);
+    NPY_LOOP_BEGIN_THREADS
+
+    switch(loop->meth) {
+    case ONE_UFUNCLOOP:
+        /* Everything is contiguous, notswapped, aligned,
+           and of the right type.  -- Fastest.
+           Or if not contiguous, then a single-stride
+           increment moves through the entire array.
+        */
+        
+        /* Only vectorize if threading is enabled and loop includes enough
+           elemnts.
+           fixme: This should be a more interesting check 
+        */
+        if (use_threads && loop->size > element_threshold)
+        {    
+            use_threads = 1;
+        }
+	else
+	{
+            use_threads = 0;
+	}
+                
+        if (use_threads)
+        {
+            /* fprintf(stderr, "using %d threads\n", thread_count); */
+            thread_parms = (thread_parm *) malloc(thread_count * sizeof(*thread_parms));
+            for (i=0;i<thread_count;i++)
+            {
+                thread_parms[i].id = i;
+                thread_parms[i].total_threads = thread_count;
+                thread_parms[i].loop = loop;
+                thread = cp_thread_pool_get(thread_pool, ufunc_thread, (void *)(&thread_parms[i]));
+                if (thread == NULL)
+                {    
+                    /* fixme: Need more intelligent error handling */
+                    fprintf(stderr, "Thread failed");
+                }    
+            }       
+
+
+            /* fixme: This doesn't work correctly with pthreads, so we use the spin lock
+               below. This needs to */
+            /* cp_thread_pool_wait(thread_pool); */
+            
+            while (cp_hashlist_item_count(thread_pool->in_use) && thread_pool->running)
+            {
+                /*
+                cp_mutex_lock(pool->pool_lock);
+                cp_cond_wait(pool->pool_cond, pool->pool_lock);
+
+                if (pool->running && 
+                cp_hashlist_item_count(pool->in_use)) 
+                cp_cond_signal(pool->pool_cond);
+                cp_mutex_unlock(pool->pool_lock);
+                */
+            }
+
+            //fprintf(stderr, "threads finished\n");
+        }
+        else
+        {        
+            loop->function((char **)loop->bufptr, &(loop->size),
+            loop->steps, loop->funcdata);
+        }    
+        UFUNC_CHECK_ERROR(loop);
+        break;
+    case NOBUFFER_UFUNCLOOP: 
+        /* Everything is notswapped, aligned and of the
+           right type but not contiguous. -- Almost as fast.
+        */
+        /*fprintf(stderr, "NOBUFFER...%d\n", loop->size);*/
+        while (loop->index < loop->size) {
+            for (i=0; i<self->nargs; i++)
+                loop->bufptr[i] = loop->iters[i]->dataptr;
+            
+            loop->function((char **)loop->bufptr, &(loop->bufcnt),
+                       loop->steps, loop->funcdata);
+            UFUNC_CHECK_ERROR(loop);
+
+            /* Adjust loop pointers */
+            
+            for (i=0; i<self->nargs; i++) {
+                PyArray_ITER_NEXT(loop->iters[i]);
+            }
+            loop->index++;
+        }
+        break;
+    case BUFFER_UFUNCLOOP: {
+        PyArray_CopySwapNFunc *copyswapn[NPY_MAXARGS];
+        PyArrayIterObject **iters=loop->iters;
+        int *swap=loop->swap;
+        char **dptr=loop->dptr;
+        int mpselsize[NPY_MAXARGS];
+        intp laststrides[NPY_MAXARGS];
+        int fastmemcpy[NPY_MAXARGS];
+        int *needbuffer=loop->needbuffer;
+        intp index=loop->index, size=loop->size;
+        int bufsize;
+        intp bufcnt;
+        int copysizes[NPY_MAXARGS];
+        char **bufptr = loop->bufptr;
+        char **buffer = loop->buffer;
+        char **castbuf = loop->castbuf;
+        intp *steps = loop->steps;
+        char *tptr[NPY_MAXARGS];
+        int ninnerloops = loop->ninnerloops;
+        Bool pyobject[NPY_MAXARGS];
+        int datasize[NPY_MAXARGS];
                 int j, k, stopcondition;
-		char *myptr1, *myptr2;
+        char *myptr1, *myptr2;
 
 
-		for (i=0; i<self->nargs; i++) {
-			copyswapn[i] = mps[i]->descr->f->copyswapn;
-			mpselsize[i] = mps[i]->descr->elsize;
-			pyobject[i] = (loop->obj && \
+        for (i=0; i<self->nargs; i++) {
+            copyswapn[i] = mps[i]->descr->f->copyswapn;
+            mpselsize[i] = mps[i]->descr->elsize;
+            pyobject[i] = (loop->obj && \
                                        (mps[i]->descr->type_num == PyArray_OBJECT));
-			laststrides[i] = iters[i]->strides[loop->lastdim];
-			if (steps[i] && laststrides[i] != mpselsize[i]) fastmemcpy[i] = 0;
-			else fastmemcpy[i] = 1;
-		}
-		/* Do generic buffered looping here (works for any kind of
-		   arrays -- some need buffers, some don't.
-		*/
+            laststrides[i] = iters[i]->strides[loop->lastdim];
+            if (steps[i] && laststrides[i] != mpselsize[i]) fastmemcpy[i] = 0;
+            else fastmemcpy[i] = 1;
+        }
+        /* Do generic buffered looping here (works for any kind of
+           arrays -- some need buffers, some don't.
+        */
 
-		/* New algorithm: N is the largest dimension.  B is the buffer-size.
-		   quotient is loop->ninnerloops-1
-		   remainder is loop->leftover
+        /* New algorithm: N is the largest dimension.  B is the buffer-size.
+           quotient is loop->ninnerloops-1
+           remainder is loop->leftover
 
-		Compute N = quotient * B + remainder.
-		quotient = N / B  # integer math
-		(store quotient + 1) as the number of innerloops
-		remainder = N % B # integer remainder
+        Compute N = quotient * B + remainder.
+        quotient = N / B  # integer math
+        (store quotient + 1) as the number of innerloops
+        remainder = N % B # integer remainder
 
-		On the inner-dimension we will have (quotient + 1) loops where
-		the size of the inner function is B for all but the last when the niter size is
-		remainder.
+        On the inner-dimension we will have (quotient + 1) loops where
+        the size of the inner function is B for all but the last when the niter size is
+        remainder.
 
-		So, the code looks very similar to NOBUFFER_LOOP except the inner-most loop is
-		replaced with...
+        So, the code looks very similar to NOBUFFER_LOOP except the inner-most loop is
+        replaced with...
 
-		for(i=0; i<quotient+1; i++) {
-		     if (i==quotient+1) make itersize remainder size
-		     copy only needed items to buffer.
-		     swap input buffers if needed
-		     cast input buffers if needed
-		     call loop_function()
-		     cast outputs in buffers if needed
-		     swap outputs in buffers if needed
-		     copy only needed items back to output arrays.
-		     update all data-pointers by strides*niter
-		     }
-		*/
+        for(i=0; i<quotient+1; i++) {
+             if (i==quotient+1) make itersize remainder size
+             copy only needed items to buffer.
+             swap input buffers if needed
+             cast input buffers if needed
+             call loop_function()
+             cast outputs in buffers if needed
+             swap outputs in buffers if needed
+             copy only needed items back to output arrays.
+             update all data-pointers by strides*niter
+             }
+        */
 
 
-		/* fprintf(stderr, "BUFFER...%d,%d,%d\n", loop->size,
-		           loop->ninnerloops, loop->leftover);
-		*/
-		/*
-		for (i=0; i<self->nargs; i++) {
-		         fprintf(stderr, "iters[%d]->dataptr = %p, %p of size %d\n", i,
-			 iters[i], iters[i]->ao->data, PyArray_NBYTES(iters[i]->ao));
-		}
-		*/
+        /* fprintf(stderr, "BUFFER...%d,%d,%d\n", loop->size,
+                   loop->ninnerloops, loop->leftover);
+        */
+        /*
+        for (i=0; i<self->nargs; i++) {
+                 fprintf(stderr, "iters[%d]->dataptr = %p, %p of size %d\n", i,
+             iters[i], iters[i]->ao->data, PyArray_NBYTES(iters[i]->ao));
+        }
+        */
 
-		stopcondition = ninnerloops;
-		if (loop->leftover == 0) stopcondition--;
-		while (index < size) {
-			bufsize=loop->bufsize;
-			for (i=0; i<self->nargs; i++) {
-				tptr[i] = loop->iters[i]->dataptr;
-				if (needbuffer[i]) {
-					dptr[i] = bufptr[i];
-					datasize[i] = (steps[i] ? bufsize : 1);
-					copysizes[i] = datasize[i] * mpselsize[i];
-				}
-				else {
-					dptr[i] = tptr[i];
-				}
-			}
+        stopcondition = ninnerloops;
+        if (loop->leftover == 0) stopcondition--;
+        while (index < size) {
+            bufsize=loop->bufsize;
+            for (i=0; i<self->nargs; i++) {
+                tptr[i] = loop->iters[i]->dataptr;
+                if (needbuffer[i]) {
+                    dptr[i] = bufptr[i];
+                    datasize[i] = (steps[i] ? bufsize : 1);
+                    copysizes[i] = datasize[i] * mpselsize[i];
+                }
+                else {
+                    dptr[i] = tptr[i];
+                }
+            }
 
-			/* This is the inner function over the last dimension */
-			for (k=1; k<=stopcondition; k++) {
-				if (k==ninnerloops) {
+            /* This is the inner function over the last dimension */
+            for (k=1; k<=stopcondition; k++) {
+                if (k==ninnerloops) {
                                         bufsize = loop->leftover;
                                         for (i=0; i<self->nargs;i++) {
-						if (!needbuffer[i]) continue;
+                        if (!needbuffer[i]) continue;
                                                 datasize[i] = (steps[i] ? bufsize : 1);
-						copysizes[i] = datasize[i] * mpselsize[i];
+                        copysizes[i] = datasize[i] * mpselsize[i];
                                         }
                                 }
 
-				for (i=0; i<self->nin; i++) {
-					if (!needbuffer[i]) continue;
-					if (fastmemcpy[i])
-						memcpy(buffer[i], tptr[i],
-						       copysizes[i]);
-					else {
-						myptr1 = buffer[i];
-						myptr2 = tptr[i];
-						for (j=0; j<bufsize; j++) {
-							memcpy(myptr1, myptr2, mpselsize[i]);
-							myptr1 += mpselsize[i];
-							myptr2 += laststrides[i];
-						}
-					}
+                for (i=0; i<self->nin; i++) {
+                    if (!needbuffer[i]) continue;
+                    if (fastmemcpy[i])
+                        memcpy(buffer[i], tptr[i],
+                               copysizes[i]);
+                    else {
+                        myptr1 = buffer[i];
+                        myptr2 = tptr[i];
+                        for (j=0; j<bufsize; j++) {
+                            memcpy(myptr1, myptr2, mpselsize[i]);
+                            myptr1 += mpselsize[i];
+                            myptr2 += laststrides[i];
+                        }
+                    }
 
-					/* swap the buffer if necessary */
-					if (swap[i]) {
-						/* fprintf(stderr, "swapping...\n");*/
-						copyswapn[i](buffer[i], mpselsize[i], NULL, -1,
-							     (intp) datasize[i], 1,
-							     mps[i]);
-					}
-					/* cast to the other buffer if necessary */
-					if (loop->cast[i]) {
-						loop->cast[i](buffer[i],
-							      castbuf[i],
-							      (intp) datasize[i],
-							      NULL, NULL);
-					}
-				}
+                    /* swap the buffer if necessary */
+                    if (swap[i]) {
+                        /* fprintf(stderr, "swapping...\n");*/
+                        copyswapn[i](buffer[i], mpselsize[i], NULL, -1,
+                                 (intp) datasize[i], 1,
+                                 mps[i]);
+                    }
+                    /* cast to the other buffer if necessary */
+                    if (loop->cast[i]) {
+                        loop->cast[i](buffer[i],
+                                  castbuf[i],
+                                  (intp) datasize[i],
+                                  NULL, NULL);
+                    }
+                }
 
-				bufcnt = (intp) bufsize;
-				loop->function((char **)dptr, &bufcnt, steps, loop->funcdata);
+                bufcnt = (intp) bufsize;
+                loop->function((char **)dptr, &bufcnt, steps, loop->funcdata);
 
-				for (i=self->nin; i<self->nargs; i++) {
-					if (!needbuffer[i]) continue;
-					if (loop->cast[i]) {
-						loop->cast[i](castbuf[i],
-							      buffer[i],
-							      (intp) datasize[i],
-							      NULL, NULL);
-					}
-					if (swap[i]) {
-						copyswapn[i](buffer[i], mpselsize[i], NULL, -1,
-							     (intp) datasize[i], 1,
-							     mps[i]);
-					}
-					/* copy back to output arrays */
-					/* decref what's already there for object arrays */
-					if (pyobject[i]) {
-						myptr1 = tptr[i];
-						for (j=0; j<datasize[i]; j++) {
-							Py_XDECREF(*((PyObject **)myptr1));
-							myptr1 += laststrides[i];
-						}
-					}
-					if (fastmemcpy[i])
-						memcpy(tptr[i], buffer[i], copysizes[i]);
-					else {
-						myptr2 = buffer[i];
-						myptr1 = tptr[i];
-						for (j=0; j<bufsize; j++) {
-							memcpy(myptr1, myptr2,
-							       mpselsize[i]);
-							myptr1 += laststrides[i];
-							myptr2 += mpselsize[i];
-						}
-					}
+                for (i=self->nin; i<self->nargs; i++) {
+                    if (!needbuffer[i]) continue;
+                    if (loop->cast[i]) {
+                        loop->cast[i](castbuf[i],
+                                  buffer[i],
+                                  (intp) datasize[i],
+                                  NULL, NULL);
+                    }
+                    if (swap[i]) {
+                        copyswapn[i](buffer[i], mpselsize[i], NULL, -1,
+                                 (intp) datasize[i], 1,
+                                 mps[i]);
+                    }
+                    /* copy back to output arrays */
+                    /* decref what's already there for object arrays */
+                    if (pyobject[i]) {
+                        myptr1 = tptr[i];
+                        for (j=0; j<datasize[i]; j++) {
+                            Py_XDECREF(*((PyObject **)myptr1));
+                            myptr1 += laststrides[i];
+                        }
+                    }
+                    if (fastmemcpy[i])
+                        memcpy(tptr[i], buffer[i], copysizes[i]);
+                    else {
+                        myptr2 = buffer[i];
+                        myptr1 = tptr[i];
+                        for (j=0; j<bufsize; j++) {
+                            memcpy(myptr1, myptr2,
+                                   mpselsize[i]);
+                            myptr1 += laststrides[i];
+                            myptr2 += mpselsize[i];
+                        }
+                    }
                                 }
-				if (k == stopcondition) continue;
-				for (i=0; i<self->nargs; i++) {
-					tptr[i] += bufsize * laststrides[i];
-					if (!needbuffer[i]) dptr[i] = tptr[i];
-				}
-			}
+                if (k == stopcondition) continue;
+                for (i=0; i<self->nargs; i++) {
+                    tptr[i] += bufsize * laststrides[i];
+                    if (!needbuffer[i]) dptr[i] = tptr[i];
+                }
+            }
                         /* end inner function over last dimension */
 
-			if (loop->objfunc) { /* DECREF castbuf when underlying function used object arrays
+            if (loop->objfunc) { /* DECREF castbuf when underlying function used object arrays
                                                     and casting was needed to get to object arrays */
-				for (i=0; i<self->nargs; i++) {
-					if (loop->cast[i]) {
-						if (steps[i] == 0) {
-							Py_XDECREF(*((PyObject **)castbuf[i]));
-						}
-						else {
-							int size = loop->bufsize;
-							PyObject **objptr = (PyObject **)castbuf[i];
-							/* size is loop->bufsize unless there
-							   was only one loop */
-							if (ninnerloops == 1) \
-								size = loop->leftover;
+                for (i=0; i<self->nargs; i++) {
+                    if (loop->cast[i]) {
+                        if (steps[i] == 0) {
+                            Py_XDECREF(*((PyObject **)castbuf[i]));
+                        }
+                        else {
+                            int size = loop->bufsize;
+                            PyObject **objptr = (PyObject **)castbuf[i];
+                            /* size is loop->bufsize unless there
+                               was only one loop */
+                            if (ninnerloops == 1) \
+                                size = loop->leftover;
 
-							for (j=0; j<size; j++) {
-								Py_XDECREF(*objptr);
-								*objptr = NULL;
-								objptr += 1;
-							}
-						}
-					}
-				}
+                            for (j=0; j<size; j++) {
+                                Py_XDECREF(*objptr);
+                                *objptr = NULL;
+                                objptr += 1;
+                            }
+                        }
+                    }
+                }
 
-			}
+            }
 
-			UFUNC_CHECK_ERROR(loop);
+            UFUNC_CHECK_ERROR(loop);
 
-			for (i=0; i<self->nargs; i++) {
-				PyArray_ITER_NEXT(loop->iters[i]);
-			}
-			index++;
+            for (i=0; i<self->nargs; i++) {
+                PyArray_ITER_NEXT(loop->iters[i]);
+            }
+            index++;
                 }
         }
         }
@@ -2007,13 +2128,13 @@
         NPY_LOOP_END_THREADS
 
         ufuncloop_dealloc(loop);
-	return 0;
+    return 0;
 
  fail:
         NPY_LOOP_END_THREADS
 
-	if (loop) ufuncloop_dealloc(loop);
-	return -1;
+    if (loop) ufuncloop_dealloc(loop);
+    return -1;
 }
 
 static PyArrayObject *
@@ -2034,7 +2155,7 @@
                 obj = PyInt_FromLong((long) 0);
         }
 
-	typecode = PyArray_DescrFromType(otype);
+    typecode = PyArray_DescrFromType(otype);
         arr = PyArray_FromAny(obj, typecode, 0, 0, CARRAY, NULL);
         Py_DECREF(obj);
         return (PyArrayObject *)arr;
@@ -2043,34 +2164,34 @@
 static int
 _create_reduce_copy(PyUFuncReduceObject *loop, PyArrayObject **arr, int rtype)
 {
-	intp maxsize;
-	PyObject *new;
-	PyArray_Descr *ntype;
+    intp maxsize;
+    PyObject *new;
+    PyArray_Descr *ntype;
 
-	maxsize = PyArray_SIZE(*arr);
+    maxsize = PyArray_SIZE(*arr);
 
-	if (maxsize < loop->bufsize) {
-		if (!(PyArray_ISBEHAVED_RO(*arr)) ||	\
-		    PyArray_TYPE(*arr) != rtype) {
-			ntype = PyArray_DescrFromType(rtype);
-			new = PyArray_FromAny((PyObject *)(*arr),
-					      ntype, 0, 0,
-					      FORCECAST | ALIGNED, NULL);
-			if (new == NULL) return -1;
-			*arr = (PyArrayObject *)new;
-			loop->decref = new;
-		}
-	}
+    if (maxsize < loop->bufsize) {
+        if (!(PyArray_ISBEHAVED_RO(*arr)) ||    \
+            PyArray_TYPE(*arr) != rtype) {
+            ntype = PyArray_DescrFromType(rtype);
+            new = PyArray_FromAny((PyObject *)(*arr),
+                          ntype, 0, 0,
+                          FORCECAST | ALIGNED, NULL);
+            if (new == NULL) return -1;
+            *arr = (PyArrayObject *)new;
+            loop->decref = new;
+        }
+    }
 
-	/* Don't decref *arr before re-assigning
-	   because it was not going to be DECREF'd anyway.
+    /* Don't decref *arr before re-assigning
+       because it was not going to be DECREF'd anyway.
 
-	   If a copy is made, then the copy will be removed
-	   on deallocation of the loop structure by setting
-	   loop->decref.
-	*/
+       If a copy is made, then the copy will be removed
+       on deallocation of the loop structure by setting
+       loop->decref.
+    */
 
-	return 0;
+    return 0;
 }
 
 static PyUFuncReduceObject *
@@ -2079,79 +2200,76 @@
 {
         PyUFuncReduceObject *loop;
         PyArrayObject *idarr;
-	PyArrayObject *aar;
+    PyArrayObject *aar;
         intp loop_i[MAX_DIMS], outsize=0;
-        int arg_types[3];
-	PyArray_SCALARKIND scalars[3] = {PyArray_NOSCALAR, PyArray_NOSCALAR,
-					 PyArray_NOSCALAR};
-	int i, j, nd;
+        int arg_types[3] = {otype, otype, otype};
+    PyArray_SCALARKIND scalars[3] = {PyArray_NOSCALAR, PyArray_NOSCALAR,
+                     PyArray_NOSCALAR};
+    int i, j;
+    int nd = (*arr)->nd;
         int flags;
-	/* Reduce type is the type requested of the input
-	   during reduction */
+    /* Reduce type is the type requested of the input
+       during reduction */
 
-        nd = (*arr)->nd;
-        arg_types[0] = otype;
-        arg_types[1] = otype;
-        arg_types[2] = otype;
         if ((loop = _pya_malloc(sizeof(PyUFuncReduceObject)))==NULL) {
                 PyErr_NoMemory(); return loop;
         }
 
         loop->retbase=0;
         loop->swap = 0;
-	loop->index = 0;
-	loop->ufunc = self;
+    loop->index = 0;
+    loop->ufunc = self;
         Py_INCREF(self);
         loop->cast = NULL;
         loop->buffer = NULL;
         loop->ret = NULL;
-	loop->it = NULL;
-	loop->rit = NULL;
-	loop->errobj = NULL;
+    loop->it = NULL;
+    loop->rit = NULL;
+    loop->errobj = NULL;
         loop->first = 1;
-	loop->decref=NULL;
+    loop->decref=NULL;
         loop->N = (*arr)->dimensions[axis];
-	loop->instrides = (*arr)->strides[axis];
+    loop->instrides = (*arr)->strides[axis];
 
-	if (select_types(loop->ufunc, arg_types, &(loop->function),
-			 &(loop->funcdata), scalars, NULL) == -1) goto fail;
+    if (select_types(loop->ufunc, arg_types, &(loop->function),
+             &(loop->funcdata), scalars, NULL) == -1) goto fail;
 
-	/* output type may change -- if it does
-	 reduction is forced into that type
-	 and we need to select the reduction function again
-	*/
-	if (otype != arg_types[2]) {
-		otype = arg_types[2];
-		arg_types[0] = otype;
-		arg_types[1] = otype;
-		if (select_types(loop->ufunc, arg_types, &(loop->function),
-				 &(loop->funcdata), scalars, NULL) == -1)
-			goto fail;
-	}
+    /* output type may change -- if it does
+     reduction is forced into that type
+     and we need to select the reduction function again
+    */
+    if (otype != arg_types[2]) {
+        otype = arg_types[2];
+        arg_types[0] = otype;
+        arg_types[1] = otype;
+        if (select_types(loop->ufunc, arg_types, &(loop->function),
+                 &(loop->funcdata), scalars, NULL) == -1)
+            goto fail;
+    }
 
-	/* get looping parameters from Python */
-	if (PyUFunc_GetPyValues(str, &(loop->bufsize), &(loop->errormask),
-				&(loop->errobj)) < 0) goto fail;
+    /* get looping parameters from Python */
+    if (PyUFunc_GetPyValues(str, &(loop->bufsize), &(loop->errormask),
+                &(loop->errobj)) < 0) goto fail;
 
-	/* Make copy if misbehaved or not otype for small arrays */
-	if (_create_reduce_copy(loop, arr, otype) < 0) goto fail;
-	aar = *arr;
+    /* Make copy if misbehaved or not otype for small arrays */
+    if (_create_reduce_copy(loop, arr, otype) < 0) goto fail;
+    aar = *arr;
 
         if (loop->N == 0) {
                 loop->meth = ZERO_EL_REDUCELOOP;
         }
-        else if (PyArray_ISBEHAVED_RO(aar) &&		\
+        else if (PyArray_ISBEHAVED_RO(aar) &&       \
                  otype == (aar)->descr->type_num) {
-		if (loop->N == 1) {
-			loop->meth = ONE_EL_REDUCELOOP;
-		}
-		else {
-			loop->meth = NOBUFFER_UFUNCLOOP;
-			loop->steps[1] = (aar)->strides[axis];
-			loop->N -= 1;
-		}
+        if (loop->N == 1) {
+            loop->meth = ONE_EL_REDUCELOOP;
         }
         else {
+            loop->meth = NOBUFFER_UFUNCLOOP;
+            loop->steps[1] = (aar)->strides[axis];
+            loop->N -= 1;
+        }
+        }
+        else {
                 loop->meth = BUFFER_UFUNCLOOP;
                 loop->swap = !(PyArray_ISNOTSWAPPED(aar));
         }
@@ -2167,7 +2285,7 @@
                 if (idarr == NULL) goto fail;
                 if (idarr->descr->elsize > UFUNC_MAXIDENTITY) {
                         PyErr_Format(PyExc_RuntimeError,
-				     "UFUNC_MAXIDENTITY (%d)"		\
+                     "UFUNC_MAXIDENTITY (%d)"       \
                                      " is too small (needs to be at least %d)",
                                      UFUNC_MAXIDENTITY, idarr->descr->elsize);
                         Py_DECREF(idarr);
@@ -2179,13 +2297,13 @@
 
         /* Construct return array */
         flags = NPY_CARRAY | NPY_UPDATEIFCOPY | NPY_FORCECAST;
-	switch(operation) {
-	case UFUNC_REDUCE:
-		for (j=0, i=0; i<nd; i++) {
-			if (i != axis)
-				loop_i[j++] = (aar)->dimensions[i];
+    switch(operation) {
+    case UFUNC_REDUCE:
+        for (j=0, i=0; i<nd; i++) {
+            if (i != axis)
+                loop_i[j++] = (aar)->dimensions[i];
 
-		}
+        }
                 if (out == NULL) {
                         loop->ret = (PyArrayObject *)                   \
                                 PyArray_New(aar->ob_type, aar->nd-1, loop_i,
@@ -2195,8 +2313,8 @@
                 else {
                         outsize = PyArray_MultiplyList(loop_i, aar->nd-1);
                 }
-		break;
-	case UFUNC_ACCUMULATE:
+        break;
+    case UFUNC_ACCUMULATE:
                 if (out == NULL) {
                         loop->ret = (PyArrayObject *)                   \
                                 PyArray_New(aar->ob_type, aar->nd, aar->dimensions,
@@ -2205,11 +2323,11 @@
                 else {
                         outsize = PyArray_MultiplyList(aar->dimensions, aar->nd);
                 }
-		break;
-	case UFUNC_REDUCEAT:
-		memcpy(loop_i, aar->dimensions, nd*sizeof(intp));
-		/* Index is 1-d array */
-		loop_i[axis] = ind_size;
+        break;
+    case UFUNC_REDUCEAT:
+        memcpy(loop_i, aar->dimensions, nd*sizeof(intp));
+        /* Index is 1-d array */
+        loop_i[axis] = ind_size;
                 if (out == NULL) {
                         loop->ret = (PyArrayObject *)                   \
                                 PyArray_New(aar->ob_type, aar->nd, loop_i, otype,
@@ -2218,14 +2336,14 @@
                 else {
                         outsize = PyArray_MultiplyList(loop_i, aar->nd);
                 }
-		if (ind_size == 0) {
-			loop->meth = ZERO_EL_REDUCELOOP;
-			return loop;
-		}
-		if (loop->meth == ONE_EL_REDUCELOOP)
-			loop->meth = NOBUFFER_REDUCELOOP;
-		break;
-	}
+        if (ind_size == 0) {
+            loop->meth = ZERO_EL_REDUCELOOP;
+            return loop;
+        }
+        if (loop->meth == ONE_EL_REDUCELOOP)
+            loop->meth = NOBUFFER_REDUCELOOP;
+        break;
+    }
         if (out) {
                 if (PyArray_SIZE(out) != outsize) {
                         PyErr_SetString(PyExc_ValueError,
@@ -2244,21 +2362,21 @@
         loop->outsize = loop->ret->descr->elsize;
         loop->bufptr[0] = loop->ret->data;
 
-	if (loop->meth == ZERO_EL_REDUCELOOP) {
-		loop->size = PyArray_SIZE(loop->ret);
-		return loop;
-	}
+    if (loop->meth == ZERO_EL_REDUCELOOP) {
+        loop->size = PyArray_SIZE(loop->ret);
+        return loop;
+    }
 
-	loop->it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)aar);
+    loop->it = (PyArrayIterObject *)PyArray_IterNew((PyObject *)aar);
         if (loop->it == NULL) return NULL;
 
-	if (loop->meth == ONE_EL_REDUCELOOP) {
-		loop->size = loop->it->size;
-		return loop;
-	}
+    if (loop->meth == ONE_EL_REDUCELOOP) {
+        loop->size = loop->it->size;
+        return loop;
+    }
 
         /* Fix iterator to loop over correct dimension */
-	/* Set size in axis dimension to 1 */
+    /* Set size in axis dimension to 1 */
 
         loop->it->contiguous = 0;
         loop->it->size /= (loop->it->dims_m1[axis]+1);
@@ -2268,62 +2386,62 @@
 
         loop->size = loop->it->size;
 
-	if (operation == UFUNC_REDUCE) {
-		loop->steps[0] = 0;
-	}
-	else {
-		loop->rit = (PyArrayIterObject *)			\
-			PyArray_IterNew((PyObject *)(loop->ret));
-		if (loop->rit == NULL) return NULL;
+    if (operation == UFUNC_REDUCE) {
+        loop->steps[0] = 0;
+    }
+    else {
+        loop->rit = (PyArrayIterObject *)           \
+            PyArray_IterNew((PyObject *)(loop->ret));
+        if (loop->rit == NULL) return NULL;
 
-		/* Fix iterator to loop over correct dimension */
-		/* Set size in axis dimension to 1 */
+        /* Fix iterator to loop over correct dimension */
+        /* Set size in axis dimension to 1 */
 
-		loop->rit->contiguous = 0;
-		loop->rit->size /= (loop->rit->dims_m1[axis]+1);
-		loop->rit->dims_m1[axis] = 0;
-		loop->rit->backstrides[axis] = 0;
+        loop->rit->contiguous = 0;
+        loop->rit->size /= (loop->rit->dims_m1[axis]+1);
+        loop->rit->dims_m1[axis] = 0;
+        loop->rit->backstrides[axis] = 0;
 
-		if (operation == UFUNC_ACCUMULATE)
-			loop->steps[0] = loop->ret->strides[axis];
-		else
-			loop->steps[0] = 0;
-	}
-	loop->steps[2] = loop->steps[0];
-	loop->bufptr[2] = loop->bufptr[0] + loop->steps[2];
+        if (operation == UFUNC_ACCUMULATE)
+            loop->steps[0] = loop->ret->strides[axis];
+        else
+            loop->steps[0] = 0;
+    }
+    loop->steps[2] = loop->steps[0];
+    loop->bufptr[2] = loop->bufptr[0] + loop->steps[2];
 
 
-	if (loop->meth == BUFFER_UFUNCLOOP) {
-		int _size;
-		loop->steps[1] = loop->outsize;
+    if (loop->meth == BUFFER_UFUNCLOOP) {
+        int _size;
+        loop->steps[1] = loop->outsize;
                 if (otype != aar->descr->type_num) {
-			_size=loop->bufsize*(loop->outsize +		\
-					     aar->descr->elsize);
+            _size=loop->bufsize*(loop->outsize +        \
+                         aar->descr->elsize);
                         loop->buffer = PyDataMem_NEW(_size);
                         if (loop->buffer == NULL) goto fail;
-			if (loop->obj) memset(loop->buffer, 0, _size);
+            if (loop->obj) memset(loop->buffer, 0, _size);
                         loop->castbuf = loop->buffer + \
                                 loop->bufsize*aar->descr->elsize;
                         loop->bufptr[1] = loop->castbuf;
                         loop->cast = PyArray_GetCastFunc(aar->descr, otype);
-			if (loop->cast == NULL) goto fail;
+            if (loop->cast == NULL) goto fail;
                 }
                 else {
-			_size = loop->bufsize * loop->outsize;
+            _size = loop->bufsize * loop->outsize;
                         loop->buffer = PyDataMem_NEW(_size);
                         if (loop->buffer == NULL) goto fail;
-			if (loop->obj) memset(loop->buffer, 0, _size);
+            if (loop->obj) memset(loop->buffer, 0, _size);
                         loop->bufptr[1] = loop->buffer;
                 }
-	}
+    }
 
 
-	PyUFunc_clearfperr();
-	return loop;
+    PyUFunc_clearfperr();
+    return loop;
 
  fail:
         ufuncreduce_dealloc(loop);
-	return NULL;
+    return NULL;
 }
 
 
@@ -2347,45 +2465,45 @@
 
         /* Construct loop object */
         loop = construct_reduce(self, &arr, out, axis, otype, UFUNC_REDUCE, 0,
-				"reduce");
-	if (!loop) return NULL;
+                "reduce");
+    if (!loop) return NULL;
 
         NPY_LOOP_BEGIN_THREADS
         switch(loop->meth) {
         case ZERO_EL_REDUCELOOP:
-		/* fprintf(stderr, "ZERO..%d\n", loop->size); */
-		for(i=0; i<loop->size; i++) {
-			if (loop->obj) Py_INCREF(*((PyObject **)loop->idptr));
-			memmove(loop->bufptr[0], loop->idptr, loop->outsize);
-			loop->bufptr[0] += loop->outsize;
-		}
+        /* fprintf(stderr, "ZERO..%d\n", loop->size); */
+        for(i=0; i<loop->size; i++) {
+            if (loop->obj) Py_INCREF(*((PyObject **)loop->idptr));
+            memmove(loop->bufptr[0], loop->idptr, loop->outsize);
+            loop->bufptr[0] += loop->outsize;
+        }
                 break;
         case ONE_EL_REDUCELOOP:
-		/*fprintf(stderr, "ONEDIM..%d\n", loop->size); */
+        /*fprintf(stderr, "ONEDIM..%d\n", loop->size); */
                 while(loop->index < loop->size) {
-			if (loop->obj)
-				Py_INCREF(*((PyObject **)loop->it->dataptr));
+            if (loop->obj)
+                Py_INCREF(*((PyObject **)loop->it->dataptr));
                         memmove(loop->bufptr[0], loop->it->dataptr,
                                loop->outsize);
-			PyArray_ITER_NEXT(loop->it);
-			loop->bufptr[0] += loop->outsize;
-			loop->index++;
-		}
-		break;
+            PyArray_ITER_NEXT(loop->it);
+            loop->bufptr[0] += loop->outsize;
+            loop->index++;
+        }
+        break;
         case NOBUFFER_UFUNCLOOP:
-		/*fprintf(stderr, "NOBUFFER..%d\n", loop->size); */
+        /*fprintf(stderr, "NOBUFFER..%d\n", loop->size); */
                 while(loop->index < loop->size) {
-			/* Copy first element to output */
-			if (loop->obj)
-				Py_INCREF(*((PyObject **)loop->it->dataptr));
+            /* Copy first element to output */
+            if (loop->obj)
+                Py_INCREF(*((PyObject **)loop->it->dataptr));
                         memmove(loop->bufptr[0], loop->it->dataptr,
                                loop->outsize);
-			/* Adjust input pointer */
+            /* Adjust input pointer */
                         loop->bufptr[1] = loop->it->dataptr+loop->steps[1];
                         loop->function((char **)loop->bufptr,
-				       &(loop->N),
+                       &(loop->N),
                                        loop->steps, loop->funcdata);
-			UFUNC_CHECK_ERROR(loop);
+            UFUNC_CHECK_ERROR(loop);
 
                         PyArray_ITER_NEXT(loop->it)
                         loop->bufptr[0] += loop->outsize;
@@ -2404,31 +2522,31 @@
                       b. Call inner function.
                    4. Repeat 2 until row is done.
                 */
-		/* fprintf(stderr, "BUFFERED..%d %d\n", loop->size,
-		   loop->swap); */
+        /* fprintf(stderr, "BUFFERED..%d %d\n", loop->size,
+           loop->swap); */
                 while(loop->index < loop->size) {
                         loop->inptr = loop->it->dataptr;
-			/* Copy (cast) First term over to output */
-			if (loop->cast) {
-				/* A little tricky because we need to
-				   cast it first */
-				arr->descr->f->copyswap(loop->buffer,
-							loop->inptr,
-							loop->swap,
-							NULL);
-				loop->cast(loop->buffer, loop->castbuf,
-					   1, NULL, NULL);
-				if (loop->obj)
-					Py_INCREF(*((PyObject **)loop->castbuf));
-				memcpy(loop->bufptr[0], loop->castbuf,
-				       loop->outsize);
-			}
-			else { /* Simple copy */
-				arr->descr->f->copyswap(loop->bufptr[0],
-							loop->inptr,
-							loop->swap, NULL);
-			}
-			loop->inptr += loop->instrides;
+            /* Copy (cast) First term over to output */
+            if (loop->cast) {
+                /* A little tricky because we need to
+                   cast it first */
+                arr->descr->f->copyswap(loop->buffer,
+                            loop->inptr,
+                            loop->swap,
+                            NULL);
+                loop->cast(loop->buffer, loop->castbuf,
+                       1, NULL, NULL);
+                if (loop->obj)
+                    Py_INCREF(*((PyObject **)loop->castbuf));
+                memcpy(loop->bufptr[0], loop->castbuf,
+                       loop->outsize);
+            }
+            else { /* Simple copy */
+                arr->descr->f->copyswap(loop->bufptr[0],
+                            loop->inptr,
+                            loop->swap, NULL);
+            }
+            loop->inptr += loop->instrides;
                         n = 1;
                         while(n < loop->N) {
                                 /* Copy up to loop->bufsize elements to
@@ -2437,9 +2555,9 @@
                                 for (i=0; i<loop->bufsize; i++, n++) {
                                         if (n == loop->N) break;
                                         arr->descr->f->copyswap(dptr,
-								loop->inptr,
-								loop->swap,
-								NULL);
+                                loop->inptr,
+                                loop->swap,
+                                NULL);
                                         loop->inptr += loop->instrides;
                                         dptr += loop->insize;
                                 }
@@ -2449,10 +2567,10 @@
                                                    i, NULL, NULL);
                                 loop->function((char **)loop->bufptr,
                                                &i,
-					       loop->steps, loop->funcdata);
-				loop->bufptr[0] += loop->steps[0]*i;
-				loop->bufptr[2] += loop->steps[2]*i;
-				UFUNC_CHECK_ERROR(loop);
+                           loop->steps, loop->funcdata);
+                loop->bufptr[0] += loop->steps[0]*i;
+                loop->bufptr[2] += loop->steps[2]*i;
+                UFUNC_CHECK_ERROR(loop);
                         }
                         PyArray_ITER_NEXT(loop->it);
                         loop->bufptr[0] += loop->outsize;
@@ -2463,7 +2581,7 @@
 
         NPY_LOOP_END_THREADS
 
-	/* Hang on to this reference -- will be decref'd with loop */
+    /* Hang on to this reference -- will be decref'd with loop */
         if (loop->retbase) ret = (PyArrayObject *)loop->ret->base;
         else ret = loop->ret;
         Py_INCREF(ret);
@@ -2486,55 +2604,55 @@
         PyUFuncReduceObject *loop;
         intp i, n;
         char *dptr;
-	NPY_BEGIN_THREADS_DEF
+    NPY_BEGIN_THREADS_DEF
 
         /* Construct loop object */
         loop = construct_reduce(self, &arr, out, axis, otype, UFUNC_ACCUMULATE, 0,
-				"accumulate");
-	if (!loop) return NULL;
+                "accumulate");
+    if (!loop) return NULL;
 
-	NPY_LOOP_BEGIN_THREADS
+    NPY_LOOP_BEGIN_THREADS
         switch(loop->meth) {
         case ZERO_EL_REDUCELOOP: /* Accumulate */
-		/* fprintf(stderr, "ZERO..%d\n", loop->size); */
-		for(i=0; i<loop->size; i++) {
-			if (loop->obj)
-				Py_INCREF(*((PyObject **)loop->idptr));
-			memcpy(loop->bufptr[0], loop->idptr, loop->outsize);
-			loop->bufptr[0] += loop->outsize;
-		}
+        /* fprintf(stderr, "ZERO..%d\n", loop->size); */
+        for(i=0; i<loop->size; i++) {
+            if (loop->obj)
+                Py_INCREF(*((PyObject **)loop->idptr));
+            memcpy(loop->bufptr[0], loop->idptr, loop->outsize);
+            loop->bufptr[0] += loop->outsize;
+        }
                 break;
         case ONE_EL_REDUCELOOP: /* Accumulate */
-		/* fprintf(stderr, "ONEDIM..%d\n", loop->size); */
+        /* fprintf(stderr, "ONEDIM..%d\n", loop->size); */
                 while(loop->index < loop->size) {
-			if (loop->obj)
-				Py_INCREF(*((PyObject **)loop->it->dataptr));
+            if (loop->obj)
+                Py_INCREF(*((PyObject **)loop->it->dataptr));
                         memcpy(loop->bufptr[0], loop->it->dataptr,
                                loop->outsize);
-			PyArray_ITER_NEXT(loop->it);
-			loop->bufptr[0] += loop->outsize;
-			loop->index++;
-		}
-		break;
+            PyArray_ITER_NEXT(loop->it);
+            loop->bufptr[0] += loop->outsize;
+            loop->index++;
+        }
+        break;
         case NOBUFFER_UFUNCLOOP: /* Accumulate */
-		/* fprintf(stderr, "NOBUFFER..%d\n", loop->size); */
+        /* fprintf(stderr, "NOBUFFER..%d\n", loop->size); */
                 while(loop->index < loop->size) {
-			/* Copy first element to output */
-			if (loop->obj)
-				Py_INCREF(*((PyObject **)loop->it->dataptr));
+            /* Copy first element to output */
+            if (loop->obj)
+                Py_INCREF(*((PyObject **)loop->it->dataptr));
                         memcpy(loop->bufptr[0], loop->it->dataptr,
                                loop->outsize);
-			/* Adjust input pointer */
+            /* Adjust input pointer */
                         loop->bufptr[1] = loop->it->dataptr+loop->steps[1];
                         loop->function((char **)loop->bufptr,
-				       &(loop->N),
+                       &(loop->N),
                                        loop->steps, loop->funcdata);
-			UFUNC_CHECK_ERROR(loop);
+            UFUNC_CHECK_ERROR(loop);
 
                         PyArray_ITER_NEXT(loop->it);
-			PyArray_ITER_NEXT(loop->rit);
+            PyArray_ITER_NEXT(loop->rit);
                         loop->bufptr[0] = loop->rit->dataptr;
-			loop->bufptr[2] = loop->bufptr[0] + loop->steps[0];
+            loop->bufptr[2] = loop->bufptr[0] + loop->steps[0];
                         loop->index++;
                 }
                 break;
@@ -2549,32 +2667,32 @@
                       b. Call inner function.
                    4. Repeat 2 until row is done.
                 */
-		/* fprintf(stderr, "BUFFERED..%d %p\n", loop->size,
-		   loop->cast); */
+        /* fprintf(stderr, "BUFFERED..%d %p\n", loop->size,
+           loop->cast); */
                 while(loop->index < loop->size) {
                         loop->inptr = loop->it->dataptr;
-			/* Copy (cast) First term over to output */
-			if (loop->cast) {
-				/* A little tricky because we need to
-				   cast it first */
-				arr->descr->f->copyswap(loop->buffer,
-							loop->inptr,
-							loop->swap,
-							NULL);
-				loop->cast(loop->buffer, loop->castbuf,
-					   1, NULL, NULL);
-				if (loop->obj)
-					Py_INCREF(*((PyObject **)loop->castbuf));
-				memcpy(loop->bufptr[0], loop->castbuf,
-				       loop->outsize);
-			}
-			else { /* Simple copy */
-				arr->descr->f->copyswap(loop->bufptr[0],
-							loop->inptr,
-							loop->swap,
-							NULL);
-			}
-			loop->inptr += loop->instrides;
+            /* Copy (cast) First term over to output */
+            if (loop->cast) {
+                /* A little tricky because we need to
+                   cast it first */
+                arr->descr->f->copyswap(loop->buffer,
+                            loop->inptr,
+                            loop->swap,
+                            NULL);
+                loop->cast(loop->buffer, loop->castbuf,
+                       1, NULL, NULL);
+                if (loop->obj)
+                    Py_INCREF(*((PyObject **)loop->castbuf));
+                memcpy(loop->bufptr[0], loop->castbuf,
+                       loop->outsize);
+            }
+            else { /* Simple copy */
+                arr->descr->f->copyswap(loop->bufptr[0],
+                            loop->inptr,
+                            loop->swap,
+                            NULL);
+            }
+            loop->inptr += loop->instrides;
                         n = 1;
                         while(n < loop->N) {
                                 /* Copy up to loop->bufsize elements to
@@ -2583,9 +2701,9 @@
                                 for (i=0; i<loop->bufsize; i++, n++) {
                                         if (n == loop->N) break;
                                         arr->descr->f->copyswap(dptr,
-								loop->inptr,
-								loop->swap,
-								NULL);
+                                loop->inptr,
+                                loop->swap,
+                                NULL);
                                         loop->inptr += loop->instrides;
                                         dptr += loop->insize;
                                 }
@@ -2595,22 +2713,22 @@
                                                    i, NULL, NULL);
                                 loop->function((char **)loop->bufptr,
                                                &i,
-					       loop->steps, loop->funcdata);
-				loop->bufptr[0] += loop->steps[0]*i;
-				loop->bufptr[2] += loop->steps[2]*i;
-				UFUNC_CHECK_ERROR(loop);
+                           loop->steps, loop->funcdata);
+                loop->bufptr[0] += loop->steps[0]*i;
+                loop->bufptr[2] += loop->steps[2]*i;
+                UFUNC_CHECK_ERROR(loop);
                         }
                         PyArray_ITER_NEXT(loop->it);
-			PyArray_ITER_NEXT(loop->rit);
+            PyArray_ITER_NEXT(loop->rit);
                         loop->bufptr[0] = loop->rit->dataptr;
-			loop->bufptr[2] = loop->bufptr[0] + loop->steps[0];
+            loop->bufptr[2] = loop->bufptr[0] + loop->steps[0];
                         loop->index++;
                 }
         }
 
-	NPY_LOOP_END_THREADS
+    NPY_LOOP_END_THREADS
 
-	/* Hang on to this reference -- will be decref'd with loop */
+    /* Hang on to this reference -- will be decref'd with loop */
         if (loop->retbase) ret = (PyArrayObject *)loop->ret->base;
         else ret = loop->ret;
         Py_INCREF(ret);
@@ -2618,7 +2736,7 @@
         return (PyObject *)ret;
 
  fail:
-	NPY_LOOP_END_THREADS
+    NPY_LOOP_END_THREADS
 
         if (loop) ufuncreduce_dealloc(loop);
         return NULL;
@@ -2647,121 +2765,121 @@
 PyUFunc_Reduceat(PyUFuncObject *self, PyArrayObject *arr, PyArrayObject *ind,
                  PyArrayObject *out, int axis, int otype)
 {
-	PyArrayObject *ret;
+    PyArrayObject *ret;
         PyUFuncReduceObject *loop;
-	intp *ptr=(intp *)ind->data;
-	intp nn=ind->dimensions[0];
-	intp mm=arr->dimensions[axis]-1;
-	intp n, i, j;
-	char *dptr;
-	NPY_BEGIN_THREADS_DEF
+    intp *ptr=(intp *)ind->data;
+    intp nn=ind->dimensions[0];
+    intp mm=arr->dimensions[axis]-1;
+    intp n, i, j;
+    char *dptr;
+    NPY_BEGIN_THREADS_DEF
 
-	/* Check for out-of-bounds values in indices array */
-	for (i=0; i<nn; i++) {
-		if ((*ptr < 0) || (*ptr > mm)) {
-			PyErr_Format(PyExc_IndexError,
-				     "index out-of-bounds (0, %d)", (int) mm);
-			return NULL;
-		}
-		ptr++;
-	}
+    /* Check for out-of-bounds values in indices array */
+    for (i=0; i<nn; i++) {
+        if ((*ptr < 0) || (*ptr > mm)) {
+            PyErr_Format(PyExc_IndexError,
+                     "index out-of-bounds (0, %d)", (int) mm);
+            return NULL;
+        }
+        ptr++;
+    }
 
-	ptr = (intp *)ind->data;
+    ptr = (intp *)ind->data;
         /* Construct loop object */
         loop = construct_reduce(self, &arr, out, axis, otype, UFUNC_REDUCEAT, nn,
-				"reduceat");
-	if (!loop) return NULL;
+                "reduceat");
+    if (!loop) return NULL;
 
-	NPY_LOOP_BEGIN_THREADS
-	switch(loop->meth) {
-	/* zero-length index -- return array immediately */
-	case ZERO_EL_REDUCELOOP:
-		/* fprintf(stderr, "ZERO..\n"); */
-		break;
-	/* NOBUFFER -- behaved array and same type */
-	case NOBUFFER_UFUNCLOOP: 	                /* Reduceat */
-		/* fprintf(stderr, "NOBUFFER..%d\n", loop->size); */
-		while(loop->index < loop->size) {
-			ptr = (intp *)ind->data;
-			for (i=0; i<nn; i++) {
-				loop->bufptr[1] = loop->it->dataptr +	\
-					(*ptr)*loop->instrides;
-				if (loop->obj)
-					Py_INCREF(*((PyObject **)loop->bufptr[1]));
-				memcpy(loop->bufptr[0], loop->bufptr[1],
-				       loop->outsize);
-				mm = (i==nn-1 ? arr->dimensions[axis]-*ptr : \
-				      *(ptr+1) - *ptr) - 1;
-				if (mm > 0) {
-					loop->bufptr[1] += loop->instrides;
-					loop->bufptr[2] = loop->bufptr[0];
-					loop->function((char **)loop->bufptr,
-						       &mm, loop->steps,
-						       loop->funcdata);
-					UFUNC_CHECK_ERROR(loop);
-				}
-				loop->bufptr[0] += loop->ret->strides[axis];
-				ptr++;
-			}
-			PyArray_ITER_NEXT(loop->it);
-			PyArray_ITER_NEXT(loop->rit);
-			loop->bufptr[0] = loop->rit->dataptr;
-			loop->index++;
-		}
-		break;
+    NPY_LOOP_BEGIN_THREADS
+    switch(loop->meth) {
+    /* zero-length index -- return array immediately */
+    case ZERO_EL_REDUCELOOP:
+        /* fprintf(stderr, "ZERO..\n"); */
+        break;
+    /* NOBUFFER -- behaved array and same type */
+    case NOBUFFER_UFUNCLOOP:                    /* Reduceat */
+        /* fprintf(stderr, "NOBUFFER..%d\n", loop->size); */
+        while(loop->index < loop->size) {
+            ptr = (intp *)ind->data;
+            for (i=0; i<nn; i++) {
+                loop->bufptr[1] = loop->it->dataptr +   \
+                    (*ptr)*loop->instrides;
+                if (loop->obj)
+                    Py_INCREF(*((PyObject **)loop->bufptr[1]));
+                memcpy(loop->bufptr[0], loop->bufptr[1],
+                       loop->outsize);
+                mm = (i==nn-1 ? arr->dimensions[axis]-*ptr : \
+                      *(ptr+1) - *ptr) - 1;
+                if (mm > 0) {
+                    loop->bufptr[1] += loop->instrides;
+                    loop->bufptr[2] = loop->bufptr[0];
+                    loop->function((char **)loop->bufptr,
+                               &mm, loop->steps,
+                               loop->funcdata);
+                    UFUNC_CHECK_ERROR(loop);
+                }
+                loop->bufptr[0] += loop->ret->strides[axis];
+                ptr++;
+            }
+            PyArray_ITER_NEXT(loop->it);
+            PyArray_ITER_NEXT(loop->rit);
+            loop->bufptr[0] = loop->rit->dataptr;
+            loop->index++;
+        }
+        break;
 
-	/* BUFFER -- misbehaved array or different types */
-	case BUFFER_UFUNCLOOP:                               /* Reduceat */
-		/* fprintf(stderr, "BUFFERED..%d\n", loop->size); */
-		while(loop->index < loop->size) {
-			ptr = (intp *)ind->data;
-			for (i=0; i<nn; i++) {
-				if (loop->obj)
-					Py_INCREF(*((PyObject **)loop->idptr));
-				memcpy(loop->bufptr[0], loop->idptr,
-				       loop->outsize);
-				n = 0;
-				mm = (i==nn-1 ? arr->dimensions[axis] - *ptr :\
-				      *(ptr+1) - *ptr);
-				if (mm < 1) mm = 1;
-				loop->inptr = loop->it->dataptr + \
-					(*ptr)*loop->instrides;
-				while (n < mm) {
-					/* Copy up to loop->bufsize elements
-					   to buffer */
-					dptr = loop->buffer;
-					for (j=0; j<loop->bufsize; j++, n++) {
-						if (n == mm) break;
-						arr->descr->f->copyswap\
-							(dptr,
-							 loop->inptr,
-							 loop->swap, NULL);
-						loop->inptr += loop->instrides;
-						dptr += loop->insize;
-					}
-					if (loop->cast)
-						loop->cast(loop->buffer,
-							   loop->castbuf,
-							   j, NULL, NULL);
-					loop->bufptr[2] = loop->bufptr[0];
-					loop->function((char **)loop->bufptr,
-						       &j, loop->steps,
-						       loop->funcdata);
-					UFUNC_CHECK_ERROR(loop);
-					loop->bufptr[0] += j*loop->steps[0];
-				}
-				loop->bufptr[0] += loop->ret->strides[axis];
-				ptr++;
-			}
-			PyArray_ITER_NEXT(loop->it);
-			PyArray_ITER_NEXT(loop->rit);
-			loop->bufptr[0] = loop->rit->dataptr;
-			loop->index++;
-		}
-		break;
-	}
+    /* BUFFER -- misbehaved array or different types */
+    case BUFFER_UFUNCLOOP:                               /* Reduceat */
+        /* fprintf(stderr, "BUFFERED..%d\n", loop->size); */
+        while(loop->index < loop->size) {
+            ptr = (intp *)ind->data;
+            for (i=0; i<nn; i++) {
+                if (loop->obj)
+                    Py_INCREF(*((PyObject **)loop->idptr));
+                memcpy(loop->bufptr[0], loop->idptr,
+                       loop->outsize);
+                n = 0;
+                mm = (i==nn-1 ? arr->dimensions[axis] - *ptr :\
+                      *(ptr+1) - *ptr);
+                if (mm < 1) mm = 1;
+                loop->inptr = loop->it->dataptr + \
+                    (*ptr)*loop->instrides;
+                while (n < mm) {
+                    /* Copy up to loop->bufsize elements
+                       to buffer */
+                    dptr = loop->buffer;
+                    for (j=0; j<loop->bufsize; j++, n++) {
+                        if (n == mm) break;
+                        arr->descr->f->copyswap\
+                            (dptr,
+                             loop->inptr,
+                             loop->swap, NULL);
+                        loop->inptr += loop->instrides;
+                        dptr += loop->insize;
+                    }
+                    if (loop->cast)
+                        loop->cast(loop->buffer,
+                               loop->castbuf,
+                               j, NULL, NULL);
+                    loop->bufptr[2] = loop->bufptr[0];
+                    loop->function((char **)loop->bufptr,
+                               &j, loop->steps,
+                               loop->funcdata);
+                    UFUNC_CHECK_ERROR(loop);
+                    loop->bufptr[0] += j*loop->steps[0];
+                }
+                loop->bufptr[0] += loop->ret->strides[axis];
+                ptr++;
+            }
+            PyArray_ITER_NEXT(loop->it);
+            PyArray_ITER_NEXT(loop->rit);
+            loop->bufptr[0] = loop->rit->dataptr;
+            loop->index++;
+        }
+        break;
+    }
 
-	NPY_LOOP_END_THREADS
+    NPY_LOOP_END_THREADS
 
         /* Hang on to this reference -- will be decref'd with loop */
         if (loop->retbase) ret = (PyArrayObject *)loop->ret->base;
@@ -2771,10 +2889,10 @@
         return (PyObject *)ret;
 
  fail:
-	NPY_LOOP_END_THREADS
+    NPY_LOOP_END_THREADS
 
         if (loop) ufuncreduce_dealloc(loop);
-	return NULL;
+    return NULL;
 }
 
 
@@ -2787,68 +2905,68 @@
 PyUFunc_GenericReduction(PyUFuncObject *self, PyObject *args,
                          PyObject *kwds, int operation)
 {
-	int axis=0;
-	PyArrayObject *mp, *ret = NULL;
-	PyObject *op, *res=NULL;
-	PyObject *obj_ind, *context;
-	PyArrayObject *indices = NULL;
-	PyArray_Descr *otype=NULL;
+    int axis=0;
+    PyArrayObject *mp, *ret = NULL;
+    PyObject *op, *res=NULL;
+    PyObject *obj_ind, *context;
+    PyArrayObject *indices = NULL;
+    PyArray_Descr *otype=NULL;
         PyArrayObject *out=NULL;
-	static char *kwlist1[] = {"array", "axis", "dtype", "out", NULL};
-	static char *kwlist2[] = {"array", "indices", "axis", "dtype", "out", NULL};
+    static char *kwlist1[] = {"array", "axis", "dtype", "out", NULL};
+    static char *kwlist2[] = {"array", "indices", "axis", "dtype", "out", NULL};
         static char *_reduce_type[] = {"reduce", "accumulate", \
-				       "reduceat", NULL};
-	if (self == NULL) {
-		PyErr_SetString(PyExc_ValueError, "function not supported");
-		return NULL;
-	}
+                       "reduceat", NULL};
+    if (self == NULL) {
+        PyErr_SetString(PyExc_ValueError, "function not supported");
+        return NULL;
+    }
 
-	if (self->nin != 2) {
-		PyErr_Format(PyExc_ValueError,
+    if (self->nin != 2) {
+        PyErr_Format(PyExc_ValueError,
                              "%s only supported for binary functions",
                              _reduce_type[operation]);
-		return NULL;
-	}
-	if (self->nout != 1) {
-		PyErr_Format(PyExc_ValueError,
+        return NULL;
+    }
+    if (self->nout != 1) {
+        PyErr_Format(PyExc_ValueError,
                              "%s only supported for functions " \
                              "returning a single value",
                              _reduce_type[operation]);
-		return NULL;
-	}
+        return NULL;
+    }
 
-	if (operation == UFUNC_REDUCEAT) {
-		PyArray_Descr *indtype;
-		indtype = PyArray_DescrFromType(PyArray_INTP);
-		if(!PyArg_ParseTupleAndKeywords(args, kwds, "OO|iO&O&", kwlist2,
-						&op, &obj_ind, &axis,
-						PyArray_DescrConverter2,
-						&otype,
+    if (operation == UFUNC_REDUCEAT) {
+        PyArray_Descr *indtype;
+        indtype = PyArray_DescrFromType(PyArray_INTP);
+        if(!PyArg_ParseTupleAndKeywords(args, kwds, "OO|iO&O&", kwlist2,
+                        &op, &obj_ind, &axis,
+                        PyArray_DescrConverter2,
+                        &otype,
                                                 PyArray_OutputConverter,
                                                 &out)) return NULL;
                 indices = (PyArrayObject *)PyArray_FromAny(obj_ind, indtype,
-							   1, 1, CARRAY, NULL);
+                               1, 1, CARRAY, NULL);
                 if (indices == NULL) return NULL;
-	}
-	else {
-		if(!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO&O&", kwlist1,
-						&op, &axis,
-						PyArray_DescrConverter2,
-						&otype,
+    }
+    else {
+        if(!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO&O&", kwlist1,
+                        &op, &axis,
+                        PyArray_DescrConverter2,
+                        &otype,
                                                 PyArray_OutputConverter,
                                                 &out)) return NULL;
-	}
+    }
 
-	/* Ensure input is an array */
+    /* Ensure input is an array */
         if (!PyArray_Check(op) && !PyArray_IsScalar(op, Generic)) {
                 context = Py_BuildValue("O(O)i", self, op, 0);
         }
         else {
                 context = NULL;
         }
-	mp = (PyArrayObject *)PyArray_FromAny(op, NULL, 0, 0, 0, context);
+    mp = (PyArrayObject *)PyArray_FromAny(op, NULL, 0, 0, 0, context);
         Py_XDECREF(context);
-	if (mp == NULL) return NULL;
+    if (mp == NULL) return NULL;
 
         /* Check to see if input is zero-dimensional */
         if (mp->nd == 0) {
@@ -2859,23 +2977,23 @@
         }
 
         /* Check to see that type (and otype) is not FLEXIBLE */
-	if (PyArray_ISFLEXIBLE(mp) ||
-	    (otype && PyTypeNum_ISFLEXIBLE(otype->type_num))) {
+    if (PyArray_ISFLEXIBLE(mp) ||
+        (otype && PyTypeNum_ISFLEXIBLE(otype->type_num))) {
                 PyErr_Format(PyExc_TypeError,
-			     "cannot perform %s with flexible type",
+                 "cannot perform %s with flexible type",
                              _reduce_type[operation]);
                 Py_DECREF(mp);
                 return NULL;
         }
 
-	if (axis < 0) axis += mp->nd;
-	if (axis < 0 || axis >= mp->nd) {
-		PyErr_SetString(PyExc_ValueError, "axis not in array");
+    if (axis < 0) axis += mp->nd;
+    if (axis < 0 || axis >= mp->nd) {
+        PyErr_SetString(PyExc_ValueError, "axis not in array");
                 Py_DECREF(mp);
-		return NULL;
-	}
+        return NULL;
+    }
 
-	/* If out is specified it determines otype unless otype
+    /* If out is specified it determines otype unless otype
            already specified.
          */
         if (otype == NULL && out != NULL) {
@@ -2884,10 +3002,10 @@
         }
 
         if (otype == NULL) {
-		/* For integer types --- make sure at
-		   least a long is used for add and multiply
+        /* For integer types --- make sure at
+           least a long is used for add and multiply
                    reduction --- to avoid overflow */
-		int typenum = PyArray_TYPE(mp);
+        int typenum = PyArray_TYPE(mp);
                 if ((typenum < NPY_FLOAT) &&                \
                     ((strcmp(self->name,"add")==0) ||       \
                      (strcmp(self->name,"multiply")==0))) {
@@ -2908,30 +3026,30 @@
         case UFUNC_REDUCE:
                 ret = (PyArrayObject *)PyUFunc_Reduce(self, mp, out, axis,
                                                       otype->type_num);
-		break;
+        break;
         case UFUNC_ACCUMULATE:
                 ret = (PyArrayObject *)PyUFunc_Accumulate(self, mp, out, axis,
                                                           otype->type_num);
-		break;
+        break;
         case UFUNC_REDUCEAT:
                 ret = (PyArrayObject *)PyUFunc_Reduceat(self, mp, indices, out,
                                                         axis, otype->type_num);
                 Py_DECREF(indices);
-		break;
+        break;
         }
         Py_DECREF(mp);
-	Py_DECREF(otype);
-	if (ret==NULL) return NULL;
-	if (op->ob_type != ret->ob_type) {
-		res = PyObject_CallMethod(op, "__array_wrap__", "O", ret);
-		if (res == NULL) PyErr_Clear();
-		else if (res == Py_None) Py_DECREF(res);
-		else {
-			Py_DECREF(ret);
-			return res;
-		}
-	}
-	return PyArray_Return(ret);
+    Py_DECREF(otype);
+    if (ret==NULL) return NULL;
+    if (op->ob_type != ret->ob_type) {
+        res = PyObject_CallMethod(op, "__array_wrap__", "O", ret);
+        if (res == NULL) PyErr_Clear();
+        else if (res == Py_None) Py_DECREF(res);
+        else {
+            Py_DECREF(ret);
+            return res;
+        }
+    }
+    return PyArray_Return(ret);
 
 }
 
@@ -2954,35 +3072,35 @@
 static void
 _find_array_wrap(PyObject *args, PyObject **output_wrap, int nin, int nout)
 {
-	int nargs, i;
-	int np = 0;
-	double priority, maxpriority;
-	PyObject *with_wrap[NPY_MAXARGS], *wraps[NPY_MAXARGS];
-	PyObject *obj, *wrap = NULL;
+    int nargs, i;
+    int np = 0;
+    double priority, maxpriority;
+    PyObject *with_wrap[NPY_MAXARGS], *wraps[NPY_MAXARGS];
+    PyObject *obj, *wrap = NULL;
 
-	nargs = PyTuple_GET_SIZE(args);
-	for (i=0; i<nin; i++) {
-		obj = PyTuple_GET_ITEM(args, i);
-		if (PyArray_CheckExact(obj) ||	\
-		    PyArray_IsAnyScalar(obj))
-			continue;
-		wrap = PyObject_GetAttrString(obj, "__array_wrap__");
-		if (wrap) {
-			if (PyCallable_Check(wrap)) {
-				with_wrap[np] = obj;
-				wraps[np] = wrap;
-				++np;
-			}
-			else {
-				Py_DECREF(wrap);
-				wrap = NULL;
-			}
-		}
-		else {
-			PyErr_Clear();
-		}
-	}
-	if (np >= 2) {
+    nargs = PyTuple_GET_SIZE(args);
+    for (i=0; i<nin; i++) {
+        obj = PyTuple_GET_ITEM(args, i);
+        if (PyArray_CheckExact(obj) ||  \
+            PyArray_IsAnyScalar(obj))
+            continue;
+        wrap = PyObject_GetAttrString(obj, "__array_wrap__");
+        if (wrap) {
+            if (PyCallable_Check(wrap)) {
+                with_wrap[np] = obj;
+                wraps[np] = wrap;
+                ++np;
+            }
+            else {
+                Py_DECREF(wrap);
+                wrap = NULL;
+            }
+        }
+        else {
+            PyErr_Clear();
+        }
+    }
+    if (np >= 2) {
                 wrap = wraps[0];
                 maxpriority = PyArray_GetPriority(with_wrap[0],
                                                   PyArray_SUBTYPE_PRIORITY);
@@ -3045,47 +3163,47 @@
                 }
         }
 
-	Py_XDECREF(wrap);
-	return;
+    Py_XDECREF(wrap);
+    return;
 }
 
 static PyObject *
 ufunc_generic_call(PyUFuncObject *self, PyObject *args, PyObject *kwds)
 {
-	int i;
-	PyTupleObject *ret;
-	PyArrayObject *mps[NPY_MAXARGS];
-	PyObject *retobj[NPY_MAXARGS];
+    int i;
+    PyTupleObject *ret;
+    PyArrayObject *mps[NPY_MAXARGS];
+    PyObject *retobj[NPY_MAXARGS];
         PyObject *wraparr[NPY_MAXARGS];
-	PyObject *res;
+    PyObject *res;
         int errval;
 
-	/* Initialize all array objects to NULL to make cleanup easier
-	   if something goes wrong. */
-	for(i=0; i<self->nargs; i++) mps[i] = NULL;
+    /* Initialize all array objects to NULL to make cleanup easier
+       if something goes wrong. */
+    for(i=0; i<self->nargs; i++) mps[i] = NULL;
 
         errval = PyUFunc_GenericFunction(self, args, kwds, mps);
         if (errval < 0) {
-		for(i=0; i<self->nargs; i++) {
-			PyArray_XDECREF_ERR(mps[i]);
-		}
-		if (errval == -1)
-			return NULL;
-		else {
-			Py_INCREF(Py_NotImplemented);
-			return Py_NotImplemented;
-		}
+        for(i=0; i<self->nargs; i++) {
+            PyArray_XDECREF_ERR(mps[i]);
         }
+        if (errval == -1)
+            return NULL;
+        else {
+            Py_INCREF(Py_NotImplemented);
+            return Py_NotImplemented;
+        }
+        }
 
-	for(i=0; i<self->nin; i++) Py_DECREF(mps[i]);
+    for(i=0; i<self->nin; i++) Py_DECREF(mps[i]);
 
 
-	/*  Use __array_wrap__ on all outputs
-	        if present on one of the input arguments.
-	    If present for multiple inputs:
-	        use __array_wrap__ of input object with largest
-		__array_priority__ (default = 0.0)
-	 */
+    /*  Use __array_wrap__ on all outputs
+            if present on one of the input arguments.
+        If present for multiple inputs:
+            use __array_wrap__ of input object with largest
+        __array_priority__ (default = 0.0)
+     */
 
         /* Exception:  we should not wrap outputs for items already
            passed in as output-arguments.  These items should either
@@ -3099,90 +3217,90 @@
         */
         _find_array_wrap(args, wraparr, self->nin, self->nout);
 
-	/* wrap outputs */
-	for (i=0; i<self->nout; i++) {
-		int j=self->nin+i;
+    /* wrap outputs */
+    for (i=0; i<self->nout; i++) {
+        int j=self->nin+i;
                 PyObject *wrap;
-		/* check to see if any UPDATEIFCOPY flags are set
-		   which meant that a temporary output was generated
-		*/
-		if (mps[j]->flags & UPDATEIFCOPY) {
-			PyObject *old = mps[j]->base;
-			Py_INCREF(old);   /* we want to hang on to this */
-			Py_DECREF(mps[j]); /* should trigger the copy
-					      back into old */
-			mps[j] = (PyArrayObject *)old;
-		}
+        /* check to see if any UPDATEIFCOPY flags are set
+           which meant that a temporary output was generated
+        */
+        if (mps[j]->flags & UPDATEIFCOPY) {
+            PyObject *old = mps[j]->base;
+            Py_INCREF(old);   /* we want to hang on to this */
+            Py_DECREF(mps[j]); /* should trigger the copy
+                          back into old */
+            mps[j] = (PyArrayObject *)old;
+        }
                 wrap = wraparr[i];
-		if (wrap != NULL) {
+        if (wrap != NULL) {
                         if (wrap == Py_None) {
                                 Py_DECREF(wrap);
                                 retobj[i] = (PyObject *)mps[j];
                                 continue;
                         }
-			res = PyObject_CallFunction(wrap, "O(OOi)",
-						    mps[j], self, args, i);
-			if (res == NULL && \
-			    PyErr_ExceptionMatches(PyExc_TypeError)) {
-				PyErr_Clear();
-				res = PyObject_CallFunctionObjArgs(wrap,
-								   mps[j],
-								   NULL);
-			}
-			Py_DECREF(wrap);
-			if (res == NULL) goto fail;
-			else if (res == Py_None) Py_DECREF(res);
-			else {
-				Py_DECREF(mps[j]);
-				retobj[i] = res;
-				continue;
-			}
-		}
+            res = PyObject_CallFunction(wrap, "O(OOi)",
+                            mps[j], self, args, i);
+            if (res == NULL && \
+                PyErr_ExceptionMatches(PyExc_TypeError)) {
+                PyErr_Clear();
+                res = PyObject_CallFunctionObjArgs(wrap,
+                                   mps[j],
+                                   NULL);
+            }
+            Py_DECREF(wrap);
+            if (res == NULL) goto fail;
+            else if (res == Py_None) Py_DECREF(res);
+            else {
+                Py_DECREF(mps[j]);
+                retobj[i] = res;
+                continue;
+            }
+        }
                 /* default behavior */
-		retobj[i] = PyArray_Return(mps[j]);
-	}
+        retobj[i] = PyArray_Return(mps[j]);
+    }
 
-	if (self->nout == 1) {
-		return retobj[0];
-	} else {
-		ret = (PyTupleObject *)PyTuple_New(self->nout);
-		for(i=0; i<self->nout; i++) {
-			PyTuple_SET_ITEM(ret, i, retobj[i]);
-		}
-		return (PyObject *)ret;
-	}
+    if (self->nout == 1) {
+        return retobj[0];
+    } else {
+        ret = (PyTupleObject *)PyTuple_New(self->nout);
+        for(i=0; i<self->nout; i++) {
+            PyTuple_SET_ITEM(ret, i, retobj[i]);
+        }
+        return (PyObject *)ret;
+    }
  fail:
-	for(i=self->nin; i<self->nargs; i++) Py_XDECREF(mps[i]);
-	return NULL;
+    for(i=self->nin; i<self->nargs; i++) Py_XDECREF(mps[i]);
+    return NULL;
 }
 
 static PyObject *
 ufunc_geterr(PyObject *dummy, PyObject *args)
 {
-	PyObject *thedict;
-	PyObject *res;
+    PyObject *thedict;
+    PyObject *res;
 
-	if (!PyArg_ParseTuple(args, "")) return NULL;
+    if (!PyArg_ParseTuple(args, "")) return NULL;
 
-	if (PyUFunc_PYVALS_NAME == NULL) {
-		PyUFunc_PYVALS_NAME = PyString_InternFromString(UFUNC_PYVALS_NAME);
-	}
-	thedict = PyThreadState_GetDict();
-	if (thedict == NULL) {
-		thedict = PyEval_GetBuiltins();
-	}
-	res = PyDict_GetItem(thedict, PyUFunc_PYVALS_NAME);
-	if (res != NULL) {
-		Py_INCREF(res);
-		return res;
-	}
-	/* Construct list of defaults */
-	res = PyList_New(3);
-	if (res == NULL) return NULL;
-	PyList_SET_ITEM(res, 0, PyInt_FromLong(PyArray_BUFSIZE));
-	PyList_SET_ITEM(res, 1, PyInt_FromLong(UFUNC_ERR_DEFAULT));
-	PyList_SET_ITEM(res, 2, Py_None); Py_INCREF(Py_None);
-	return res;
+    if (PyUFunc_PYVALS_NAME == NULL) {
+        PyUFunc_PYVALS_NAME = PyString_InternFromString(UFUNC_PYVALS_NAME);
+    }
+    thedict = PyThreadState_GetDict();
+    if (thedict == NULL) {
+        thedict = PyEval_GetBuiltins();
+    }
+    res = PyDict_GetItem(thedict, PyUFunc_PYVALS_NAME);
+    if (res != NULL) {
+        Py_INCREF(res);
+        return res;
+    }
+    /* Construct list of defaults */
+    res = PyList_New(3);
+    if (res == NULL) return NULL;
+    PyList_SET_ITEM(res, 0, PyInt_FromLong(PyArray_BUFSIZE));
+    PyList_SET_ITEM(res, 1, PyInt_FromLong(UFUNC_ERR_DEFAULT));
+    PyList_SET_ITEM(res, 2, Py_None); Py_INCREF(Py_None);
+    return res;
 }
 
 #if USE_USE_DEFAULTS==1
@@ -3195,57 +3313,57 @@
 static int
 ufunc_update_use_defaults(void)
 {
-	PyObject *errobj;
-	int errmask, bufsize;
-	int res;
+    PyObject *errobj;
+    int errmask, bufsize;
+    int res;
 
-	PyUFunc_NUM_NODEFAULTS += 1;
+    PyUFunc_NUM_NODEFAULTS += 1;
         res = PyUFunc_GetPyValues("test", &bufsize, &errmask,
-				  &errobj);
-	PyUFunc_NUM_NODEFAULTS -= 1;
+                  &errobj);
+    PyUFunc_NUM_NODEFAULTS -= 1;
 
-	if (res < 0) return -1;
+    if (res < 0) return -1;
 
-	if ((errmask != UFUNC_ERR_DEFAULT) ||		\
-	    (bufsize != PyArray_BUFSIZE) ||		\
-	    (PyTuple_GET_ITEM(errobj, 1) != Py_None)) {
-		PyUFunc_NUM_NODEFAULTS += 1;
-	}
-	else if (PyUFunc_NUM_NODEFAULTS > 0) {
-		PyUFunc_NUM_NODEFAULTS -= 1;
-	}
-	return 0;
+    if ((errmask != UFUNC_ERR_DEFAULT) ||       \
+        (bufsize != PyArray_BUFSIZE) ||     \
+        (PyTuple_GET_ITEM(errobj, 1) != Py_None)) {
+        PyUFunc_NUM_NODEFAULTS += 1;
+    }
+    else if (PyUFunc_NUM_NODEFAULTS > 0) {
+        PyUFunc_NUM_NODEFAULTS -= 1;
+    }
+    return 0;
 }
 #endif
 
 static PyObject *
 ufunc_seterr(PyObject *dummy, PyObject *args)
 {
-	PyObject *thedict;
-	int res;
-	PyObject *val;
-	static char *msg = "Error object must be a list of length 3";
+    PyObject *thedict;
+    int res;
+    PyObject *val;
+    static char *msg = "Error object must be a list of length 3";
 
-	if (!PyArg_ParseTuple(args, "O", &val)) return NULL;
+    if (!PyArg_ParseTuple(args, "O", &val)) return NULL;
 
-	if (!PyList_CheckExact(val) || PyList_GET_SIZE(val) != 3) {
-		PyErr_SetString(PyExc_ValueError, msg);
-		return NULL;
-	}
-	if (PyUFunc_PYVALS_NAME == NULL) {
-		PyUFunc_PYVALS_NAME = PyString_InternFromString(UFUNC_PYVALS_NAME);
-	}
-	thedict = PyThreadState_GetDict();
-	if (thedict == NULL) {
-		thedict = PyEval_GetBuiltins();
-	}
-	res = PyDict_SetItem(thedict, PyUFunc_PYVALS_NAME, val);
-	if (res < 0) return NULL;
+    if (!PyList_CheckExact(val) || PyList_GET_SIZE(val) != 3) {
+        PyErr_SetString(PyExc_ValueError, msg);
+        return NULL;
+    }
+    if (PyUFunc_PYVALS_NAME == NULL) {
+        PyUFunc_PYVALS_NAME = PyString_InternFromString(UFUNC_PYVALS_NAME);
+    }
+    thedict = PyThreadState_GetDict();
+    if (thedict == NULL) {
+        thedict = PyEval_GetBuiltins();
+    }
+    res = PyDict_SetItem(thedict, PyUFunc_PYVALS_NAME, val);
+    if (res < 0) return NULL;
 #if USE_USE_DEFAULTS==1
-	if (ufunc_update_use_defaults() < 0) return NULL;
+    if (ufunc_update_use_defaults() < 0) return NULL;
 #endif
-	Py_INCREF(Py_None);
-	return Py_None;
+    Py_INCREF(Py_None);
+    return Py_None;
 }
 
 
@@ -3265,7 +3383,7 @@
         PyUFuncObject *self;
         char *fname, *str;
         Py_ssize_t fname_len=-1;
-	int offset[2];
+    int offset[2];
 
         if (!PyArg_ParseTuple(args, "Oii", &function, &nin, &nout)) return NULL;
 
@@ -3278,15 +3396,15 @@
         if (self == NULL) return NULL;
         PyObject_Init((PyObject *)self, &PyUFunc_Type);
 
-	self->userloops = NULL;
-	self->nin = nin;
-	self->nout = nout;
-	self->nargs = nin+nout;
-	self->identity = PyUFunc_None;
-	self->functions = pyfunc_functions;
+    self->userloops = NULL;
+    self->nin = nin;
+    self->nout = nout;
+    self->nargs = nin+nout;
+    self->identity = PyUFunc_None;
+    self->functions = pyfunc_functions;
 
-	self->ntypes = 1;
-	self->check_return = 0;
+    self->ntypes = 1;
+    self->check_return = 0;
 
         pyname = PyObject_GetAttrString(function, "__name__");
         if (pyname)
@@ -3301,29 +3419,29 @@
 
 
 
-	/* self->ptr holds a pointer for enough memory for
-	   self->data[0] (fdata)
-	   self->data
-	   self->name
-	   self->types
+    /* self->ptr holds a pointer for enough memory for
+       self->data[0] (fdata)
+       self->data
+       self->name
+       self->types
 
-	   To be safest, all of these need their memory aligned on void * pointers
-	   Therefore, we may need to allocate extra space.
-	*/
-	offset[0] = sizeof(PyUFunc_PyFuncData);
-	i = (sizeof(PyUFunc_PyFuncData) % sizeof(void *));
-	if (i) offset[0] += (sizeof(void *) - i);
-	offset[1] = self->nargs;
-	i = (self->nargs % sizeof(void *));
-	if (i) offset[1] += (sizeof(void *)-i);
+       To be safest, all of these need their memory aligned on void * pointers
+       Therefore, we may need to allocate extra space.
+    */
+    offset[0] = sizeof(PyUFunc_PyFuncData);
+    i = (sizeof(PyUFunc_PyFuncData) % sizeof(void *));
+    if (i) offset[0] += (sizeof(void *) - i);
+    offset[1] = self->nargs;
+    i = (self->nargs % sizeof(void *));
+    if (i) offset[1] += (sizeof(void *)-i);
 
         self->ptr = _pya_malloc(offset[0] + offset[1] + sizeof(void *) + \
-			   (fname_len+14));
+               (fname_len+14));
 
-	if (self->ptr == NULL) return PyErr_NoMemory();
+    if (self->ptr == NULL) return PyErr_NoMemory();
         Py_INCREF(function);
         self->obj = function;
-	fdata = (PyUFunc_PyFuncData *)(self->ptr);
+    fdata = (PyUFunc_PyFuncData *)(self->ptr);
         fdata->nin = nin;
         fdata->nout = nout;
         fdata->callable = function;
@@ -3331,7 +3449,7 @@
         self->data = (void **)(((char *)self->ptr) + offset[0]);
         self->data[0] = (void *)fdata;
 
-	self->types = (char *)self->data + sizeof(void *);
+    self->types = (char *)self->data + sizeof(void *);
         for (i=0; i<self->nargs; i++) self->types[i] = PyArray_OBJECT;
 
         str = self->types + offset[1];
@@ -3344,70 +3462,70 @@
         self->doc = "dynamic ufunc based on a python function";
 
 
-	return (PyObject *)self;
+    return (PyObject *)self;
 }
 
 /*UFUNC_API*/
 static int
 PyUFunc_ReplaceLoopBySignature(PyUFuncObject *func, 
-			       PyUFuncGenericFunction newfunc, 
-			       int *signature, 
-			       PyUFuncGenericFunction *oldfunc)
+                   PyUFuncGenericFunction newfunc, 
+                   int *signature, 
+                   PyUFuncGenericFunction *oldfunc)
 {
-	int i,j;
+    int i,j;
         int res = -1;
-	/* Find the location of the matching signature */
-	for (i=0; i<func->ntypes; i++) {
-		for (j=0; j<func->nargs; j++) {
-			if (signature[j] != func->types[i*func->nargs+j])
-				break;
-		}
-		if (j < func->nargs) continue;
-		
-		if (oldfunc != NULL) {
-			*oldfunc = func->functions[i];
-		}
-		func->functions[i] = newfunc;
+    /* Find the location of the matching signature */
+    for (i=0; i<func->ntypes; i++) {
+        for (j=0; j<func->nargs; j++) {
+            if (signature[j] != func->types[i*func->nargs+j])
+                break;
+        }
+        if (j < func->nargs) continue;
+        
+        if (oldfunc != NULL) {
+            *oldfunc = func->functions[i];
+        }
+        func->functions[i] = newfunc;
                 res = 0;
                 break;
-	}
-	return res;
+    }
+    return res;
 }
 
 /*UFUNC_API*/
 static PyObject *
 PyUFunc_FromFuncAndData(PyUFuncGenericFunction *func, void **data,
-			char *types, int ntypes,
-			int nin, int nout, int identity,
-			char *name, char *doc, int check_return)
+            char *types, int ntypes,
+            int nin, int nout, int identity,
+            char *name, char *doc, int check_return)
 {
-	PyUFuncObject *self;
+    PyUFuncObject *self;
 
         self = _pya_malloc(sizeof(PyUFuncObject));
         if (self == NULL) return NULL;
         PyObject_Init((PyObject *)self, &PyUFunc_Type);
 
-	self->nin = nin;
-	self->nout = nout;
-	self->nargs = nin+nout;
-	self->identity = identity;
+    self->nin = nin;
+    self->nout = nout;
+    self->nargs = nin+nout;
+    self->identity = identity;
 
-	self->functions = func;
-	self->data = data;
-	self->types = types;
-	self->ntypes = ntypes;
-	self->check_return = check_return;
+    self->functions = func;
+    self->data = data;
+    self->types = types;
+    self->ntypes = ntypes;
+    self->check_return = check_return;
         self->ptr = NULL;
         self->obj = NULL;
-	self->userloops=NULL;
+    self->userloops=NULL;
 
-	if (name == NULL) self->name = "?";
-	else self->name = name;
+    if (name == NULL) self->name = "?";
+    else self->name = name;
 
         if (doc == NULL) self->doc = "NULL";
-	else self->doc = doc;
+    else self->doc = doc;
 
-	return (PyObject *)self;
+    return (PyObject *)self;
 }
 
 /* This is the first-part of the CObject structure.
@@ -3460,30 +3578,30 @@
 /*UFUNC_API*/
 static int
 PyUFunc_RegisterLoopForType(PyUFuncObject *ufunc,
-			    int usertype,
-			    PyUFuncGenericFunction function,
-			    int *arg_types,
-			    void *data)
+                int usertype,
+                PyUFuncGenericFunction function,
+                int *arg_types,
+                void *data)
 {
-	PyArray_Descr *descr;
+    PyArray_Descr *descr;
         PyUFunc_Loop1d *funcdata;
-    	PyObject *key, *cobj;
-	int i;
+        PyObject *key, *cobj;
+    int i;
         int *newtypes=NULL;
 
-	descr=PyArray_DescrFromType(usertype);
-	if ((usertype < PyArray_USERDEF) || (descr==NULL)) {
-		PyErr_SetString(PyExc_TypeError,
-				"unknown user-defined type");
-		return -1;
-	}
-	Py_DECREF(descr);
+    descr=PyArray_DescrFromType(usertype);
+    if ((usertype < PyArray_USERDEF) || (descr==NULL)) {
+        PyErr_SetString(PyExc_TypeError,
+                "unknown user-defined type");
+        return -1;
+    }
+    Py_DECREF(descr);
 
-	if (ufunc->userloops == NULL) {
-		ufunc->userloops = PyDict_New();
-	}
-	key = PyInt_FromLong((long) usertype);
-	if (key == NULL) return -1;
+    if (ufunc->userloops == NULL) {
+        ufunc->userloops = PyDict_New();
+    }
+    key = PyInt_FromLong((long) usertype);
+    if (key == NULL) return -1;
         funcdata = _pya_malloc(sizeof(PyUFunc_Loop1d));
         if (funcdata == NULL) goto fail;
         newtypes = _pya_malloc(sizeof(int)*ufunc->nargs);
@@ -3572,7 +3690,7 @@
 ufunc_dealloc(PyUFuncObject *self)
 {
         if (self->ptr) _pya_free(self->ptr);
-	Py_XDECREF(self->userloops);
+    Py_XDECREF(self->userloops);
         Py_XDECREF(self->obj);
         _pya_free(self);
 }
@@ -3580,11 +3698,11 @@
 static PyObject *
 ufunc_repr(PyUFuncObject *self)
 {
-	char buf[100];
+    char buf[100];
 
-	sprintf(buf, "<ufunc '%.50s'>", self->name);
+    sprintf(buf, "<ufunc '%.50s'>", self->name);
 
-	return PyString_FromString(buf);
+    return PyString_FromString(buf);
 }
 
 
@@ -3599,72 +3717,72 @@
 static PyObject *
 ufunc_outer(PyUFuncObject *self, PyObject *args, PyObject *kwds)
 {
-	int i;
-	PyObject *ret;
-	PyArrayObject *ap1=NULL, *ap2=NULL, *ap_new=NULL;
-	PyObject *new_args, *tmp;
-	PyObject *shape1, *shape2, *newshape;
+    int i;
+    PyObject *ret;
+    PyArrayObject *ap1=NULL, *ap2=NULL, *ap_new=NULL;
+    PyObject *new_args, *tmp;
+    PyObject *shape1, *shape2, *newshape;
 
-	if(self->nin != 2) {
-		PyErr_SetString(PyExc_ValueError,
-				"outer product only supported "\
-				"for binary functions");
-		return NULL;
-	}
+    if(self->nin != 2) {
+        PyErr_SetString(PyExc_ValueError,
+                "outer product only supported "\
+                "for binary functions");
+        return NULL;
+    }
 
-	if (PySequence_Length(args) != 2) {
-		PyErr_SetString(PyExc_TypeError,
-				"exactly two arguments expected");
-		return NULL;
-	}
+    if (PySequence_Length(args) != 2) {
+        PyErr_SetString(PyExc_TypeError,
+                "exactly two arguments expected");
+        return NULL;
+    }
 
-	tmp = PySequence_GetItem(args, 0);
-	if (tmp == NULL) return NULL;
-	ap1 = (PyArrayObject *)					\
-		PyArray_FromObject(tmp, PyArray_NOTYPE, 0, 0);
-	Py_DECREF(tmp);
-	if (ap1 == NULL) return NULL;
+    tmp = PySequence_GetItem(args, 0);
+    if (tmp == NULL) return NULL;
+    ap1 = (PyArrayObject *)                 \
+        PyArray_FromObject(tmp, PyArray_NOTYPE, 0, 0);
+    Py_DECREF(tmp);
+    if (ap1 == NULL) return NULL;
 
-	tmp = PySequence_GetItem(args, 1);
-	if (tmp == NULL) return NULL;
-	ap2 = (PyArrayObject *)PyArray_FromObject(tmp, PyArray_NOTYPE, 0, 0);
-	Py_DECREF(tmp);
-	if (ap2 == NULL) {Py_DECREF(ap1); return NULL;}
+    tmp = PySequence_GetItem(args, 1);
+    if (tmp == NULL) return NULL;
+    ap2 = (PyArrayObject *)PyArray_FromObject(tmp, PyArray_NOTYPE, 0, 0);
+    Py_DECREF(tmp);
+    if (ap2 == NULL) {Py_DECREF(ap1); return NULL;}
 
-	/* Construct new shape tuple */
-	shape1 = PyTuple_New(ap1->nd);
-	if (shape1 == NULL) goto fail;
-	for (i=0; i<ap1->nd; i++)
-		PyTuple_SET_ITEM(shape1, i,
-				 PyLong_FromLongLong((longlong)ap1->	\
-						     dimensions[i]));
+    /* Construct new shape tuple */
+    shape1 = PyTuple_New(ap1->nd);
+    if (shape1 == NULL) goto fail;
+    for (i=0; i<ap1->nd; i++)
+        PyTuple_SET_ITEM(shape1, i,
+                 PyLong_FromLongLong((longlong)ap1->    \
+                             dimensions[i]));
 
-	shape2 = PyTuple_New(ap2->nd);
-	for (i=0; i<ap2->nd; i++)
-		PyTuple_SET_ITEM(shape2, i, PyInt_FromLong((long) 1));
-	if (shape2 == NULL) {Py_DECREF(shape1); goto fail;}
-	newshape = PyNumber_Add(shape1, shape2);
-	Py_DECREF(shape1);
-	Py_DECREF(shape2);
-	if (newshape == NULL) goto fail;
+    shape2 = PyTuple_New(ap2->nd);
+    for (i=0; i<ap2->nd; i++)
+        PyTuple_SET_ITEM(shape2, i, PyInt_FromLong((long) 1));
+    if (shape2 == NULL) {Py_DECREF(shape1); goto fail;}
+    newshape = PyNumber_Add(shape1, shape2);
+    Py_DECREF(shape1);
+    Py_DECREF(shape2);
+    if (newshape == NULL) goto fail;
 
-	ap_new = (PyArrayObject *)PyArray_Reshape(ap1, newshape);
-	Py_DECREF(newshape);
-	if (ap_new == NULL) goto fail;
+    ap_new = (PyArrayObject *)PyArray_Reshape(ap1, newshape);
+    Py_DECREF(newshape);
+    if (ap_new == NULL) goto fail;
 
-	new_args = Py_BuildValue("(OO)", ap_new, ap2);
-	Py_DECREF(ap1);
-	Py_DECREF(ap2);
-	Py_DECREF(ap_new);
-	ret = ufunc_generic_call(self, new_args, kwds);
-	Py_DECREF(new_args);
-	return ret;
+    new_args = Py_BuildValue("(OO)", ap_new, ap2);
+    Py_DECREF(ap1);
+    Py_DECREF(ap2);
+    Py_DECREF(ap_new);
+    ret = ufunc_generic_call(self, new_args, kwds);
+    Py_DECREF(new_args);
+    return ret;
 
  fail:
-	Py_XDECREF(ap1);
-	Py_XDECREF(ap2);
-	Py_XDECREF(ap_new);
-	return NULL;
+    Py_XDECREF(ap1);
+    Py_XDECREF(ap2);
+    Py_XDECREF(ap_new);
+    return NULL;
 }
 
 
@@ -3672,31 +3790,31 @@
 ufunc_reduce(PyUFuncObject *self, PyObject *args, PyObject *kwds)
 {
 
-	return PyUFunc_GenericReduction(self, args, kwds, UFUNC_REDUCE);
+    return PyUFunc_GenericReduction(self, args, kwds, UFUNC_REDUCE);
 }
 
 static PyObject *
 ufunc_accumulate(PyUFuncObject *self, PyObject *args, PyObject *kwds)
 {
 
-	return PyUFunc_GenericReduction(self, args, kwds, UFUNC_ACCUMULATE);
+    return PyUFunc_GenericReduction(self, args, kwds, UFUNC_ACCUMULATE);
 }
 
 static PyObject *
 ufunc_reduceat(PyUFuncObject *self, PyObject *args, PyObject *kwds)
 {
-	return PyUFunc_GenericReduction(self, args, kwds, UFUNC_REDUCEAT);
+    return PyUFunc_GenericReduction(self, args, kwds, UFUNC_REDUCEAT);
 }
 
 
 static struct PyMethodDef ufunc_methods[] = {
-	{"reduce",  (PyCFunction)ufunc_reduce, METH_VARARGS | METH_KEYWORDS},
-	{"accumulate",  (PyCFunction)ufunc_accumulate,
-	 METH_VARARGS | METH_KEYWORDS},
-	{"reduceat",  (PyCFunction)ufunc_reduceat,
-	 METH_VARARGS | METH_KEYWORDS},
-	{"outer", (PyCFunction)ufunc_outer, METH_VARARGS | METH_KEYWORDS},
-	{NULL,		NULL}		/* sentinel */
+    {"reduce",  (PyCFunction)ufunc_reduce, METH_VARARGS | METH_KEYWORDS},
+    {"accumulate",  (PyCFunction)ufunc_accumulate,
+     METH_VARARGS | METH_KEYWORDS},
+    {"reduceat",  (PyCFunction)ufunc_reduceat,
+     METH_VARARGS | METH_KEYWORDS},
+    {"outer", (PyCFunction)ufunc_outer, METH_VARARGS | METH_KEYWORDS},
+    {NULL,      NULL}       /* sentinel */
 };
 
 
@@ -3707,184 +3825,184 @@
 static PyObject *
 _makeargs(int num, char *ltr)
 {
-	PyObject *str;
-	int i;
-	switch (num) {
-	case 0:
-		return PyString_FromString("");
-	case 1:
-		return PyString_FromString(ltr);
-	}
-	str = PyString_FromFormat("%s1,%s2", ltr, ltr);
-	for(i = 3; i <= num; ++i) {
-		PyString_ConcatAndDel(&str, PyString_FromFormat(",%s%d", ltr, i));
-	}
-	return str;
+    PyObject *str;
+    int i;
+    switch (num) {
+    case 0:
+        return PyString_FromString("");
+    case 1:
+        return PyString_FromString(ltr);
+    }
+    str = PyString_FromFormat("%s1,%s2", ltr, ltr);
+    for(i = 3; i <= num; ++i) {
+        PyString_ConcatAndDel(&str, PyString_FromFormat(",%s%d", ltr, i));
+    }
+    return str;
 }
 
 static char
 _typecharfromnum(int num) {
-	PyArray_Descr *descr;
-	char ret;
+    PyArray_Descr *descr;
+    char ret;
 
-	descr = PyArray_DescrFromType(num);
-	ret = descr->type;
-	Py_DECREF(descr);
-	return ret;
+    descr = PyArray_DescrFromType(num);
+    ret = descr->type;
+    Py_DECREF(descr);
+    return ret;
 }
 
 static PyObject *
 ufunc_get_doc(PyUFuncObject *self)
 {
-	/* Put docstring first or FindMethod finds it...*/
-	/* could so some introspection on name and nin + nout */
-	/* to automate the first part of it */
-	/* the doc string shouldn't need the calling convention */
-	/* construct
-	   y1,y2,,... = name(x1,x2,...) __doc__
-	*/
-	PyObject *outargs, *inargs, *doc;
-	outargs = _makeargs(self->nout, "y");
-	inargs = _makeargs(self->nin, "x");
-	doc = PyString_FromFormat("%s = %s(%s) %s",
-				  PyString_AS_STRING(outargs),
-				  self->name,
-				  PyString_AS_STRING(inargs),
-				  self->doc);
-	Py_DECREF(outargs);
-	Py_DECREF(inargs);
-	return doc;
+    /* Put docstring first or FindMethod finds it...*/
+    /* could so some introspection on name and nin + nout */
+    /* to automate the first part of it */
+    /* the doc string shouldn't need the calling convention */
+    /* construct
+       y1,y2,,... = name(x1,x2,...) __doc__
+    */
+    PyObject *outargs, *inargs, *doc;
+    outargs = _makeargs(self->nout, "y");
+    inargs = _makeargs(self->nin, "x");
+    doc = PyString_FromFormat("%s = %s(%s) %s",
+                  PyString_AS_STRING(outargs),
+                  self->name,
+                  PyString_AS_STRING(inargs),
+                  self->doc);
+    Py_DECREF(outargs);
+    Py_DECREF(inargs);
+    return doc;
 }
 
 static PyObject *
 ufunc_get_nin(PyUFuncObject *self)
 {
-	return PyInt_FromLong(self->nin);
+    return PyInt_FromLong(self->nin);
 }
 
 static PyObject *
 ufunc_get_nout(PyUFuncObject *self)
 {
-	return PyInt_FromLong(self->nout);
+    return PyInt_FromLong(self->nout);
 }
 
 static PyObject *
 ufunc_get_nargs(PyUFuncObject *self)
 {
-	return PyInt_FromLong(self->nargs);
+    return PyInt_FromLong(self->nargs);
 }
 
 static PyObject *
 ufunc_get_ntypes(PyUFuncObject *self)
 {
-	return PyInt_FromLong(self->ntypes);
+    return PyInt_FromLong(self->ntypes);
 }
 
 static PyObject *
 ufunc_get_types(PyUFuncObject *self)
 {
-	/* return a list with types grouped
-	   input->output */
-	PyObject *list;
-	PyObject *str;
-	int k, j, n, nt=self->ntypes;
-	int ni = self->nin;
-	int no = self->nout;
-	char *t;
-	list = PyList_New(nt);
-	if (list == NULL) return NULL;
-	t = _pya_malloc(no+ni+2);
-	n = 0;
-	for (k=0; k<nt; k++) {
-		for (j=0; j<ni; j++) {
-			t[j] = _typecharfromnum(self->types[n]);
-			n++;
-		}
-		t[ni] = '-';
-		t[ni+1] = '>';
-		for (j=0; j<no; j++) {
-			t[ni+2+j] =					\
-				_typecharfromnum(self->types[n]);
-			n++;
-		}
-		str = PyString_FromStringAndSize(t, no+ni+2);
-		PyList_SET_ITEM(list, k, str);
-	}
-	_pya_free(t);
-	return list;
+    /* return a list with types grouped
+       input->output */
+    PyObject *list;
+    PyObject *str;
+    int k, j, n, nt=self->ntypes;
+    int ni = self->nin;
+    int no = self->nout;
+    char *t;
+    list = PyList_New(nt);
+    if (list == NULL) return NULL;
+    t = _pya_malloc(no+ni+2);
+    n = 0;
+    for (k=0; k<nt; k++) {
+        for (j=0; j<ni; j++) {
+            t[j] = _typecharfromnum(self->types[n]);
+            n++;
+        }
+        t[ni] = '-';
+        t[ni+1] = '>';
+        for (j=0; j<no; j++) {
+            t[ni+2+j] =                 \
+                _typecharfromnum(self->types[n]);
+            n++;
+        }
+        str = PyString_FromStringAndSize(t, no+ni+2);
+        PyList_SET_ITEM(list, k, str);
+    }
+    _pya_free(t);
+    return list;
 
 }
 
 static PyObject *
 ufunc_get_name(PyUFuncObject *self)
 {
-	return PyString_FromString(self->name);
+    return PyString_FromString(self->name);
 }
 
 static PyObject *
 ufunc_get_identity(PyUFuncObject *self)
 {
-	switch(self->identity) {
-	case PyUFunc_One:
-		return PyInt_FromLong(1);
-	case PyUFunc_Zero:
-		return PyInt_FromLong(0);
-	}
-	return Py_None;
+    switch(self->identity) {
+    case PyUFunc_One:
+        return PyInt_FromLong(1);
+    case PyUFunc_Zero:
+        return PyInt_FromLong(0);
+    }
+    return Py_None;
 }
 
 
 #undef _typecharfromnum
 
 static char Ufunctype__doc__[] =
-	"Optimized functions make it possible to implement arithmetic "\
-	"with arrays efficiently";
+    "Optimized functions make it possible to implement arithmetic "\
+    "with arrays efficiently";
 
 static PyGetSetDef ufunc_getset[] = {
-	{"__doc__",  (getter)ufunc_get_doc,      NULL, "documentation string"},
-	{"nin",      (getter)ufunc_get_nin,      NULL, "number of inputs"},
-	{"nout",     (getter)ufunc_get_nout,     NULL, "number of outputs"},
-	{"nargs",    (getter)ufunc_get_nargs,    NULL, "number of arguments"},
-	{"ntypes",   (getter)ufunc_get_ntypes,   NULL, "number of types"},
-	{"types",    (getter)ufunc_get_types,    NULL, "return a list with types grouped input->output"},
-	{"__name__", (getter)ufunc_get_name,     NULL, "function name"},
-	{"identity", (getter)ufunc_get_identity, NULL, "identity value"},
-	{NULL, NULL, NULL, NULL},  /* Sentinel */
+    {"__doc__",  (getter)ufunc_get_doc,      NULL, "documentation string"},
+    {"nin",      (getter)ufunc_get_nin,      NULL, "number of inputs"},
+    {"nout",     (getter)ufunc_get_nout,     NULL, "number of outputs"},
+    {"nargs",    (getter)ufunc_get_nargs,    NULL, "number of arguments"},
+    {"ntypes",   (getter)ufunc_get_ntypes,   NULL, "number of types"},
+    {"types",    (getter)ufunc_get_types,    NULL, "return a list with types grouped input->output"},
+    {"__name__", (getter)ufunc_get_name,     NULL, "function name"},
+    {"identity", (getter)ufunc_get_identity, NULL, "identity value"},
+    {NULL, NULL, NULL, NULL},  /* Sentinel */
 };
 
 static PyTypeObject PyUFunc_Type = {
-	PyObject_HEAD_INIT(0)
-	0,				/*ob_size*/
-	"numpy.ufunc",			/*tp_name*/
-	sizeof(PyUFuncObject),		/*tp_basicsize*/
-	0,				/*tp_itemsize*/
-	/* methods */
-	(destructor)ufunc_dealloc,	/*tp_dealloc*/
-	(printfunc)0,		        /*tp_print*/
-	(getattrfunc)0,         	/*tp_getattr*/
-	(setattrfunc)0,	                /*tp_setattr*/
-	(cmpfunc)0,	          	/*tp_compare*/
-	(reprfunc)ufunc_repr,		/*tp_repr*/
-	0,			       /*tp_as_number*/
-	0,		               /*tp_as_sequence*/
-	0,		               /*tp_as_mapping*/
-	(hashfunc)0,		       /*tp_hash*/
-	(ternaryfunc)ufunc_generic_call, /*tp_call*/
-	(reprfunc)ufunc_repr,	       /*tp_str*/
-        0,	          	       /* tp_getattro */
-        0,			       /* tp_setattro */
-        0,			       /* tp_as_buffer */
+    PyObject_HEAD_INIT(0)
+    0,              /*ob_size*/
+    "numpy.ufunc",          /*tp_name*/
+    sizeof(PyUFuncObject),      /*tp_basicsize*/
+    0,              /*tp_itemsize*/
+    /* methods */
+    (destructor)ufunc_dealloc,  /*tp_dealloc*/
+    (printfunc)0,               /*tp_print*/
+    (getattrfunc)0,             /*tp_getattr*/
+    (setattrfunc)0,                 /*tp_setattr*/
+    (cmpfunc)0,             /*tp_compare*/
+    (reprfunc)ufunc_repr,       /*tp_repr*/
+    0,                 /*tp_as_number*/
+    0,                     /*tp_as_sequence*/
+    0,                     /*tp_as_mapping*/
+    (hashfunc)0,               /*tp_hash*/
+    (ternaryfunc)ufunc_generic_call, /*tp_call*/
+    (reprfunc)ufunc_repr,          /*tp_str*/
+        0,                     /* tp_getattro */
+        0,                 /* tp_setattro */
+        0,                 /* tp_as_buffer */
         Py_TPFLAGS_DEFAULT,            /* tp_flags */
-	Ufunctype__doc__,              /* tp_doc */
-        0,	                       /* tp_traverse */
-        0,			       /* tp_clear */
-        0,			       /* tp_richcompare */
-        0,			       /* tp_weaklistoffset */
-        0,	                       /* tp_iter */
-        0,		               /* tp_iternext */
-	ufunc_methods,                 /* tp_methods */
-        0,		               /* tp_members */
-        ufunc_getset,		       /* tp_getset */
+    Ufunctype__doc__,              /* tp_doc */
+        0,                         /* tp_traverse */
+        0,                 /* tp_clear */
+        0,                 /* tp_richcompare */
+        0,                 /* tp_weaklistoffset */
+        0,                         /* tp_iter */
+        0,                     /* tp_iternext */
+    ufunc_methods,                 /* tp_methods */
+        0,                     /* tp_members */
+        ufunc_getset,              /* tp_getset */
 };
 
 /* End of code for ufunc objects */

Added: branches/multicore/numpy/core/src/ufuncthreadapi.c
===================================================================
--- branches/multicore/numpy/core/src/ufuncthreadapi.c	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/src/ufuncthreadapi.c	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,95 @@
+#include <Python.h>
+#include "numpy/ufuncthreadapi.h"
+
+#ifdef WIN32
+    /* fixme: npy_byte conflicts with a definition in the windows headers.
+    */
+    #undef npy_byte
+    #include <windows.h>
+    
+#endif
+    
+/* Global object that stores how ufunc operations are threaded.
+   fixme: This is potentially a bad idea.  At the minimum, we should
+          store this on a per-thread basis.
+*/
+
+UFuncThreadSettings thread_settings;
+
+/* Determine the number of processors on this machine. 
+   Return 1 if it is not possible to determine the value.
+*/
+
+int number_of_processors()
+{
+   /* default the number of processors to 1.*/
+   int number_of_processors=1;
+   
+#ifdef WIN32
+    /* determine the number of processors */   
+    SYSTEM_INFO siSysInfo;
+    GetSystemInfo(&siSysInfo); 
+    number_of_processors = (int) siSysInfo.dwNumberOfProcessors; 
+#endif
+
+    return number_of_processors;
+}
+
+void init_thread_settings(UFuncThreadSettings* settings)
+{
+   /* default the number of processors to 1.*/
+   int processor_count=number_of_processors();
+
+    /* default to using one thread per processor.
+       fixme: We probably want to throttle this back on machines with
+              more than 4 processors unless we figure out better 
+              scaling.
+    */
+    settings->thread_count = processor_count; 
+    settings->use_threads = processor_count > 1;
+    settings->element_threshold=20000;
+}
+
+/* Python UFunc Threading API */
+
+/* Set the parameters that control how ufuncs operations are threaded. */
+static char
+doc_setthreading[] = "_setthreading(use_threads, thread_count, element_threshold) determines how numpy threads vector operations.\nIt returns a list of the old settings.\nSee setthreading() for more information on these parameters.";
+
+static PyObject *
+ufunc_setthreading(PyObject *dummy, PyObject *args)
+{
+
+	int use_threads, thread_count, element_threshold;
+
+	if (!PyArg_ParseTuple(args, "iii", &use_threads, &thread_count, &element_threshold)) 
+	    return NULL;
+
+	thread_settings.use_threads = use_threads;
+	thread_settings.thread_count = thread_count;
+	thread_settings.element_threshold = element_threshold;
+
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static char
+doc_getthreading[] = "_getthreading() returns a list of the form [use_threads, thread_count, element_threshold].\nSee setthreading() for more information on these parameters.";
+
+static PyObject *
+ufunc_getthreading(PyObject *dummy, PyObject *args)
+{
+	PyObject *res;
+
+	/* Construct list of defaults */
+	res = PyList_New(3);
+	if (res == NULL) 
+	    return NULL;
+	    
+	PyList_SET_ITEM(res, 0, PyInt_FromLong(thread_settings.use_threads));
+	PyList_SET_ITEM(res, 1, PyInt_FromLong(thread_settings.thread_count));
+	PyList_SET_ITEM(res, 2, PyInt_FromLong(thread_settings.element_threshold));
+
+	return res;
+
+}

Modified: branches/multicore/numpy/core/src/umathmodule.c.src
===================================================================
--- branches/multicore/numpy/core/src/umathmodule.c.src	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/src/umathmodule.c.src	2007-04-10 17:54:59 UTC (rev 3692)
@@ -6,6 +6,7 @@
 #include "numpy/ufuncobject.h"
 #include "abstract.h"
 #include <math.h>
+#include "numpy/ufuncthreadapi.h"
 
 /* A whole slew of basic math functions are provided originally
    by Konrad Hinsen. */
@@ -2046,6 +2047,7 @@
 
 #include "__umath_generated.c"
 
+#include "ufuncthreadapi.c"
 
 #include "ufuncobject.c"
 
@@ -2119,6 +2121,10 @@
 	 METH_VARARGS, NULL},
 	{"geterrobj", (PyCFunction) ufunc_geterr,
 	 METH_VARARGS, NULL},
+	{"_setthreading", (PyCFunction) ufunc_setthreading,
+	 METH_VARARGS, doc_setthreading},
+	{"_getthreading", (PyCFunction) ufunc_getthreading,
+	 METH_NOARGS, doc_getthreading},
 	{NULL,		NULL, 0}		/* sentinel */
 };
 
@@ -2218,6 +2224,9 @@
 	PyDict_SetItemString(d, "conj", s);
 	PyDict_SetItemString(d, "mod", s2);
 
+    /* initialize the default thread settings for the ufuncs. */
+    init_thread_settings(&thread_settings);
+     
 	return;
  err:
 	/* Check for errors */

Added: branches/multicore/numpy/core/tests/test_threadapi.py
===================================================================
--- branches/multicore/numpy/core/tests/test_threadapi.py	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/tests/test_threadapi.py	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,98 @@
+from numpy.testing import *
+set_package_path()
+from numpy.core.umath import _setthreading, _getthreading
+from numpy.core import setthreading, getthreading
+restore_path()
+
+class test_threading_state(NumpyTestCase):
+    
+    def check__getthreading(self):
+        """ Check "low level" _getthreading() api for getting threading info.
+        """
+        use_threads, thread_count, element_threshold = _getthreading()
+        
+        # It is impossible to tell what the defaults should be.
+        # They will vary from machine to machine.  Simply check that
+        # they are sane.
+        self.assertTrue(use_threads in [0,1])
+        self.assertTrue(thread_count>0)
+        self.assertTrue(element_threshold>0)
+
+    def check__setthreading(self):
+        """ Check "low level" _setthreading() api for setting threading info.
+        """
+        
+        _setthreading(1, 4, 100000)
+               
+        use_threads, thread_count, element_threshold = _getthreading()
+        
+        self.assertEqual(use_threads, 1)
+        self.assertEqual(thread_count, 4)
+        self.assertEqual(element_threshold, 100000)
+
+    def check_setthreading(self):
+        
+        default = getthreading()
+        old = setthreading(use_threads=1, thread_count=4, 
+                           element_threshold=100000)
+        
+        # ensure the returned value from setthreading was the previous state.
+        self.assertEqual(default, old)
+        
+        use_threads, thread_count, element_threshold = getthreading()
+        
+        self.assertEqual(use_threads, 1)
+        self.assertEqual(thread_count, 4)
+        self.assertEqual(element_threshold, 100000)
+
+    def check_setthreading_use_threads(self):
+        
+        default = getthreading()
+        old = setthreading(use_threads=0)
+        
+        # ensure the returned value from setthreading was the previous state.
+        self.assertEqual(default, old)
+        
+        use_threads, thread_count, element_threshold = getthreading()
+        
+        self.assertEqual(use_threads, 0)
+        self.assertEqual(thread_count, default[1])
+        self.assertEqual(element_threshold, default[2])
+
+    def check_setthreading_thread_count(self):
+        
+        default = getthreading()
+        old = setthreading(thread_count=20)
+        
+        # ensure the returned value from setthreading was the previous state.
+        self.assertEqual(default, old)
+        
+        use_threads, thread_count, element_threshold = getthreading()
+        
+        self.assertEqual(use_threads, default[0])
+        self.assertEqual(thread_count, 20)
+        self.assertEqual(element_threshold, default[2])
+
+    def check_setthreading_element_threshold(self):
+        
+        default = getthreading()
+        old = setthreading(element_threshold=1e6)
+        
+        # ensure the returned value from setthreading was the previous state.
+        self.assertEqual(default, old)
+        
+        use_threads, thread_count, element_threshold = getthreading()
+        
+        self.assertEqual(use_threads, default[0])
+        self.assertEqual(thread_count, default[1])
+        self.assertEqual(element_threshold, 1e6)
+
+    def check_docstrings(self):
+        self.assertTrue(len(_setthreading.__doc__) > 0)
+        self.assertTrue(len(_getthreading.__doc__) > 0)        
+        self.assertTrue(len(setthreading.__doc__) > 0)        
+        self.assertTrue(len(getthreading.__doc__) > 0)        
+        
+        
+if __name__ == "__main__":
+    NumpyTest().run()

Added: branches/multicore/numpy/core/threadapi.py
===================================================================
--- branches/multicore/numpy/core/threadapi.py	2007-04-10 15:44:17 UTC (rev 3691)
+++ branches/multicore/numpy/core/threadapi.py	2007-04-10 17:54:59 UTC (rev 3692)
@@ -0,0 +1,44 @@
+""" API for setting/getting the parameters that determine how numpy threads
+    vector operations.
+"""
+
+__all__ = ['setthreading', 'getthreading']
+
+import umath
+
+def setthreading(use_threads=None, thread_count=None, element_threshold=None):
+    """ Settings that determine how numpy uses threads on vector operations.          
+    
+        use_threads -- None, leaves value unaltered.  
+                       0 tells numpy not to use threads on vector operations.
+                       1 numpy uses threads on vector operations if appropriate.
+        thread_count -- Number of threads to use for vector operations.        
+        element_threshold -- numpy will only thread vector operations that
+                             have more than this number of elements in the
+                             arrays.
+                             
+        fixme: In many cases, the thread_count and element_threshold values
+               might be better as "suggestions" instead of exact values. 
+               We may want to add another thread state value that allows
+               numpy to pick the best thread settings.               
+    """
+    old_settings = umath._getthreading()
+    
+    settings = old_settings[:]
+    if use_threads is not None:
+        if use_threads:
+            settings[0] = 1
+        else: 
+            settings[0] = 0
+
+    if thread_count is not None:
+        settings[1] = int(thread_count)
+
+    if element_threshold is not None:
+        settings[2] = int(element_threshold)
+
+    umath._setthreading(*settings)
+   
+    return old_settings         
+            
+getthreading = umath._getthreading
\ No newline at end of file



More information about the Numpy-svn mailing list