summaryrefslogtreecommitdiff
path: root/Source/DirectFB/lib/fusion
diff options
context:
space:
mode:
Diffstat (limited to 'Source/DirectFB/lib/fusion')
-rwxr-xr-xSource/DirectFB/lib/fusion/Makefile.am100
-rwxr-xr-xSource/DirectFB/lib/fusion/Makefile.in804
-rwxr-xr-xSource/DirectFB/lib/fusion/arena.c566
-rwxr-xr-xSource/DirectFB/lib/fusion/arena.h62
-rwxr-xr-xSource/DirectFB/lib/fusion/build.h.in36
-rwxr-xr-xSource/DirectFB/lib/fusion/call.c581
-rwxr-xr-xSource/DirectFB/lib/fusion/call.h74
-rwxr-xr-xSource/DirectFB/lib/fusion/conf.c113
-rwxr-xr-xSource/DirectFB/lib/fusion/conf.h55
-rwxr-xr-xSource/DirectFB/lib/fusion/fusion.c2658
-rwxr-xr-xSource/DirectFB/lib/fusion/fusion.h142
-rwxr-xr-xSource/DirectFB/lib/fusion/fusion.pc.in11
-rwxr-xr-xSource/DirectFB/lib/fusion/fusion_internal.h185
-rwxr-xr-xSource/DirectFB/lib/fusion/hash.c560
-rwxr-xr-xSource/DirectFB/lib/fusion/hash.h179
-rwxr-xr-xSource/DirectFB/lib/fusion/lock.c687
-rwxr-xr-xSource/DirectFB/lib/fusion/lock.h122
-rwxr-xr-xSource/DirectFB/lib/fusion/object.c640
-rwxr-xr-xSource/DirectFB/lib/fusion/object.h279
-rwxr-xr-xSource/DirectFB/lib/fusion/property.c530
-rwxr-xr-xSource/DirectFB/lib/fusion/property.h114
-rwxr-xr-xSource/DirectFB/lib/fusion/protocol.h119
-rwxr-xr-xSource/DirectFB/lib/fusion/reactor.c1868
-rwxr-xr-xSource/DirectFB/lib/fusion/reactor.h197
-rwxr-xr-xSource/DirectFB/lib/fusion/ref.c849
-rwxr-xr-xSource/DirectFB/lib/fusion/ref.h134
-rwxr-xr-xSource/DirectFB/lib/fusion/shm/Makefile.am31
-rwxr-xr-xSource/DirectFB/lib/fusion/shm/Makefile.in565
-rwxr-xr-xSource/DirectFB/lib/fusion/shm/fake.c163
-rwxr-xr-xSource/DirectFB/lib/fusion/shm/heap.c802
-rwxr-xr-xSource/DirectFB/lib/fusion/shm/pool.c954
-rwxr-xr-xSource/DirectFB/lib/fusion/shm/pool.h69
-rwxr-xr-xSource/DirectFB/lib/fusion/shm/shm.c337
-rwxr-xr-xSource/DirectFB/lib/fusion/shm/shm.h48
-rwxr-xr-xSource/DirectFB/lib/fusion/shm/shm_internal.h264
-rwxr-xr-xSource/DirectFB/lib/fusion/shmalloc.c679
-rwxr-xr-xSource/DirectFB/lib/fusion/shmalloc.h124
-rwxr-xr-xSource/DirectFB/lib/fusion/types.h87
-rwxr-xr-xSource/DirectFB/lib/fusion/vector.c230
-rwxr-xr-xSource/DirectFB/lib/fusion/vector.h164
40 files changed, 16182 insertions, 0 deletions
diff --git a/Source/DirectFB/lib/fusion/Makefile.am b/Source/DirectFB/lib/fusion/Makefile.am
new file mode 100755
index 0000000..b97afe1
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/Makefile.am
@@ -0,0 +1,100 @@
+## Makefile.am for DirectFB/lib/fusion
+
+SUBDIRS = shm
+
+
+INCLUDES = \
+ -I$(top_builddir)/include \
+ -I$(top_builddir)/lib \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"${RUNTIME_SYSROOT}@DATADIR@\" \
+ -DMODULEDIR=\"${RUNTIME_SYSROOT}@MODULEDIR@\"
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = fusion.pc
+
+
+# If the old location isn't cleared, builds of external modules fail
+install-exec-local:
+ rm -rf $(DESTDIR)$(INTERNALINCLUDEDIR)/core/fusion
+ rm -rf $(DESTDIR)$(INTERNALINCLUDEDIR)/fusion
+
+
+includedir = @INCLUDEDIR@/fusion
+
+include_HEADERS = \
+ arena.h \
+ build.h \
+ call.h \
+ conf.h \
+ fusion.h \
+ fusion_internal.h \
+ hash.h \
+ lock.h \
+ object.h \
+ property.h \
+ protocol.h \
+ reactor.h \
+ ref.h \
+ shmalloc.h \
+ types.h \
+ vector.h
+
+
+lib_LTLIBRARIES = libfusion.la
+
+libfusion_la_SOURCES = \
+ arena.c \
+ call.c \
+ conf.c \
+ fusion.c \
+ hash.c \
+ lock.c \
+ object.c \
+ property.c \
+ reactor.c \
+ ref.c \
+ shmalloc.c \
+ vector.c
+
+libfusion_la_LIBADD = \
+ shm/libfusion_shm.la \
+ ../direct/libdirect.la
+
+libfusion_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -release $(LT_RELEASE) \
+ $(DFB_LDFLAGS)
+
+
+#
+## and now rebuild the static version with the *correct* object files
+#
+if BUILD_STATIC
+
+clean-local:
+ rm -f libfusion_fixed.a
+
+all-local: libfusion_fixed.a
+
+libfusion_fixed.a: .libs/libfusion.a
+ rm -f libfusion_fixed.a
+ ${AR} cru libfusion_fixed.a `find . -name "*.o" | grep -v '.libs'`
+ ${RANLIB} libfusion_fixed.a
+ cp -pf libfusion_fixed.a .libs/libfusion.a
+
+.libs/libfusion.a: libfusion.la
+
+else
+
+clean-local:
+
+all-local:
+
+endif
+
+
+include $(top_srcdir)/rules/nmfile.make
diff --git a/Source/DirectFB/lib/fusion/Makefile.in b/Source/DirectFB/lib/fusion/Makefile.in
new file mode 100755
index 0000000..34f267d
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/Makefile.in
@@ -0,0 +1,804 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/build.h.in \
+ $(srcdir)/fusion.pc.in $(top_srcdir)/rules/nmfile.make
+subdir = lib/fusion
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = build.h fusion.pc
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" \
+ "$(DESTDIR)$(includedir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libfusion_la_DEPENDENCIES = shm/libfusion_shm.la \
+ ../direct/libdirect.la
+am_libfusion_la_OBJECTS = arena.lo call.lo conf.lo fusion.lo hash.lo \
+ lock.lo object.lo property.lo reactor.lo ref.lo shmalloc.lo \
+ vector.lo
+libfusion_la_OBJECTS = $(am_libfusion_la_OBJECTS)
+libfusion_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libfusion_la_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libfusion_la_SOURCES)
+DIST_SOURCES = $(libfusion_la_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+pkgconfigDATA_INSTALL = $(INSTALL_DATA)
+DATA = $(pkgconfig_DATA)
+includeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(include_HEADERS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+ASFLAGS = @ASFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIR = @DATADIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DFB_CFLAGS_OMIT_FRAME_POINTER = @DFB_CFLAGS_OMIT_FRAME_POINTER@
+DFB_INTERNAL_CFLAGS = @DFB_INTERNAL_CFLAGS@
+DFB_LDFLAGS = @DFB_LDFLAGS@
+DFB_SMOOTH_SCALING = @DFB_SMOOTH_SCALING@
+DIRECTFB_BINARY_AGE = @DIRECTFB_BINARY_AGE@
+DIRECTFB_CSOURCE = @DIRECTFB_CSOURCE@
+DIRECTFB_INTERFACE_AGE = @DIRECTFB_INTERFACE_AGE@
+DIRECTFB_MAJOR_VERSION = @DIRECTFB_MAJOR_VERSION@
+DIRECTFB_MICRO_VERSION = @DIRECTFB_MICRO_VERSION@
+DIRECTFB_MINOR_VERSION = @DIRECTFB_MINOR_VERSION@
+DIRECTFB_VERSION = @DIRECTFB_VERSION@
+DIRECT_BUILD_DEBUG = @DIRECT_BUILD_DEBUG@
+DIRECT_BUILD_DEBUGS = @DIRECT_BUILD_DEBUGS@
+DIRECT_BUILD_GETTID = @DIRECT_BUILD_GETTID@
+DIRECT_BUILD_NETWORK = @DIRECT_BUILD_NETWORK@
+DIRECT_BUILD_STDBOOL = @DIRECT_BUILD_STDBOOL@
+DIRECT_BUILD_TEXT = @DIRECT_BUILD_TEXT@
+DIRECT_BUILD_TRACE = @DIRECT_BUILD_TRACE@
+DSYMUTIL = @DSYMUTIL@
+DYNLIB = @DYNLIB@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+FREETYPE_PROVIDER = @FREETYPE_PROVIDER@
+FUSION_BUILD_KERNEL = @FUSION_BUILD_KERNEL@
+FUSION_BUILD_MULTI = @FUSION_BUILD_MULTI@
+FUSION_MESSAGE_SIZE = @FUSION_MESSAGE_SIZE@
+GIF_PROVIDER = @GIF_PROVIDER@
+GREP = @GREP@
+HAVE_LINUX = @HAVE_LINUX@
+INCLUDEDIR = @INCLUDEDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTERNALINCLUDEDIR = @INTERNALINCLUDEDIR@
+JPEG_PROVIDER = @JPEG_PROVIDER@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBJPEG = @LIBJPEG@
+LIBOBJS = @LIBOBJS@
+LIBPNG = @LIBPNG@
+LIBPNG_CONFIG = @LIBPNG_CONFIG@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_BINARY = @LT_BINARY@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAN2HTML = @MAN2HTML@
+MKDIR_P = @MKDIR_P@
+MODULEDIR = @MODULEDIR@
+MODULEDIRNAME = @MODULEDIRNAME@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+OSX_LIBS = @OSX_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PNG_PROVIDER = @PNG_PROVIDER@
+RANLIB = @RANLIB@
+RUNTIME_SYSROOT = @RUNTIME_SYSROOT@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_LIBS = @SDL_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOPATH = @SOPATH@
+STRIP = @STRIP@
+SYSCONFDIR = @SYSCONFDIR@
+SYSFS_LIBS = @SYSFS_LIBS@
+THREADFLAGS = @THREADFLAGS@
+THREADLIB = @THREADLIB@
+TSLIB_CFLAGS = @TSLIB_CFLAGS@
+TSLIB_LIBS = @TSLIB_LIBS@
+VERSION = @VERSION@
+VNC_CFLAGS = @VNC_CFLAGS@
+VNC_CONFIG = @VNC_CONFIG@
+VNC_LIBS = @VNC_LIBS@
+X11_CFLAGS = @X11_CFLAGS@
+X11_LIBS = @X11_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @INCLUDEDIR@/fusion
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = shm
+INCLUDES = \
+ -I$(top_builddir)/include \
+ -I$(top_builddir)/lib \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"${RUNTIME_SYSROOT}@DATADIR@\" \
+ -DMODULEDIR=\"${RUNTIME_SYSROOT}@MODULEDIR@\"
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = fusion.pc
+include_HEADERS = \
+ arena.h \
+ build.h \
+ call.h \
+ conf.h \
+ fusion.h \
+ fusion_internal.h \
+ hash.h \
+ lock.h \
+ object.h \
+ property.h \
+ protocol.h \
+ reactor.h \
+ ref.h \
+ shmalloc.h \
+ types.h \
+ vector.h
+
+lib_LTLIBRARIES = libfusion.la
+libfusion_la_SOURCES = \
+ arena.c \
+ call.c \
+ conf.c \
+ fusion.c \
+ hash.c \
+ lock.c \
+ object.c \
+ property.c \
+ reactor.c \
+ ref.c \
+ shmalloc.c \
+ vector.c
+
+libfusion_la_LIBADD = \
+ shm/libfusion_shm.la \
+ ../direct/libdirect.la
+
+libfusion_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -release $(LT_RELEASE) \
+ $(DFB_LDFLAGS)
+
+@BUILD_SHARED_TRUE@@ENABLE_TRACE_TRUE@LIBTONM = $(LTLIBRARIES:.la=-$(LT_RELEASE).so.$(LT_BINARY))
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(top_srcdir)/rules/nmfile.make $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/fusion/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lib/fusion/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+build.h: $(top_builddir)/config.status $(srcdir)/build.h.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+fusion.pc: $(top_builddir)/config.status $(srcdir)/fusion.pc.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libfusion.la: $(libfusion_la_OBJECTS) $(libfusion_la_DEPENDENCIES)
+ $(libfusion_la_LINK) -rpath $(libdir) $(libfusion_la_OBJECTS) $(libfusion_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arena.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/call.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fusion.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/property.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reactor.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ref.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shmalloc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vector.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgconfigDATA: $(pkgconfig_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)"
+ @list='$(pkgconfig_DATA)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(pkgconfigDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
+ $(pkgconfigDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(pkgconfigdir)/$$f"; \
+ done
+
+uninstall-pkgconfigDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgconfig_DATA)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(pkgconfigdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(pkgconfigdir)/$$f"; \
+ done
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
+ $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+ list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ distdir=`$(am__cd) $(distdir) && pwd`; \
+ top_distdir=`$(am__cd) $(top_distdir) && pwd`; \
+ (cd $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$top_distdir" \
+ distdir="$$distdir/$$subdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS) all-local
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+@BUILD_SHARED_FALSE@install-data-local:
+@ENABLE_TRACE_FALSE@install-data-local:
+clean: clean-recursive
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \
+ mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-data-local install-includeHEADERS \
+ install-pkgconfigDATA
+
+install-dvi: install-dvi-recursive
+
+install-exec-am: install-exec-local install-libLTLIBRARIES
+
+install-html: install-html-recursive
+
+install-info: install-info-recursive
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-ps: install-ps-recursive
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+ uninstall-pkgconfigDATA
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \
+ install-strip
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am all-local check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-local ctags \
+ ctags-recursive distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-data-local install-dvi install-dvi-am \
+ install-exec install-exec-am install-exec-local install-html \
+ install-html-am install-includeHEADERS install-info \
+ install-info-am install-libLTLIBRARIES install-man install-pdf \
+ install-pdf-am install-pkgconfigDATA install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am uninstall-includeHEADERS \
+ uninstall-libLTLIBRARIES uninstall-pkgconfigDATA
+
+
+# If the old location isn't cleared, builds of external modules fail
+install-exec-local:
+ rm -rf $(DESTDIR)$(INTERNALINCLUDEDIR)/core/fusion
+ rm -rf $(DESTDIR)$(INTERNALINCLUDEDIR)/fusion
+
+#
+#
+
+@BUILD_STATIC_TRUE@clean-local:
+@BUILD_STATIC_TRUE@ rm -f libfusion_fixed.a
+
+@BUILD_STATIC_TRUE@all-local: libfusion_fixed.a
+
+@BUILD_STATIC_TRUE@libfusion_fixed.a: .libs/libfusion.a
+@BUILD_STATIC_TRUE@ rm -f libfusion_fixed.a
+@BUILD_STATIC_TRUE@ ${AR} cru libfusion_fixed.a `find . -name "*.o" | grep -v '.libs'`
+@BUILD_STATIC_TRUE@ ${RANLIB} libfusion_fixed.a
+@BUILD_STATIC_TRUE@ cp -pf libfusion_fixed.a .libs/libfusion.a
+
+@BUILD_STATIC_TRUE@.libs/libfusion.a: libfusion.la
+
+@BUILD_STATIC_FALSE@clean-local:
+
+@BUILD_STATIC_FALSE@all-local:
+
+@BUILD_SHARED_TRUE@@ENABLE_TRACE_TRUE@install-data-local:
+@BUILD_SHARED_TRUE@@ENABLE_TRACE_TRUE@ mkdir -p -- "$(DESTDIR)$(libdir)"
+@BUILD_SHARED_TRUE@@ENABLE_TRACE_TRUE@ nm -n ".libs/$(LIBTONM)" > "$(DESTDIR)$(libdir)/nm-n.$(LIBTONM)"
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/Source/DirectFB/lib/fusion/arena.c b/Source/DirectFB/lib/fusion/arena.c
new file mode 100755
index 0000000..9d86dca
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/arena.c
@@ -0,0 +1,566 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <pthread.h>
+
+#include <direct/debug.h>
+#include <direct/list.h>
+#include <direct/mem.h>
+#include <direct/messages.h>
+
+#include <fusion/build.h>
+#include <fusion/types.h>
+#include <fusion/lock.h>
+#include <fusion/hash.h>
+#include <fusion/ref.h>
+#include <fusion/arena.h>
+#include <fusion/shm/shm.h>
+#include <fusion/shmalloc.h>
+
+#include "fusion_internal.h"
+
+
+#if FUSION_BUILD_MULTI
+
+D_DEBUG_DOMAIN( Fusion_Arena, "Fusion/Arena", "Fusion Arena" );
+
+struct __Fusion_FusionArena {
+ DirectLink link;
+
+ int magic;
+
+ FusionWorldShared *shared;
+
+ FusionSkirmish lock;
+ FusionRef ref;
+
+ char *name;
+
+ FusionHash *field_hash;
+};
+
+/**********************************************************************************************************************/
+
+static FusionArena *lock_arena ( FusionWorld *world,
+ const char *name,
+ bool add );
+
+static void unlock_arena( FusionArena *arena );
+
+/**********************************************************************************************************************/
+
+DirectResult
+fusion_arena_enter (FusionWorld *world,
+ const char *name,
+ ArenaEnterFunc initialize,
+ ArenaEnterFunc join,
+ void *ctx,
+ FusionArena **ret_arena,
+ int *ret_error)
+{
+ FusionArena *arena;
+ FusionWorldShared *shared;
+ ArenaEnterFunc func;
+ int error = 0;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ D_ASSERT( name != NULL );
+ D_ASSERT( initialize != NULL );
+ D_ASSERT( join != NULL );
+ D_ASSERT( ret_arena != NULL );
+
+ D_DEBUG_AT( Fusion_Arena, "%s( '%s' )\n", __FUNCTION__, name );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ /* Lookup arena and lock it. If it doesn't exist create it. */
+ arena = lock_arena( world, name, true );
+ if (!arena)
+ return DR_FAILURE;
+
+ /* Check if we are the first. */
+ if (fusion_ref_zero_trylock( &arena->ref ) == DR_OK) {
+ D_DEBUG ("Fusion/Arena: entering arena '%s' (establishing)\n", name);
+
+ /* Call 'initialize' later. */
+ func = initialize;
+
+ /* Unlock the reference counter. */
+ fusion_ref_unlock( &arena->ref );
+ }
+ else {
+ D_DEBUG ("Fusion/Arena: entering arena '%s' (joining)\n", name);
+
+ fusion_shm_attach_unattached( world );
+
+ /* Call 'join' later. */
+ func = join;
+ }
+
+ /* Increase reference counter. */
+ fusion_ref_up (&arena->ref, false);
+
+ /* Return the arena. */
+ *ret_arena = arena;
+
+ /* Call 'initialize' or 'join'. */
+ error = func (arena, ctx);
+
+ /* Return the return value of the callback. */
+ if (ret_error)
+ *ret_error = error;
+
+ if (error) {
+ fusion_ref_down (&arena->ref, false);
+
+ if (func == initialize) {
+ /* Destroy fields. */
+ fusion_hash_destroy( arena->field_hash );
+
+ /* Destroy reference counter. */
+ fusion_ref_destroy( &arena->ref );
+
+ /* Destroy the arena lock. This has to happen before
+ locking the list. Otherwise a dead lock with lock_arena()
+ below could occur. */
+ fusion_skirmish_destroy( &arena->lock );
+
+ /* Lock the list and remove the arena. */
+ fusion_skirmish_prevail( &shared->arenas_lock );
+ direct_list_remove( &shared->arenas, &arena->link );
+ fusion_skirmish_dismiss( &shared->arenas_lock );
+
+ D_MAGIC_CLEAR( arena );
+
+ /* Free allocated memory. */
+ SHFREE( shared->main_pool, arena->name );
+ SHFREE( shared->main_pool, arena );
+
+ return DR_OK;
+ }
+ }
+
+ /* Unlock the arena. */
+ unlock_arena( arena );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_arena_add_shared_field (FusionArena *arena,
+ const char *name,
+ void *data)
+{
+ DirectResult ret;
+ FusionWorldShared *shared;
+ char *shname;
+
+ D_ASSERT( arena != NULL );
+ D_ASSERT( data != NULL );
+ D_ASSERT( name != NULL );
+
+ D_MAGIC_ASSERT( arena, FusionArena );
+
+ D_DEBUG_AT( Fusion_Arena, "%s( '%s', '%s' -> %p )\n", __FUNCTION__, arena->name, name, data );
+
+ shared = arena->shared;
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ /* Lock the arena. */
+ ret = fusion_skirmish_prevail( &arena->lock );
+ if (ret)
+ return ret;
+
+ /* Give it the requested name. */
+ shname = SHSTRDUP( shared->main_pool, name );
+ if (shname)
+ ret = fusion_hash_replace( arena->field_hash, shname, data, NULL, NULL );
+ else
+ ret = D_OOSHM();
+
+ /* Unlock the arena. */
+ fusion_skirmish_dismiss( &arena->lock );
+
+ return ret;
+}
+
+DirectResult
+fusion_arena_get_shared_field (FusionArena *arena,
+ const char *name,
+ void **data)
+{
+ void *ptr;
+
+ D_ASSERT( arena != NULL );
+ D_ASSERT( name != NULL );
+ D_ASSERT( data != NULL );
+
+ D_MAGIC_ASSERT( arena, FusionArena );
+
+ D_DEBUG_AT( Fusion_Arena, "%s( '%s', '%s' )\n", __FUNCTION__, arena->name, name );
+
+ /* Lock the arena. */
+ if (fusion_skirmish_prevail( &arena->lock ))
+ return DR_FAILURE;
+
+ /* Lookup entry. */
+ ptr = fusion_hash_lookup( arena->field_hash, name );
+
+ D_DEBUG_AT( Fusion_Arena, " -> %p\n", ptr );
+
+ /* Unlock the arena. */
+ fusion_skirmish_dismiss( &arena->lock );
+
+ if (!ptr)
+ return DR_ITEMNOTFOUND;
+
+ *data = ptr;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_arena_exit (FusionArena *arena,
+ ArenaExitFunc shutdown,
+ ArenaExitFunc leave,
+ void *ctx,
+ bool emergency,
+ int *ret_error)
+{
+ int error = 0;
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( arena, FusionArena );
+
+ D_DEBUG_AT( Fusion_Arena, "%s( '%s' )\n", __FUNCTION__, arena->name );
+
+ D_ASSERT( shutdown != NULL );
+
+ shared = arena->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ /* Lock the arena. */
+ if (fusion_skirmish_prevail( &arena->lock ))
+ return DR_FAILURE;
+
+ /* Decrease reference counter. */
+ fusion_ref_down( &arena->ref, false );
+
+ /* If we are the last... */
+ if (fusion_ref_zero_trylock( &arena->ref ) == DR_OK) {
+ /* Deinitialize everything. */
+ error = shutdown( arena, ctx, emergency );
+
+ /* Destroy fields. */
+ fusion_hash_destroy( arena->field_hash );
+
+ /* Destroy reference counter. */
+ fusion_ref_destroy( &arena->ref );
+
+ /* Destroy the arena lock. This has to happen before
+ locking the list. Otherwise a dead lock with lock_arena()
+ below could occur. */
+ fusion_skirmish_destroy( &arena->lock );
+
+ /* Lock the list and remove the arena. */
+ fusion_skirmish_prevail( &shared->arenas_lock );
+ direct_list_remove( &shared->arenas, &arena->link );
+ fusion_skirmish_dismiss( &shared->arenas_lock );
+
+ D_MAGIC_CLEAR( arena );
+
+ /* Free allocated memory. */
+ SHFREE( shared->main_pool, arena->name );
+ SHFREE( shared->main_pool, arena );
+ }
+ else {
+ if (!leave) {
+ fusion_ref_up( &arena->ref, false );
+ fusion_skirmish_dismiss( &arena->lock );
+ return DR_BUSY;
+ }
+
+ /* Simply leave the arena. */
+ error = leave( arena, ctx, emergency );
+
+ /* Unlock the arena. */
+ fusion_skirmish_dismiss( &arena->lock );
+ }
+
+ /* Return the return value of the callback. */
+ if (ret_error)
+ *ret_error = error;
+
+ return DR_OK;
+}
+
+
+/*****************************
+ * File internal functions *
+ *****************************/
+
+static FusionArena *
+create_arena( FusionWorld *world,
+ const char *name )
+{
+ DirectResult ret;
+ char buf[64];
+ FusionArena *arena;
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_ASSERT( name != NULL );
+
+ shared = world->shared;
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ arena = SHCALLOC( shared->main_pool, 1, sizeof(FusionArena) );
+ if (!arena) {
+ D_OOSHM();
+ return NULL;
+ }
+
+ arena->shared = shared;
+
+ snprintf( buf, sizeof(buf), "Arena '%s'", name );
+
+ /* Initialize lock and reference counter. */
+ ret = fusion_skirmish_init( &arena->lock, buf, world );
+ if (ret)
+ goto error;
+
+ ret = fusion_ref_init( &arena->ref, buf, world );
+ if (ret)
+ goto error_ref;
+
+ /* Give it the requested name. */
+ arena->name = SHSTRDUP( shared->main_pool, name );
+ if (!arena->name) {
+ D_OOSHM();
+ goto error_prevail;
+ }
+
+ ret = fusion_hash_create( shared->main_pool, HASH_STRING, HASH_PTR, 7, &arena->field_hash );
+ if (ret)
+ goto error_hash;
+
+ fusion_hash_set_autofree( arena->field_hash, true, false );
+
+ /* Add it to the list. */
+ direct_list_prepend( &shared->arenas, &arena->link );
+
+ /* Lock the newly created arena. */
+ ret = fusion_skirmish_prevail( &arena->lock );
+ if (ret)
+ goto error_prevail;
+
+ D_MAGIC_SET( arena, FusionArena );
+
+ /* Returned locked new arena. */
+ return arena;
+
+
+error_prevail:
+ fusion_hash_destroy( arena->field_hash );
+
+error_hash:
+ if (arena->name)
+ SHFREE( shared->main_pool, arena->name );
+
+ fusion_ref_destroy( &arena->ref );
+
+error_ref:
+ fusion_skirmish_destroy( &arena->lock );
+
+error:
+ SHFREE( shared->main_pool, arena );
+
+ return NULL;
+}
+
+static FusionArena *
+lock_arena( FusionWorld *world,
+ const char *name,
+ bool add )
+{
+ FusionArena *arena;
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_ASSERT( name != NULL );
+
+ shared = world->shared;
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ /* Lock the list. */
+ if (fusion_skirmish_prevail( &shared->arenas_lock ))
+ return NULL;
+
+ /* For each exisiting arena... */
+ direct_list_foreach (arena, shared->arenas) {
+ /* Lock the arena.
+ This would fail if the arena has been
+ destroyed while waiting for the lock. */
+ if (fusion_skirmish_prevail( &arena->lock ))
+ continue;
+
+ D_MAGIC_ASSERT( arena, FusionArena );
+
+ /* Check if the name matches. */
+ if (! strcmp( arena->name, name )) {
+ /* Check for an orphaned arena. */
+ if (fusion_ref_zero_trylock( &arena->ref ) == DR_OK) {
+ D_ERROR( "Fusion/Arena: orphaned arena '%s'!\n", name );
+
+ fusion_ref_unlock( &arena->ref );
+
+// arena = NULL;
+ }
+
+ /* Unlock the list. */
+ fusion_skirmish_dismiss( &shared->arenas_lock );
+
+ /* Return locked arena. */
+ return arena;
+ }
+
+ /* Unlock mismatched arena. */
+ fusion_skirmish_dismiss( &arena->lock );
+ }
+
+ /* If no arena name matched, create a new arena
+ before unlocking the list again. */
+ arena = add ? create_arena( world, name ) : NULL;
+
+ /* Unlock the list. */
+ fusion_skirmish_dismiss( &shared->arenas_lock );
+
+ return arena;
+}
+
+static void
+unlock_arena( FusionArena *arena )
+{
+ D_ASSERT( arena != NULL );
+
+ D_MAGIC_ASSERT( arena, FusionArena );
+
+ /* Unlock the arena. */
+ fusion_skirmish_dismiss( &arena->lock );
+}
+
+#else
+
+DirectResult
+fusion_arena_enter (FusionWorld *world,
+ const char *name,
+ ArenaEnterFunc initialize,
+ ArenaEnterFunc join,
+ void *ctx,
+ FusionArena **ret_arena,
+ int *ret_error)
+{
+ int error;
+
+ D_ASSERT( name != NULL );
+ D_ASSERT( initialize != NULL );
+ D_ASSERT( join != NULL );
+ D_ASSERT( ret_arena != NULL );
+
+ /* Always call 'initialize'. */
+ error = initialize (NULL, ctx);
+
+ /* Return the return value of the callback. */
+ if (ret_error)
+ *ret_error = error;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_arena_add_shared_field (FusionArena *arena,
+ const char *name,
+ void *data)
+{
+ D_ASSERT( data != NULL );
+ D_ASSERT( name != NULL );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_arena_get_shared_field (FusionArena *arena,
+ const char *name,
+ void **data)
+{
+ D_ASSERT( data != NULL );
+ D_ASSERT( name != NULL );
+
+ D_BUG( "should not call this in fake mode" );
+
+ /* No field by that name has been found. */
+ return DR_ITEMNOTFOUND;
+}
+
+DirectResult
+fusion_arena_exit (FusionArena *arena,
+ ArenaExitFunc shutdown,
+ ArenaExitFunc leave,
+ void *ctx,
+ bool emergency,
+ int *ret_error)
+{
+ int error = 0;
+
+ D_ASSERT( shutdown != NULL );
+
+ /* Deinitialize everything. */
+ error = shutdown( arena, ctx, emergency );
+
+ /* Return the return value of the callback. */
+ if (ret_error)
+ *ret_error = error;
+
+ return DR_OK;
+}
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/arena.h b/Source/DirectFB/lib/fusion/arena.h
new file mode 100755
index 0000000..d11d134
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/arena.h
@@ -0,0 +1,62 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__ARENA_H__
+#define __FUSION__ARENA_H__
+
+#include <fusion/types.h>
+
+typedef int (*ArenaEnterFunc) (FusionArena *arena, void *ctx);
+typedef int (*ArenaExitFunc) (FusionArena *arena, void *ctx, bool emergency);
+
+
+DirectResult fusion_arena_enter (FusionWorld *world,
+ const char *name,
+ ArenaEnterFunc initialize,
+ ArenaEnterFunc join,
+ void *ctx,
+ FusionArena **ret_arena,
+ int *ret_error);
+
+DirectResult fusion_arena_add_shared_field (FusionArena *arena,
+ const char *name,
+ void *data);
+
+DirectResult fusion_arena_get_shared_field (FusionArena *arena,
+ const char *name,
+ void **data);
+
+DirectResult fusion_arena_exit (FusionArena *arena,
+ ArenaExitFunc shutdown,
+ ArenaExitFunc leave,
+ void *ctx,
+ bool emergency,
+ int *ret_error);
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/build.h.in b/Source/DirectFB/lib/fusion/build.h.in
new file mode 100755
index 0000000..74b4128
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/build.h.in
@@ -0,0 +1,36 @@
+/*
+ (c) Copyright 2000-2002 convergence integrated media GmbH.
+ (c) Copyright 2002-2004 convergence GmbH.
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org> and
+ Ville Syrjälä <syrjala@sci.fi>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__BUILD_H__
+#define __FUSION__BUILD_H__
+
+#define FUSION_BUILD_MULTI (@FUSION_BUILD_MULTI@)
+#define FUSION_BUILD_KERNEL (@FUSION_BUILD_KERNEL@)
+#define FUSION_MESSAGE_SIZE (@FUSION_MESSAGE_SIZE@)
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/call.c b/Source/DirectFB/lib/fusion/call.c
new file mode 100755
index 0000000..71ce5e5
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/call.c
@@ -0,0 +1,581 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <fusion/build.h>
+
+#include <direct/debug.h>
+#include <direct/messages.h>
+
+#include <fusion/types.h>
+#include <fusion/call.h>
+#include <fusion/conf.h>
+
+#include "fusion_internal.h"
+
+
+D_DEBUG_DOMAIN( Fusion_Call, "Fusion/Call", "Fusion Call" );
+
+
+#if FUSION_BUILD_MULTI
+
+#if FUSION_BUILD_KERNEL
+
+DirectResult
+fusion_call_init (FusionCall *call,
+ FusionCallHandler handler,
+ void *ctx,
+ const FusionWorld *world)
+{
+ FusionCallNew call_new;
+
+ D_DEBUG_AT( Fusion_Call, "%s( %p, %p <%s>, %p, %p )\n", __FUNCTION__, call, handler,
+ direct_trace_lookup_symbol_at( handler ), ctx, world );
+
+ D_ASSERT( call != NULL );
+ D_ASSERT( handler != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_MAGIC_ASSERT( world->shared, FusionWorldShared );
+
+ /* Called from others. */
+ call_new.handler = handler;
+ call_new.ctx = ctx;
+
+ while (ioctl( world->fusion_fd, FUSION_CALL_NEW, &call_new )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_CALL_NEW");
+
+ return DR_FAILURE;
+ }
+
+ memset( call, 0, sizeof(FusionCall) );
+
+ /* Store handler, called directly when called by ourself. */
+ call->handler = handler;
+ call->ctx = ctx;
+
+ /* Store call and own fusion id. */
+ call->call_id = call_new.call_id;
+ call->fusion_id = fusion_id( world );
+
+ /* Keep back pointer to shared world data. */
+ call->shared = world->shared;
+
+ D_DEBUG_AT( Fusion_Call, " -> call id %d\n", call->call_id );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_call_execute (FusionCall *call,
+ FusionCallExecFlags flags,
+ int call_arg,
+ void *call_ptr,
+ int *ret_val)
+{
+ D_DEBUG_AT( Fusion_Call, "%s( %p, 0x%x, %d, %p )\n", __FUNCTION__, call, flags, call_arg, call_ptr );
+
+ D_ASSERT( call != NULL );
+
+ if (!call->handler)
+ return DR_DESTROYED;
+
+ D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler ) );
+
+ if (!(flags & FCEF_NODIRECT) && call->fusion_id == _fusion_id( call->shared )) {
+ int ret;
+ FusionCallHandlerResult result;
+
+ result = call->handler( _fusion_id( call->shared ), call_arg, call_ptr, call->ctx, 0, &ret );
+
+ if (result != FCHR_RETURN)
+ D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" );
+
+ if (ret_val)
+ *ret_val = ret;
+ }
+ else {
+ FusionCallExecute execute;
+
+ execute.call_id = call->call_id;
+ execute.call_arg = call_arg;
+ execute.call_ptr = call_ptr;
+ execute.flags = flags;
+
+ while (ioctl( _fusion_fd( call->shared ), FUSION_CALL_EXECUTE, &execute )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+// D_ERROR ("Fusion/Call: invalid call\n");
+ return DR_INVARG;
+ case EIDRM:
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_CALL_EXECUTE");
+
+ return DR_FAILURE;
+ }
+
+ if (ret_val)
+ *ret_val = execute.ret_val;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_call_return( FusionCall *call,
+ unsigned int serial,
+ int val )
+{
+ FusionCallReturn call_ret;
+
+ D_DEBUG_AT( Fusion_Call, "%s( %p, %u, %d )\n", __FUNCTION__, call, serial, val );
+
+ D_ASSERT( call != NULL );
+
+ D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler ) );
+
+ D_ASSUME( serial != 0 );
+ if (!serial)
+ return DR_UNSUPPORTED;
+
+ call_ret.call_id = call->call_id;
+ call_ret.val = val;
+ call_ret.serial = serial;
+
+ while (ioctl (_fusion_fd( call->shared ), FUSION_CALL_RETURN, &call_ret)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EIDRM:
+ D_WARN( "caller withdrawn (signal?)" );
+ return DR_NOCONTEXT;
+ case EINVAL:
+ D_ERROR( "Fusion/Call: invalid call\n" );
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_CALL_RETURN");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_call_destroy (FusionCall *call)
+{
+ D_DEBUG_AT( Fusion_Call, "%s( %p )\n", __FUNCTION__, call );
+
+ D_ASSERT( call != NULL );
+ D_ASSERT( call->handler != NULL );
+
+ D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call->handler ) );
+
+ while (ioctl (_fusion_fd( call->shared ), FUSION_CALL_DESTROY, &call->call_id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Call: invalid call\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_CALL_DESTROY");
+
+ return DR_FAILURE;
+ }
+
+ call->handler = NULL;
+
+ return DR_OK;
+}
+
+void
+_fusion_call_process( FusionWorld *world, int call_id, FusionCallMessage *msg )
+{
+ FusionCallHandler call_handler;
+ FusionCallReturn call_ret;
+ FusionCallHandlerResult result;
+
+ D_DEBUG_AT( Fusion_Call, "%s()\n", __FUNCTION__ );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_ASSERT( msg != NULL );
+
+ call_handler = msg->handler;
+
+ D_ASSERT( call_handler != NULL );
+
+ D_DEBUG_AT( Fusion_Call, " -> %s\n", direct_trace_lookup_symbol_at( call_handler ) );
+
+ call_ret.val = 0;
+
+ result = call_handler( msg->caller, msg->call_arg, msg->call_ptr, msg->ctx, msg->serial, &call_ret.val );
+
+ switch (result) {
+ case FCHR_RETURN:
+ if (msg->serial) {
+ call_ret.serial = msg->serial;
+ call_ret.call_id = call_id;
+
+ while (ioctl (world->fusion_fd, FUSION_CALL_RETURN, &call_ret)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EIDRM:
+ D_WARN( "caller withdrawn (signal?)" );
+ return;
+ case EINVAL:
+ D_ERROR( "Fusion/Call: invalid call\n" );
+ return;
+ default:
+ D_PERROR( "FUSION_CALL_RETURN" );
+ return;
+ }
+ }
+ }
+ break;
+
+ case FCHR_RETAIN:
+ break;
+
+ default:
+ D_BUG( "unknown result %d from call handler", result );
+ }
+}
+
+#else /* FUSION_BUILD_KERNEL */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+
+DirectResult
+fusion_call_init (FusionCall *call,
+ FusionCallHandler handler,
+ void *ctx,
+ const FusionWorld *world)
+{
+ D_ASSERT( call != NULL );
+ D_ASSERT( handler != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_MAGIC_ASSERT( world->shared, FusionWorldShared );
+
+ memset( call, 0, sizeof(FusionCall) );
+
+ call->call_id = ++world->shared->call_ids;
+
+ /* Store handler, called directly when called by ourself. */
+ call->handler = handler;
+ call->ctx = ctx;
+
+ /* Store own fusion id. */
+ call->fusion_id = fusion_id( world );
+
+ /* Keep back pointer to shared world data. */
+ call->shared = world->shared;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_call_execute (FusionCall *call,
+ FusionCallExecFlags flags,
+ int call_arg,
+ void *call_ptr,
+ int *ret_val)
+{
+ DirectResult ret = DR_OK;
+ FusionWorld *world;
+ FusionCallMessage msg;
+ struct sockaddr_un addr;
+
+ D_ASSERT( call != NULL );
+
+ if (!call->handler)
+ return DR_DESTROYED;
+
+ if (!(flags & FCEF_NODIRECT) && call->fusion_id == _fusion_id( call->shared )) {
+ int ret;
+ FusionCallHandlerResult result;
+
+ result = call->handler( _fusion_id( call->shared ), call_arg, call_ptr, call->ctx, 0, &ret );
+
+ if (result != FCHR_RETURN)
+ D_WARN( "local call handler returned FCHR_RETAIN, need FCEF_NODIRECT" );
+
+ if (ret_val)
+ *ret_val = ret;
+
+ return DR_OK;
+ }
+
+ world = _fusion_world( call->shared );
+
+ msg.type = FMT_CALL;
+ msg.caller = world->fusion_id;
+ msg.call_id = call->call_id;
+ msg.call_arg = call_arg;
+ msg.call_ptr = call_ptr;
+ msg.handler = call->handler;
+ msg.ctx = call->ctx;
+ msg.flags = flags;
+
+ if (flags & FCEF_ONEWAY) {
+ /* Invalidate serial. */
+ msg.serial = -1;
+
+ /* Send message. */
+ addr.sun_family = AF_UNIX;
+ snprintf( addr.sun_path, sizeof(addr.sun_path),
+ "/tmp/.fusion-%d/%lx", call->shared->world_index, call->fusion_id );
+
+ ret = _fusion_send_message( world->fusion_fd, &msg, sizeof(msg), &addr );
+ }
+ else {
+ int fd;
+ socklen_t len;
+ int err;
+
+ fd = socket( PF_LOCAL, SOCK_RAW, 0 );
+ if (fd < 0) {
+ D_PERROR( "Fusion/Call: Error creating local socket!\n" ) ;
+ return DR_IO;
+ }
+
+ /* Set close-on-exec flag. */
+ fcntl( fd, F_SETFD, FD_CLOEXEC );
+
+ addr.sun_family = AF_UNIX;
+ len = snprintf( addr.sun_path, sizeof(addr.sun_path),
+ "/tmp/.fusion-%d/call.%x.", fusion_world_index( world ), call->call_id );
+
+ /* Generate call serial (socket address is based on it). */
+ for (msg.serial = 0; msg.serial <= 0xffffff; msg.serial++) {
+ snprintf( addr.sun_path+len, sizeof(addr.sun_path)-len, "%x", msg.serial );
+ err = bind( fd, (struct sockaddr*)&addr, sizeof(addr) );
+ if (err == 0) {
+ chmod( addr.sun_path, 0660 );
+ /* Change group, if requested. */
+ if (fusion_config->shmfile_gid != (gid_t)-1)
+ chown( addr.sun_path, -1, fusion_config->shmfile_gid );
+ break;
+ }
+ }
+
+ if (err < 0) {
+ D_PERROR( "Fusion/Call: Error binding local socket!\n" );
+ close( fd );
+ return DR_IO;
+ }
+
+ /* Send message. */
+ snprintf( addr.sun_path, sizeof(addr.sun_path),
+ "/tmp/.fusion-%d/%lx", call->shared->world_index, call->fusion_id );
+
+ ret = _fusion_send_message( fd, &msg, sizeof(msg), &addr );
+ if (ret == DR_OK) {
+ FusionCallReturn callret;
+ /* Wait for reply. */
+ ret = _fusion_recv_message( fd, &callret, sizeof(callret), NULL );
+ if (ret == DR_OK) {
+ if (ret_val)
+ *ret_val = callret.val;
+ }
+ }
+
+ len = sizeof(addr);
+ if (getsockname( fd, (struct sockaddr*)&addr, &len ) == 0)
+ unlink( addr.sun_path );
+ close( fd );
+ }
+
+ return ret;
+}
+
+DirectResult
+fusion_call_return( FusionCall *call,
+ unsigned int serial,
+ int val )
+{
+ struct sockaddr_un addr;
+ FusionCallReturn callret;
+
+ D_ASSERT( call != NULL );
+
+ addr.sun_family = AF_UNIX;
+ snprintf( addr.sun_path, sizeof(addr.sun_path),
+ "/tmp/.fusion-%d/call.%x.%x", call->shared->world_index, call->call_id, serial );
+
+ callret.type = FMT_CALLRET;
+ callret.val = val;
+
+ return _fusion_send_message( _fusion_fd( call->shared ), &callret, sizeof(callret), &addr );
+}
+
+DirectResult
+fusion_call_destroy (FusionCall *call)
+{
+ D_ASSERT( call != NULL );
+ D_ASSERT( call->handler != NULL );
+
+ call->handler = NULL;
+
+ return DR_OK;
+}
+
+void
+_fusion_call_process( FusionWorld *world, int call_id, FusionCallMessage *msg )
+{
+ FusionCallHandler call_handler;
+ FusionCallHandlerResult result;
+ FusionCallReturn callret;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_ASSERT( msg != NULL );
+
+ call_handler = msg->handler;
+
+ D_ASSERT( call_handler != NULL );
+
+ callret.type = FMT_CALLRET;
+ callret.val = 0;
+
+ result = call_handler( msg->caller, msg->call_arg, msg->call_ptr, msg->ctx, msg->serial, &callret.val );
+ switch (result) {
+ case FCHR_RETURN:
+ if (!(msg->flags & FCEF_ONEWAY)) {
+ struct sockaddr_un addr;
+
+ addr.sun_family = AF_UNIX;
+ snprintf( addr.sun_path, sizeof(addr.sun_path),
+ "/tmp/.fusion-%d/call.%x.%x", fusion_world_index( world ), call_id, msg->serial );
+
+ if (_fusion_send_message( world->fusion_fd, &callret, sizeof(callret), &addr ))
+ D_ERROR( "Fusion/Call: Couldn't send call return (serial: 0x%08x)!\n", msg->serial );
+ }
+ break;
+
+ case FCHR_RETAIN:
+ break;
+
+ default:
+ D_BUG( "unknown result %d from call handler", result );
+ break;
+ }
+}
+
+#endif /* FUSION_BUILD_KERNEL */
+
+#else /* FUSION_BUILD_MULTI */
+
+DirectResult
+fusion_call_init (FusionCall *call,
+ FusionCallHandler handler,
+ void *ctx,
+ const FusionWorld *world)
+{
+ D_ASSERT( call != NULL );
+ D_ASSERT( call->handler == NULL );
+ D_ASSERT( handler != NULL );
+
+ /* Called locally. */
+ call->handler = handler;
+ call->ctx = ctx;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_call_execute (FusionCall *call,
+ FusionCallExecFlags flags,
+ int call_arg,
+ void *call_ptr,
+ int *ret_val)
+{
+ FusionCallHandlerResult ret;
+ int val = 0;
+
+ D_ASSERT( call != NULL );
+
+ if (!call->handler)
+ return DR_DESTROYED;
+
+ ret = call->handler( 1, call_arg, call_ptr, call->ctx, 0, &val );
+ if (ret != FCHR_RETURN)
+ D_WARN( "only FCHR_RETURN supported in single app core at the moment" );
+
+ if (ret_val)
+ *ret_val = val;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_call_return( FusionCall *call,
+ unsigned int serial,
+ int val )
+{
+ return DR_UNIMPLEMENTED;
+}
+
+DirectResult
+fusion_call_destroy (FusionCall *call)
+{
+ D_ASSERT( call != NULL );
+ D_ASSERT( call->handler != NULL );
+
+ call->handler = NULL;
+
+ return DR_OK;
+}
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/call.h b/Source/DirectFB/lib/fusion/call.h
new file mode 100755
index 0000000..e513696
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/call.h
@@ -0,0 +1,74 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__CALL_H__
+#define __FUSION__CALL_H__
+
+#include <fusion/types.h>
+
+typedef enum {
+ FCHR_RETURN,
+ FCHR_RETAIN
+} FusionCallHandlerResult;
+
+typedef FusionCallHandlerResult (*FusionCallHandler) (int caller, /* fusion id of the caller */
+ int call_arg, /* optional call parameter */
+ void *call_ptr, /* optional call parameter */
+ void *ctx, /* optional handler context */
+ unsigned int serial,
+ int *ret_val );
+
+typedef struct {
+ FusionWorldShared *shared;
+ int call_id;
+ FusionID fusion_id;
+ FusionCallHandler handler;
+ void *ctx;
+} FusionCall;
+
+
+DirectResult fusion_call_init ( FusionCall *call,
+ FusionCallHandler handler,
+ void *ctx,
+ const FusionWorld *world );
+
+DirectResult fusion_call_execute( FusionCall *call,
+ FusionCallExecFlags flags,
+ int call_arg,
+ void *call_ptr,
+ int *ret_val );
+
+DirectResult fusion_call_return ( FusionCall *call,
+ unsigned int serial,
+ int val );
+
+DirectResult fusion_call_destroy( FusionCall *call );
+
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/conf.c b/Source/DirectFB/lib/fusion/conf.c
new file mode 100755
index 0000000..017364f
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/conf.c
@@ -0,0 +1,113 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#include <stddef.h>
+#include <string.h>
+#include <grp.h>
+
+#include <direct/conf.h>
+#include <direct/mem.h>
+#include <direct/messages.h>
+
+#include <fusion/conf.h>
+
+
+static FusionConfig config = {
+ .tmpfs = NULL,
+ .shmfile_gid = -1,
+};
+
+FusionConfig *fusion_config = &config;
+const char *fusion_config_usage =
+ "libfusion options:\n"
+ " force-slave Always enter as a slave, waiting for the master, if not there\n"
+ " tmpfs=<directory> Location of shared memory file\n"
+ " shmfile-group=<groupname> Group that owns shared memory files\n"
+ " [no-]debugshm Enable shared memory allocation tracking\n"
+ " [no-]madv-remove Enable usage of MADV_REMOVE (default = auto)\n"
+ "\n";
+
+/**********************************************************************************************************************/
+
+DirectResult
+fusion_config_set( const char *name, const char *value )
+{
+ if (strcmp (name, "tmpfs" ) == 0) {
+ if (value) {
+ if (fusion_config->tmpfs)
+ D_FREE( fusion_config->tmpfs );
+ fusion_config->tmpfs = D_STRDUP( value );
+ }
+ else {
+ D_ERROR("Fusion/Config 'tmpfs': No directory specified!\n");
+ return DR_INVARG;
+ }
+ } else
+ if (strcmp (name, "shmfile-group" ) == 0) {
+ if (value) {
+ struct group *group_info;
+
+ group_info = getgrnam( value );
+ if (group_info)
+ fusion_config->shmfile_gid = group_info->gr_gid;
+ else
+ D_PERROR("Fusion/Config 'shmfile-group': Group '%s' not found!\n", value);
+ }
+ else {
+ D_ERROR("Fusion/Config 'shmfile-group': No file group name specified!\n");
+ return DR_INVARG;
+ }
+ } else
+ if (strcmp (name, "force-slave" ) == 0) {
+ fusion_config->force_slave = true;
+ } else
+ if (strcmp (name, "no-force-slave" ) == 0) {
+ fusion_config->force_slave = false;
+ } else
+ if (strcmp (name, "debugshm" ) == 0) {
+ fusion_config->debugshm = true;
+ } else
+ if (strcmp (name, "no-debugshm" ) == 0) {
+ fusion_config->debugshm = false;
+ } else
+ if (strcmp (name, "madv-remove" ) == 0) {
+ fusion_config->madv_remove = true;
+ fusion_config->madv_remove_force = true;
+ } else
+ if (strcmp (name, "no-madv-remove" ) == 0) {
+ fusion_config->madv_remove = false;
+ fusion_config->madv_remove_force = true;
+ } else
+ if (direct_config_set( name, value ))
+ return DR_UNSUPPORTED;
+
+ return DR_OK;
+}
+
diff --git a/Source/DirectFB/lib/fusion/conf.h b/Source/DirectFB/lib/fusion/conf.h
new file mode 100755
index 0000000..0cdf9a2
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/conf.h
@@ -0,0 +1,55 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__CONF_H__
+#define __FUSION__CONF_H__
+
+
+#include <fusion/types.h>
+
+struct __Fusion_FusionConfig {
+ char *tmpfs; /* location of shm file */
+
+ bool debugshm;
+ bool madv_remove;
+ bool madv_remove_force;
+ bool force_slave;
+
+ gid_t shmfile_gid; /* group that owns shm file */
+};
+
+extern FusionConfig *fusion_config;
+
+extern const char *fusion_config_usage;
+
+
+DirectResult fusion_config_set( const char *name, const char *value );
+
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/fusion.c b/Source/DirectFB/lib/fusion/fusion.c
new file mode 100755
index 0000000..2812f20
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/fusion.c
@@ -0,0 +1,2658 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <time.h>
+#include <fcntl.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/utsname.h>
+
+#include <direct/clock.h>
+#include <direct/debug.h>
+#include <direct/direct.h>
+#include <direct/mem.h>
+#include <direct/messages.h>
+#include <direct/signals.h>
+#include <direct/thread.h>
+#include <direct/trace.h>
+#include <direct/util.h>
+
+#include <fusion/build.h>
+#include <fusion/conf.h>
+#include <fusion/types.h>
+
+#include "fusion_internal.h"
+
+#include <fusion/shmalloc.h>
+
+#include <fusion/shm/shm.h>
+
+
+#if FUSION_BUILD_MULTI
+
+D_DEBUG_DOMAIN( Fusion_Main, "Fusion/Main", "Fusion - High level IPC" );
+D_DEBUG_DOMAIN( Fusion_Main_Dispatch, "Fusion/Main/Dispatch", "Fusion - High level IPC Dispatch" );
+
+/**********************************************************************************************************************/
+
+static void *fusion_dispatch_loop ( DirectThread *thread,
+ void *arg );
+
+/**********************************************************************************************************************/
+
+static void fusion_fork_handler_prepare( void );
+static void fusion_fork_handler_parent( void );
+static void fusion_fork_handler_child( void );
+
+/**********************************************************************************************************************/
+
+static FusionWorld *fusion_worlds[FUSION_MAX_WORLDS];
+static pthread_mutex_t fusion_worlds_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_once_t fusion_init_once = PTHREAD_ONCE_INIT;
+
+/**********************************************************************************************************************/
+
+int
+_fusion_fd( const FusionWorldShared *shared )
+{
+ int index;
+ FusionWorld *world;
+
+// D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ index = shared->world_index;
+
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < FUSION_MAX_WORLDS );
+
+ world = fusion_worlds[index];
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return world->fusion_fd;
+}
+
+FusionID
+_fusion_id( const FusionWorldShared *shared )
+{
+ int index;
+ FusionWorld *world;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ index = shared->world_index;
+
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < FUSION_MAX_WORLDS );
+
+ world = fusion_worlds[index];
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return world->fusion_id;
+}
+
+FusionWorld *
+_fusion_world( const FusionWorldShared *shared )
+{
+ int index;
+ FusionWorld *world;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ index = shared->world_index;
+
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < FUSION_MAX_WORLDS );
+
+ world = fusion_worlds[index];
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return world;
+}
+
+/**********************************************************************************************************************/
+
+static void
+init_once( void )
+{
+ struct utsname uts;
+ int i, j, k, l;
+
+ pthread_atfork( fusion_fork_handler_prepare, fusion_fork_handler_parent, fusion_fork_handler_child );
+
+ if (uname( &uts ) < 0) {
+ D_PERROR( "Fusion/Init: uname() failed!\n" );
+ return;
+ }
+
+#if !FUSION_BUILD_KERNEL
+ D_INFO( "Fusion/Init: "
+ "Builtin Implementation is still experimental! Crash/Deadlocks might occur!\n" );
+#endif
+
+ if (fusion_config->madv_remove_force) {
+ if (fusion_config->madv_remove)
+ D_INFO( "Fusion/SHM: Using MADV_REMOVE (forced)\n" );
+ else
+ D_INFO( "Fusion/SHM: Not using MADV_REMOVE (forced)!\n" );
+ }
+ else {
+ switch (sscanf( uts.release, "%d.%d.%d.%d", &i, &j, &k, &l )) {
+ case 3:
+ l = 0;
+ case 4:
+ if (((i << 24) | (j << 16) | (k << 8) | l) >= 0x02061302)
+ fusion_config->madv_remove = true;
+ break;
+
+ default:
+ D_WARN( "could not parse kernel version '%s'", uts.release );
+ }
+
+ if (fusion_config->madv_remove)
+ D_INFO( "Fusion/SHM: Using MADV_REMOVE (%d.%d.%d.%d >= 2.6.19.2)\n", i, j, k, l );
+ else
+ D_INFO( "Fusion/SHM: NOT using MADV_REMOVE (%d.%d.%d.%d < 2.6.19.2)! [0x%08x]\n",
+ i, j, k, l, (i << 24) | (j << 16) | (k << 8) | l );
+ }
+}
+
+/**********************************************************************************************************************/
+
+#if FUSION_BUILD_KERNEL
+
+static void
+fusion_world_fork( FusionWorld *world )
+{
+ int fd;
+ char buf1[20];
+ char buf2[20];
+ FusionEnter enter;
+ FusionFork fork;
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ snprintf( buf1, sizeof(buf1), "/dev/fusion%d", shared->world_index );
+ snprintf( buf2, sizeof(buf2), "/dev/fusion/%d", shared->world_index );
+
+ /* Open Fusion Kernel Device. */
+ fd = direct_try_open( buf1, buf2, O_RDWR | O_NONBLOCK, true );
+ if (fd < 0) {
+ D_PERROR( "Fusion/Main: Reopening fusion device (world %d) failed!\n", shared->world_index );
+ raise(5);
+ }
+
+ /* Drop "identity" when running another program. */
+ if (fcntl( fd, F_SETFD, FD_CLOEXEC ) < 0)
+ D_PERROR( "Fusion/Init: Setting FD_CLOEXEC flag failed!\n" );
+
+ /* Fill enter information. */
+ enter.api.major = FUSION_API_MAJOR_REQUIRED;
+ enter.api.minor = FUSION_API_MINOR_REQUIRED;
+ enter.fusion_id = 0; /* Clear for check below. */
+
+ /* Enter the fusion world. */
+ while (ioctl( fd, FUSION_ENTER, &enter )) {
+ if (errno != EINTR) {
+ D_PERROR( "Fusion/Init: Could not reenter world '%d'!\n", shared->world_index );
+ raise(5);
+ }
+ }
+
+ /* Check for valid Fusion ID. */
+ if (!enter.fusion_id) {
+ D_ERROR( "Fusion/Init: Got no ID from FUSION_ENTER! Kernel module might be too old.\n" );
+ raise(5);
+ }
+
+ D_DEBUG_AT( Fusion_Main, " -> Fusion ID 0x%08lx\n", enter.fusion_id );
+
+
+ /* Fill fork information. */
+ fork.fusion_id = world->fusion_id;
+
+ /* Fork within the fusion world. */
+ while (ioctl( fd, FUSION_FORK, &fork )) {
+ if (errno != EINTR) {
+ D_PERROR( "Fusion/Main: Could not fork in world '%d'!\n", shared->world_index );
+ raise(5);
+ }
+ }
+
+ D_DEBUG_AT( Fusion_Main, " -> Fusion ID 0x%08lx\n", fork.fusion_id );
+
+ /* Get new fusion id back. */
+ world->fusion_id = fork.fusion_id;
+
+ /* Close old file descriptor. */
+ close( world->fusion_fd );
+
+ /* Write back new file descriptor. */
+ world->fusion_fd = fd;
+
+
+ D_DEBUG_AT( Fusion_Main, " -> restarting dispatcher loop...\n" );
+
+ /* Restart the dispatcher thread. FIXME: free old struct */
+ world->dispatch_loop = direct_thread_create( DTT_MESSAGING,
+ fusion_dispatch_loop,
+ world, "Fusion Dispatch" );
+ if (!world->dispatch_loop)
+ raise(5);
+}
+
+static void
+fusion_fork_handler_prepare( void )
+{
+ int i;
+
+ D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ );
+
+ for (i=0; i<FUSION_MAX_WORLDS; i++) {
+ FusionWorld *world = fusion_worlds[i];
+
+ if (!world)
+ continue;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ if (world->fork_callback)
+ world->fork_callback( world->fork_action, FFS_PREPARE );
+ }
+}
+
+static void
+fusion_fork_handler_parent( void )
+{
+ int i;
+
+ D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ );
+
+ for (i=0; i<FUSION_MAX_WORLDS; i++) {
+ FusionWorld *world = fusion_worlds[i];
+ FusionWorldShared *shared;
+
+ if (!world)
+ continue;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ if (world->fork_callback)
+ world->fork_callback( world->fork_action, FFS_PARENT );
+
+ if (world->fork_action == FFA_FORK) {
+ /* Increase the shared reference counter. */
+ if (fusion_master( world ))
+ shared->refs++;
+ }
+ }
+}
+
+static void
+fusion_fork_handler_child( void )
+{
+ int i;
+
+ D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ );
+
+ for (i=0; i<FUSION_MAX_WORLDS; i++) {
+ FusionWorld *world = fusion_worlds[i];
+
+ if (!world)
+ continue;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ if (world->fork_callback)
+ world->fork_callback( world->fork_action, FFS_CHILD );
+
+ switch (world->fork_action) {
+ default:
+ D_BUG( "unknown fork action %d", world->fork_action );
+
+ case FFA_CLOSE:
+ D_DEBUG_AT( Fusion_Main, " -> closing world %d\n", i );
+
+ /* Remove world from global list. */
+ fusion_worlds[i] = NULL;
+
+ /* Unmap shared area. */
+ munmap( world->shared, sizeof(FusionWorldShared) );
+
+ /* Close Fusion Kernel Device. */
+ close( world->fusion_fd );
+
+ /* Free local world data. */
+ D_MAGIC_CLEAR( world );
+ D_FREE( world );
+
+ break;
+
+ case FFA_FORK:
+ D_DEBUG_AT( Fusion_Main, " -> forking in world %d\n", i );
+
+ fusion_world_fork( world );
+
+ break;
+ }
+ }
+}
+
+/**********************************************************************************************************************/
+
+/*
+ * Enters a fusion world by joining or creating it.
+ *
+ * If <b>world</b> is negative, the next free index is used to create a new world.
+ * Otherwise the world with the specified index is joined or created.
+ */
+DirectResult
+fusion_enter( int world_index,
+ int abi_version,
+ FusionEnterRole role,
+ FusionWorld **ret_world )
+{
+ DirectResult ret = DR_OK;
+ int fd = -1;
+ FusionWorld *world = NULL;
+ FusionWorldShared *shared = NULL;
+ FusionEnter enter;
+ char buf1[20];
+ char buf2[20];
+
+ D_DEBUG_AT( Fusion_Main, "%s( %d, %d, %p )\n", __FUNCTION__, world_index, abi_version, ret_world );
+
+ D_ASSERT( ret_world != NULL );
+
+ if (world_index >= FUSION_MAX_WORLDS) {
+ D_ERROR( "Fusion/Init: World index %d exceeds maximum index %d!\n", world_index, FUSION_MAX_WORLDS - 1 );
+ return DR_INVARG;
+ }
+
+ pthread_once( &fusion_init_once, init_once );
+
+
+ if (fusion_config->force_slave)
+ role = FER_SLAVE;
+
+ direct_initialize();
+
+ pthread_mutex_lock( &fusion_worlds_lock );
+
+
+ if (world_index < 0) {
+ if (role == FER_SLAVE) {
+ D_ERROR( "Fusion/Init: Slave role and a new world (index -1) was requested!\n" );
+ pthread_mutex_unlock( &fusion_worlds_lock );
+ return DR_INVARG;
+ }
+
+ for (world_index=0; world_index<FUSION_MAX_WORLDS; world_index++) {
+ world = fusion_worlds[world_index];
+ if (world)
+ break;
+
+ snprintf( buf1, sizeof(buf1), "/dev/fusion%d", world_index );
+ snprintf( buf2, sizeof(buf2), "/dev/fusion/%d", world_index );
+
+ /* Open Fusion Kernel Device. */
+ fd = direct_try_open( buf1, buf2, O_RDWR | O_NONBLOCK | O_EXCL, false );
+ if (fd < 0) {
+ if (errno != EBUSY)
+ D_PERROR( "Fusion/Init: Error opening '%s' and/or '%s'!\n", buf1, buf2 );
+ }
+ else
+ break;
+ }
+ }
+ else {
+ world = fusion_worlds[world_index];
+ if (!world) {
+ int flags = O_RDWR | O_NONBLOCK;
+
+ snprintf( buf1, sizeof(buf1), "/dev/fusion%d", world_index );
+ snprintf( buf2, sizeof(buf2), "/dev/fusion/%d", world_index );
+
+ if (role == FER_MASTER)
+ flags |= O_EXCL;
+ else if (role == FER_SLAVE)
+ flags |= O_APPEND;
+
+ /* Open Fusion Kernel Device. */
+ fd = direct_try_open( buf1, buf2, flags, true );
+ }
+ }
+
+ /* Enter a world again? */
+ if (world) {
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_ASSERT( world->refs > 0 );
+
+ /* Check the role again. */
+ switch (role) {
+ case FER_MASTER:
+ if (world->fusion_id != FUSION_ID_MASTER) {
+ D_ERROR( "Fusion/Init: Master role requested for a world (%d) "
+ "we're already slave in!\n", world_index );
+ ret = DR_UNSUPPORTED;
+ goto error;
+ }
+ break;
+
+ case FER_SLAVE:
+ if (world->fusion_id == FUSION_ID_MASTER) {
+ D_ERROR( "Fusion/Init: Slave role requested for a world (%d) "
+ "we're already master in!\n", world_index );
+ ret = DR_UNSUPPORTED;
+ goto error;
+ }
+ break;
+
+ case FER_ANY:
+ break;
+ }
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ if (shared->world_abi != abi_version) {
+ D_ERROR( "Fusion/Init: World ABI (%d) of world '%d' doesn't match own (%d)!\n",
+ shared->world_abi, world_index, abi_version );
+ ret = DR_VERSIONMISMATCH;
+ goto error;
+ }
+
+ world->refs++;
+
+ pthread_mutex_unlock( &fusion_worlds_lock );
+
+ D_DEBUG_AT( Fusion_Main, " -> using existing world %p [%d]\n", world, world_index );
+
+ /* Return the world. */
+ *ret_world = world;
+
+ return DR_OK;
+ }
+
+ if (fd < 0) {
+ D_PERROR( "Fusion/Init: Opening fusion device (world %d) as '%s' failed!\n", world_index,
+ role == FER_ANY ? "any" : (role == FER_MASTER ? "master" : "slave") );
+ ret = DR_INIT;
+ goto error;
+ }
+
+ /* Drop "identity" when running another program. */
+ if (fcntl( fd, F_SETFD, FD_CLOEXEC ) < 0)
+ D_PERROR( "Fusion/Init: Setting FD_CLOEXEC flag failed!\n" );
+
+ /* Fill enter information. */
+ enter.api.major = FUSION_API_MAJOR_REQUIRED;
+ enter.api.minor = FUSION_API_MINOR_REQUIRED;
+ enter.fusion_id = 0; /* Clear for check below. */
+
+ /* Enter the fusion world. */
+ while (ioctl( fd, FUSION_ENTER, &enter )) {
+ if (errno != EINTR) {
+ D_PERROR( "Fusion/Init: Could not enter world '%d'!\n", world_index );
+ ret = DR_INIT;
+ goto error;
+ }
+ }
+
+ /* Check for valid Fusion ID. */
+ if (!enter.fusion_id) {
+ D_ERROR( "Fusion/Init: Got no ID from FUSION_ENTER! Kernel module might be too old.\n" );
+ ret = DR_INIT;
+ goto error;
+ }
+
+ D_DEBUG_AT( Fusion_Main, " -> Fusion ID 0x%08lx\n", enter.fusion_id );
+
+ /* Check slave role only, master is handled by O_EXCL earlier. */
+ if (role == FER_SLAVE && enter.fusion_id == FUSION_ID_MASTER) {
+ D_PERROR( "Fusion/Init: Entering world '%d' as a slave failed!\n", world_index );
+ ret = DR_UNSUPPORTED;
+ goto error;
+ }
+
+ /* Map shared area. */
+ shared = mmap( (void*) 0x20000000 + 0x2000 * world_index, sizeof(FusionWorldShared),
+ PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, fd, 0 );
+ if (shared == MAP_FAILED) {
+ D_PERROR( "Fusion/Init: Mapping shared area failed!\n" );
+ goto error;
+ }
+
+ D_DEBUG_AT( Fusion_Main, " -> shared area at %p, size %zu\n", shared, sizeof(FusionWorldShared) );
+
+ /* Initialize shared data. */
+ if (enter.fusion_id == FUSION_ID_MASTER) {
+ /* Initialize reference counter. */
+ shared->refs = 1;
+
+ /* Set ABI version. */
+ shared->world_abi = abi_version;
+
+ /* Set the world index. */
+ shared->world_index = world_index;
+
+ /* Set start time of world clock. */
+ direct_monotonic_gettimeofday( &shared->start_time );
+
+ D_MAGIC_SET( shared, FusionWorldShared );
+ }
+ else {
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ /* Check ABI version. */
+ if (shared->world_abi != abi_version) {
+ D_ERROR( "Fusion/Init: World ABI (%d) doesn't match own (%d)!\n",
+ shared->world_abi, abi_version );
+ ret = DR_VERSIONMISMATCH;
+ goto error;
+ }
+ }
+
+ /* Synchronize to world clock. */
+ direct_clock_set_start( &shared->start_time );
+
+
+ /* Allocate local data. */
+ world = D_CALLOC( 1, sizeof(FusionWorld) );
+ if (!world) {
+ ret = D_OOM();
+ goto error;
+ }
+
+ /* Initialize local data. */
+ world->refs = 1;
+ world->shared = shared;
+ world->fusion_fd = fd;
+ world->fusion_id = enter.fusion_id;
+
+ D_MAGIC_SET( world, FusionWorld );
+
+ fusion_worlds[world_index] = world;
+
+
+ /* Initialize shared memory part. */
+ ret = fusion_shm_init( world );
+ if (ret)
+ goto error2;
+
+
+ D_DEBUG_AT( Fusion_Main, " -> initializing other parts...\n" );
+
+ /* Initialize other parts. */
+ if (enter.fusion_id == FUSION_ID_MASTER) {
+ fusion_skirmish_init( &shared->arenas_lock, "Fusion Arenas", world );
+ fusion_skirmish_init( &shared->reactor_globals, "Fusion Reactor Globals", world );
+
+ /* Create the main pool. */
+ ret = fusion_shm_pool_create( world, "Fusion Main Pool", 0x100000,
+ fusion_config->debugshm, &shared->main_pool );
+ if (ret)
+ goto error3;
+ }
+
+
+ D_DEBUG_AT( Fusion_Main, " -> starting dispatcher loop...\n" );
+
+ /* Start the dispatcher thread. */
+ world->dispatch_loop = direct_thread_create( DTT_MESSAGING,
+ fusion_dispatch_loop,
+ world, "Fusion Dispatch" );
+ if (!world->dispatch_loop) {
+ ret = DR_FAILURE;
+ goto error4;
+ }
+
+
+ /* Let others enter the world. */
+ if (enter.fusion_id == FUSION_ID_MASTER) {
+ D_DEBUG_AT( Fusion_Main, " -> unblocking world...\n" );
+
+ while (ioctl( fd, FUSION_UNBLOCK )) {
+ if (errno != EINTR) {
+ D_PERROR( "Fusion/Init: Could not unblock world!\n" );
+ ret = DR_FUSION;
+ goto error4;
+ }
+ }
+ }
+
+ D_DEBUG_AT( Fusion_Main, " -> done. (%p)\n", world );
+
+ pthread_mutex_unlock( &fusion_worlds_lock );
+
+ /* Return the fusion world. */
+ *ret_world = world;
+
+ return DR_OK;
+
+
+error4:
+ if (world->dispatch_loop)
+ direct_thread_destroy( world->dispatch_loop );
+
+ if (enter.fusion_id == FUSION_ID_MASTER)
+ fusion_shm_pool_destroy( world, shared->main_pool );
+
+error3:
+ if (enter.fusion_id == FUSION_ID_MASTER) {
+ fusion_skirmish_destroy( &shared->arenas_lock );
+ fusion_skirmish_destroy( &shared->reactor_globals );
+ }
+
+ fusion_shm_deinit( world );
+
+
+error2:
+ fusion_worlds[world_index] = world;
+
+ D_MAGIC_CLEAR( world );
+
+ D_FREE( world );
+
+error:
+ if (shared && shared != MAP_FAILED) {
+ if (enter.fusion_id == FUSION_ID_MASTER)
+ D_MAGIC_CLEAR( shared );
+
+ munmap( shared, sizeof(FusionWorldShared) );
+ }
+
+ if (fd != -1)
+ close( fd );
+
+ pthread_mutex_unlock( &fusion_worlds_lock );
+
+ direct_shutdown();
+
+ return ret;
+}
+
+DirectResult
+fusion_stop_dispatcher( FusionWorld *world,
+ bool emergency )
+{
+ if (!emergency) {
+ fusion_sync( world );
+
+ direct_thread_lock( world->dispatch_loop );
+ }
+
+ world->dispatch_stop = true;
+
+ if (!emergency) {
+ direct_thread_unlock( world->dispatch_loop );
+
+ fusion_sync( world );
+ }
+
+ return DR_OK;
+}
+
+/*
+ * Exits the fusion world.
+ *
+ * If 'emergency' is true the function won't join but kill the dispatcher thread.
+ */
+DirectResult
+fusion_exit( FusionWorld *world,
+ bool emergency )
+{
+ FusionWorldShared *shared;
+
+ D_DEBUG_AT( Fusion_Main, "%s( %p, %semergency )\n", __FUNCTION__, world, emergency ? "" : "no " );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+
+ pthread_mutex_lock( &fusion_worlds_lock );
+
+ D_ASSERT( world->refs > 0 );
+
+ if (--world->refs) {
+ pthread_mutex_unlock( &fusion_worlds_lock );
+ return DR_OK;
+ }
+
+ if (!emergency) {
+ int foo;
+ FusionSendMessage msg;
+
+ /* Wake up the read loop thread. */
+ msg.fusion_id = world->fusion_id;
+ msg.msg_id = 0;
+ msg.msg_data = &foo;
+ msg.msg_size = sizeof(foo);
+
+ while (ioctl( world->fusion_fd, FUSION_SEND_MESSAGE, &msg ) < 0) {
+ if (errno != EINTR) {
+ D_PERROR( "FUSION_SEND_MESSAGE" );
+ direct_thread_cancel( world->dispatch_loop );
+ break;
+ }
+ }
+
+ /* Wait for its termination. */
+ direct_thread_join( world->dispatch_loop );
+ }
+
+ direct_thread_destroy( world->dispatch_loop );
+
+ /* Master has to deinitialize shared data. */
+ if (fusion_master( world )) {
+ shared->refs--;
+ if (shared->refs == 0) {
+ fusion_skirmish_destroy( &shared->reactor_globals );
+ fusion_skirmish_destroy( &shared->arenas_lock );
+
+ fusion_shm_pool_destroy( world, shared->main_pool );
+
+ /* Deinitialize shared memory. */
+ fusion_shm_deinit( world );
+ }
+ }
+ else {
+ /* Leave shared memory. */
+ fusion_shm_deinit( world );
+ }
+
+ /* Reset local dispatch nodes. */
+ _fusion_reactor_free_all( world );
+
+
+ /* Remove world from global list. */
+ fusion_worlds[shared->world_index] = NULL;
+
+
+ /* Unmap shared area. */
+ if (fusion_master( world ) && shared->refs == 0)
+ D_MAGIC_CLEAR( shared );
+
+ munmap( shared, sizeof(FusionWorldShared) );
+
+
+ /* Close Fusion Kernel Device. */
+ close( world->fusion_fd );
+
+
+ /* Free local world data. */
+ D_MAGIC_CLEAR( world );
+ D_FREE( world );
+
+
+ pthread_mutex_unlock( &fusion_worlds_lock );
+
+ direct_shutdown();
+
+ return DR_OK;
+}
+
+/*
+ * Sends a signal to one or more fusionees and optionally waits
+ * for their processes to terminate.
+ *
+ * A fusion_id of zero means all fusionees but the calling one.
+ * A timeout of zero means infinite waiting while a negative value
+ * means no waiting at all.
+ */
+DirectResult
+fusion_kill( FusionWorld *world,
+ FusionID fusion_id,
+ int signal,
+ int timeout_ms )
+{
+ FusionKill param;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ param.fusion_id = fusion_id;
+ param.signal = signal;
+ param.timeout_ms = timeout_ms;
+
+ while (ioctl( world->fusion_fd, FUSION_KILL, &param )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case ETIMEDOUT:
+ return DR_TIMEOUT;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_KILL");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+/**********************************************************************************************************************/
+
+static void *
+fusion_dispatch_loop( DirectThread *thread, void *arg )
+{
+ int len = 0;
+ int result;
+ char buf[FUSION_MESSAGE_SIZE];
+ fd_set set;
+ FusionWorld *world = arg;
+
+ D_DEBUG_AT( Fusion_Main_Dispatch, "%s() running...\n", __FUNCTION__ );
+
+ while (true) {
+ char *buf_p = buf;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ FD_ZERO( &set );
+ FD_SET( world->fusion_fd, &set );
+
+ result = select( world->fusion_fd + 1, &set, NULL, NULL, NULL );
+ if (result < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ default:
+ D_PERROR( "Fusion/Dispatcher: select() failed!\n" );
+ return NULL;
+ }
+ }
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ if (FD_ISSET( world->fusion_fd, &set )) {
+ len = read( world->fusion_fd, buf, FUSION_MESSAGE_SIZE );
+ if (len < 0)
+ break;
+
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> got %d bytes...\n", len );
+
+ direct_thread_lock( world->dispatch_loop );
+
+ if (world->dispatch_stop) {
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> IGNORING (dispatch_stop!)\n" );
+ }
+ else {
+ while (buf_p < buf + len) {
+ FusionReadMessage *header = (FusionReadMessage*) buf_p;
+ void *data = buf_p + sizeof(FusionReadMessage);
+
+ if (world->dispatch_stop) {
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> ABORTING (dispatch_stop!)\n" );
+ break;
+ }
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_ASSERT( (buf + len - buf_p) >= sizeof(FusionReadMessage) );
+
+ switch (header->msg_type) {
+ case FMT_SEND:
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SEND!\n" );
+ break;
+ case FMT_CALL:
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_CALL...\n" );
+ _fusion_call_process( world, header->msg_id, data );
+ break;
+ case FMT_REACTOR:
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_REACTOR...\n" );
+ _fusion_reactor_process_message( world, header->msg_id, header->msg_channel, data );
+ break;
+ case FMT_SHMPOOL:
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SHMPOOL...\n" );
+ _fusion_shmpool_process( world, header->msg_id, data );
+ break;
+ default:
+ D_DEBUG( "Fusion/Receiver: discarding message of unknown type '%d'\n",
+ header->msg_type );
+ break;
+ }
+
+ buf_p = data + ((header->msg_size + 3) & ~3);
+ }
+ }
+
+ direct_thread_unlock( world->dispatch_loop );
+
+ if (!world->refs) {
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> good bye!\n" );
+ return NULL;
+ }
+ }
+ }
+
+ D_PERROR( "Fusion/Receiver: reading from fusion device failed!\n" );
+
+ return NULL;
+}
+
+/**********************************************************************************************************************/
+
+#else /* FUSION_BUILD_KERNEL */
+
+#include <dirent.h>
+
+#include <direct/system.h>
+
+typedef struct {
+ DirectLink link;
+
+ FusionRef *ref;
+
+ int count;
+} __FusioneeRef;
+
+typedef struct {
+ DirectLink link;
+
+ FusionID id;
+ pid_t pid;
+
+ DirectLink *refs;
+} __Fusionee;
+
+
+/**********************************************************************************************************************/
+
+static DirectResult
+_fusion_add_fusionee( FusionWorld *world, FusionID fusion_id )
+{
+ DirectResult ret;
+ FusionWorldShared *shared;
+ __Fusionee *fusionee;
+
+ D_DEBUG_AT( Fusion_Main, "%s( %p, %lu )\n", __FUNCTION__, world, fusion_id );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ fusionee = SHCALLOC( shared->main_pool, 1, sizeof(__Fusionee) );
+ if (!fusionee)
+ return D_OOSHM();
+
+ fusionee->id = fusion_id;
+ fusionee->pid = direct_gettid();
+
+ ret = fusion_skirmish_prevail( &shared->fusionees_lock );
+ if (ret) {
+ SHFREE( shared->main_pool, fusionee );
+ return ret;
+ }
+
+ direct_list_append( &shared->fusionees, &fusionee->link );
+
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+
+ /* Set local pointer. */
+ world->fusionee = fusionee;
+
+ return DR_OK;
+}
+
+void
+_fusion_add_local( FusionWorld *world, FusionRef *ref, int add )
+{
+ FusionWorldShared *shared;
+ __Fusionee *fusionee;
+ __FusioneeRef *fusionee_ref;
+
+ //D_DEBUG_AT( Fusion_Main, "%s( %p, %p, %d )\n", __FUNCTION__, world, ref, add );
+
+ D_ASSERT( ref != NULL );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ fusionee = world->fusionee;
+
+ D_ASSERT( fusionee != NULL );
+
+ direct_list_foreach (fusionee_ref, fusionee->refs) {
+ if (fusionee_ref->ref == ref)
+ break;
+ }
+
+ if (fusionee_ref) {
+ fusionee_ref->count += add;
+
+ //D_DEBUG_AT( Fusion_Main, " -> refs = %d\n", fusionee_ref->count );
+
+ if (fusionee_ref->count == 0) {
+ direct_list_remove( &fusionee->refs, &fusionee_ref->link );
+ SHFREE( shared->main_pool, fusionee_ref );
+ }
+ }
+ else {
+ if (add <= 0) /* called from _fusion_remove_fusionee() */
+ return;
+
+ //D_DEBUG_AT( Fusion_Main, " -> new ref\n" );
+
+ fusionee_ref = SHCALLOC( shared->main_pool, 1, sizeof(__FusioneeRef) );
+ if (!fusionee_ref) {
+ D_OOSHM();
+ return;
+ }
+
+ fusionee_ref->ref = ref;
+ fusionee_ref->count = add;
+
+ direct_list_prepend( &fusionee->refs, &fusionee_ref->link );
+ }
+}
+
+void
+_fusion_check_locals( FusionWorld *world, FusionRef *ref )
+{
+ FusionWorldShared *shared;
+ __Fusionee *fusionee;
+ __FusioneeRef *fusionee_ref, *temp;
+ DirectLink *list = NULL;
+
+ D_DEBUG_AT( Fusion_Main, "%s( %p, %p )\n", __FUNCTION__, world, ref );
+
+ D_ASSERT( ref != NULL );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ if (fusion_skirmish_prevail( &shared->fusionees_lock ))
+ return;
+
+ direct_list_foreach (fusionee, shared->fusionees) {
+ if (fusionee->id == world->fusion_id)
+ continue;
+
+ direct_list_foreach (fusionee_ref, fusionee->refs) {
+ if (fusionee_ref->ref == ref) {
+ if (kill( fusionee->pid, 0 ) < 0 && errno == ESRCH) {
+ direct_list_remove( &fusionee->refs, &fusionee_ref->link );
+ direct_list_append( &list, &fusionee_ref->link );
+ }
+ break;
+ }
+ }
+ }
+
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+
+ direct_list_foreach_safe (fusionee_ref, temp, list) {
+ _fusion_ref_change( ref, -fusionee_ref->count, false );
+
+ SHFREE( shared->main_pool, fusionee_ref );
+ }
+}
+
+void
+_fusion_remove_all_locals( FusionWorld *world, const FusionRef *ref )
+{
+ FusionWorldShared *shared;
+ __Fusionee *fusionee;
+ __FusioneeRef *fusionee_ref, *temp;
+
+ D_DEBUG_AT( Fusion_Main, "%s( %p, %p )\n", __FUNCTION__, world, ref );
+
+ D_ASSERT( ref != NULL );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ if (fusion_skirmish_prevail( &shared->fusionees_lock ))
+ return;
+
+ direct_list_foreach (fusionee, shared->fusionees) {
+ direct_list_foreach_safe (fusionee_ref, temp, fusionee->refs) {
+ if (fusionee_ref->ref == ref) {
+ direct_list_remove( &fusionee->refs, &fusionee_ref->link );
+
+ SHFREE( shared->main_pool, fusionee_ref );
+ }
+ }
+ }
+
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+}
+
+static void
+_fusion_remove_fusionee( FusionWorld *world, FusionID fusion_id )
+{
+ FusionWorldShared *shared;
+ __Fusionee *fusionee;
+ __FusioneeRef *fusionee_ref, *temp;
+
+ D_DEBUG_AT( Fusion_Main, "%s( %p, %lu )\n", __FUNCTION__, world, fusion_id );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ fusion_skirmish_prevail( &shared->fusionees_lock );
+
+ if (fusion_id == world->fusion_id) {
+ fusionee = world->fusionee;
+ }
+ else {
+ direct_list_foreach (fusionee, shared->fusionees) {
+ if (fusionee->id == fusion_id)
+ break;
+ }
+ }
+
+ if (!fusionee) {
+ D_DEBUG_AT( Fusion_Main, "Fusionee %lu not found!\n", fusion_id );
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+ return;
+ }
+
+ direct_list_remove( &shared->fusionees, &fusionee->link );
+
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+
+ direct_list_foreach_safe (fusionee_ref, temp, fusionee->refs) {
+ direct_list_remove( &fusionee->refs, &fusionee_ref->link );
+
+ _fusion_ref_change( fusionee_ref->ref, -fusionee_ref->count, false );
+
+ SHFREE( shared->main_pool, fusionee_ref );
+ }
+
+ SHFREE( shared->main_pool, fusionee );
+}
+
+/**********************************************************************************************************************/
+
+DirectResult
+_fusion_send_message( int fd,
+ const void *msg,
+ size_t msg_size,
+ struct sockaddr_un *addr )
+{
+ socklen_t len = sizeof(struct sockaddr_un);
+
+ D_ASSERT( msg != NULL );
+
+ if (!addr) {
+ addr = alloca( sizeof(struct sockaddr_un) );
+ getsockname( fd, (struct sockaddr*)addr, &len );
+ }
+
+ while (sendto( fd, msg, msg_size, 0, (struct sockaddr*)addr, len ) < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case ECONNREFUSED:
+ return DR_FUSION;
+ default:
+ break;
+ }
+
+ D_PERROR( "Fusion: sendto()\n" );
+
+ return DR_IO;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+_fusion_recv_message( int fd,
+ void *msg,
+ size_t msg_size,
+ struct sockaddr_un *addr )
+{
+ socklen_t len = addr ? sizeof(struct sockaddr_un) : 0;
+
+ D_ASSERT( msg != NULL );
+
+ while (recvfrom( fd, msg, msg_size, 0, (struct sockaddr*)addr, &len ) < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case ECONNREFUSED:
+ return DR_FUSION;
+ default:
+ break;
+ }
+
+ D_PERROR( "Fusion: recvfrom()\n" );
+
+ return DR_IO;
+ }
+
+ return DR_OK;
+}
+
+/**********************************************************************************************************************/
+
+static void
+fusion_fork_handler_prepare( void )
+{
+ int i;
+
+ D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ );
+
+ for (i=0; i<FUSION_MAX_WORLDS; i++) {
+ FusionWorld *world = fusion_worlds[i];
+
+ if (!world)
+ continue;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ if (world->fork_callback)
+ world->fork_callback( world->fork_action, FFS_PREPARE );
+ }
+}
+
+static void
+fusion_fork_handler_parent( void )
+{
+ int i;
+
+ D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ );
+
+ for (i=0; i<FUSION_MAX_WORLDS; i++) {
+ FusionWorld *world = fusion_worlds[i];
+ FusionWorldShared *shared;
+
+ if (!world)
+ continue;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ if (world->fork_callback)
+ world->fork_callback( world->fork_action, FFS_PARENT );
+
+ if (world->fork_action == FFA_FORK) {
+ /* Increase the shared reference counter. */
+ if (fusion_master( world ))
+ shared->refs++;
+
+ /* Cancel the dispatcher to prevent conflicts. */
+ direct_thread_cancel( world->dispatch_loop );
+ }
+ }
+}
+
+static void
+fusion_fork_handler_child( void )
+{
+ int i;
+
+ D_DEBUG_AT( Fusion_Main, "%s()\n", __FUNCTION__ );
+
+ for (i=0; i<FUSION_MAX_WORLDS; i++) {
+ FusionWorld *world = fusion_worlds[i];
+ FusionWorldShared *shared;
+
+ if (!world)
+ continue;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ if (world->fork_callback)
+ world->fork_callback( world->fork_action, FFS_CHILD );
+
+ switch (world->fork_action) {
+ default:
+ D_BUG( "unknown fork action %d", world->fork_action );
+
+ case FFA_CLOSE:
+ D_DEBUG_AT( Fusion_Main, " -> closing world %d\n", i );
+
+ /* Remove world from global list. */
+ fusion_worlds[i] = NULL;
+
+ /* Unmap shared area. */
+ munmap( world->shared, sizeof(FusionWorldShared) );
+
+ /* Close socket. */
+ close( world->fusion_fd );
+
+ /* Free local world data. */
+ D_MAGIC_CLEAR( world );
+ D_FREE( world );
+
+ break;
+
+ case FFA_FORK: {
+ __Fusionee *fusionee;
+ __FusioneeRef *fusionee_ref;
+
+ D_DEBUG_AT( Fusion_Main, " -> forking in world %d\n", i );
+
+ fusionee = world->fusionee;
+
+ D_DEBUG_AT( Fusion_Main, " -> duplicating fusion id %lu\n", world->fusion_id );
+
+ fusion_skirmish_prevail( &shared->fusionees_lock );
+
+ if (_fusion_add_fusionee( world, world->fusion_id )) {
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+ raise( SIGTRAP );
+ }
+
+ D_DEBUG_AT( Fusion_Main, " -> duplicating local refs...\n" );
+
+ direct_list_foreach (fusionee_ref, fusionee->refs) {
+ __FusioneeRef *new_ref;
+
+ new_ref = SHCALLOC( shared->main_pool, 1, sizeof(__FusioneeRef) );
+ if (!new_ref) {
+ D_OOSHM();
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+ raise( SIGTRAP );
+ }
+
+ new_ref->ref = fusionee_ref->ref;
+ new_ref->count = fusionee_ref->count;
+ /* Avoid locking. */
+ new_ref->ref->multi.builtin.local += new_ref->count;
+
+ direct_list_append( &((__Fusionee*)world->fusionee)->refs, &new_ref->link );
+ }
+
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+
+ D_DEBUG_AT( Fusion_Main, " -> restarting dispatcher loop...\n" );
+
+ /* Restart the dispatcher thread. FIXME: free old struct */
+ world->dispatch_loop = direct_thread_create( DTT_MESSAGING,
+ fusion_dispatch_loop,
+ world, "Fusion Dispatch" );
+ if (!world->dispatch_loop)
+ raise( SIGTRAP );
+
+ } break;
+ }
+ }
+}
+
+/**********************************************************************************************************************/
+
+/*
+ * Enters a fusion world by joining or creating it.
+ *
+ * If <b>world</b> is negative, the next free index is used to create a new world.
+ * Otherwise the world with the specified index is joined or created.
+ */
+DirectResult
+fusion_enter( int world_index,
+ int abi_version,
+ FusionEnterRole role,
+ FusionWorld **ret_world )
+{
+ DirectResult ret = DR_OK;
+ int fd = -1;
+ FusionID id = -1;
+ FusionWorld *world = NULL;
+ FusionWorldShared *shared = MAP_FAILED;
+ struct sockaddr_un addr;
+ char buf[128];
+ int len, err;
+
+ D_DEBUG_AT( Fusion_Main, "%s( %d, %d, %p )\n", __FUNCTION__, world_index, abi_version, ret_world );
+
+ D_ASSERT( ret_world != NULL );
+
+ if (world_index >= FUSION_MAX_WORLDS) {
+ D_ERROR( "Fusion/Init: World index %d exceeds maximum index %d!\n", world_index, FUSION_MAX_WORLDS - 1 );
+ return DR_INVARG;
+ }
+
+ if (fusion_config->force_slave)
+ role = FER_SLAVE;
+
+ pthread_once( &fusion_init_once, init_once );
+
+ direct_initialize();
+
+ fd = socket( PF_LOCAL, SOCK_RAW, 0 );
+ if (fd < 0) {
+ D_PERROR( "Fusion/Init: Error creating local socket!\n" );
+ return DR_IO;
+ }
+
+ /* Set close-on-exec flag. */
+ if (fcntl( fd, F_SETFD, FD_CLOEXEC ) < 0)
+ D_PERROR( "Fusion/Init: Couldn't set close-on-exec flag!\n" );
+
+ pthread_mutex_lock( &fusion_worlds_lock );
+
+ addr.sun_family = AF_UNIX;
+
+ if (world_index < 0) {
+ if (role == FER_SLAVE) {
+ D_ERROR( "Fusion/Init: Slave role and a new world (index -1) was requested!\n" );
+ pthread_mutex_unlock( &fusion_worlds_lock );
+ close( fd );
+ return DR_INVARG;
+ }
+
+ for (world_index=0; world_index<FUSION_MAX_WORLDS; world_index++) {
+ if (fusion_worlds[world_index])
+ continue;
+
+ len = snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/", world_index );
+ /* Make socket directory if it doesn't exits. */
+ if (mkdir( addr.sun_path, 0775 ) == 0) {
+ chmod( addr.sun_path, 0775 );
+ if (fusion_config->shmfile_gid != (gid_t)-1)
+ chown( addr.sun_path, -1, fusion_config->shmfile_gid );
+ }
+
+ snprintf( addr.sun_path+len, sizeof(addr.sun_path)-len, "%lx", FUSION_ID_MASTER );
+
+ /* Bind to address. */
+ err = bind( fd, (struct sockaddr*)&addr, sizeof(addr) );
+ if (err == 0) {
+ chmod( addr.sun_path, 0660 );
+ /* Change group, if requested. */
+ if (fusion_config->shmfile_gid != (gid_t)-1)
+ chown( addr.sun_path, -1, fusion_config->shmfile_gid );
+ id = FUSION_ID_MASTER;
+ break;
+ }
+ }
+ }
+ else {
+ world = fusion_worlds[world_index];
+ if (!world) {
+ len = snprintf( addr.sun_path, sizeof(addr.sun_path), "/tmp/.fusion-%d/", world_index );
+ /* Make socket directory if it doesn't exits. */
+ if (mkdir( addr.sun_path, 0775 ) == 0) {
+ chmod( addr.sun_path, 0775 );
+ if (fusion_config->shmfile_gid != (gid_t)-1)
+ chown( addr.sun_path, -1, fusion_config->shmfile_gid );
+ }
+
+ /* Check wether we are master. */
+ snprintf( addr.sun_path+len, sizeof(addr.sun_path)-len, "%lx", FUSION_ID_MASTER );
+
+ err = bind( fd, (struct sockaddr*)&addr, sizeof(addr) );
+ if (err < 0) {
+ if (role == FER_MASTER) {
+ D_ERROR( "Fusion/Main: Couldn't start session as master! Remove %s.\n", addr.sun_path );
+ ret = DR_INIT;
+ goto error;
+ }
+
+ /* Auto generate slave id. */
+ for (id = FUSION_ID_MASTER+1; id < (FusionID)-1; id++) {
+ snprintf( addr.sun_path+len, sizeof(addr.sun_path)-len, "%lx", id );
+ err = bind( fd, (struct sockaddr*)&addr, sizeof(addr) );
+ if (err == 0) {
+ chmod( addr.sun_path, 0660 );
+ /* Change group, if requested. */
+ if (fusion_config->shmfile_gid != (gid_t)-1)
+ chown( addr.sun_path, -1, fusion_config->shmfile_gid );
+ break;
+ }
+ }
+ }
+ else if (err == 0 && role != FER_SLAVE) {
+ chmod( addr.sun_path, 0660 );
+ /* Change group, if requested. */
+ if (fusion_config->shmfile_gid != (gid_t)-1)
+ chown( addr.sun_path, -1, fusion_config->shmfile_gid );
+ id = FUSION_ID_MASTER;
+ }
+ }
+ }
+
+ /* Enter a world again? */
+ if (world) {
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_ASSERT( world->refs > 0 );
+
+ /* Check the role again. */
+ switch (role) {
+ case FER_MASTER:
+ if (world->fusion_id != FUSION_ID_MASTER) {
+ D_ERROR( "Fusion/Init: Master role requested for a world (%d) "
+ "we're already slave in!\n", world_index );
+ ret = DR_UNSUPPORTED;
+ goto error;
+ }
+ break;
+
+ case FER_SLAVE:
+ if (world->fusion_id == FUSION_ID_MASTER) {
+ D_ERROR( "Fusion/Init: Slave role requested for a world (%d) "
+ "we're already master in!\n", world_index );
+ ret = DR_UNSUPPORTED;
+ goto error;
+ }
+ break;
+
+ case FER_ANY:
+ break;
+ }
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ if (shared->world_abi != abi_version) {
+ D_ERROR( "Fusion/Init: World ABI (%d) of world '%d' doesn't match own (%d)!\n",
+ shared->world_abi, world_index, abi_version );
+ ret = DR_VERSIONMISMATCH;
+ goto error;
+ }
+
+ world->refs++;
+
+ pthread_mutex_unlock( &fusion_worlds_lock );
+
+ D_DEBUG_AT( Fusion_Main, " -> using existing world %p [%d]\n", world, world_index );
+
+ close( fd );
+
+ /* Return the world. */
+ *ret_world = world;
+
+ return DR_OK;
+ }
+
+ if (id == (FusionID)-1) {
+ D_ERROR( "Fusion/Init: Opening fusion socket (world %d) as '%s' failed!\n", world_index,
+ role == FER_ANY ? "any" : (role == FER_MASTER ? "master" : "slave") );
+ ret = DR_INIT;
+ goto error;
+ }
+
+ D_DEBUG_AT( Fusion_Main, " -> Fusion ID 0x%08lx\n", id );
+
+ if (id == FUSION_ID_MASTER) {
+ int shared_fd;
+
+ snprintf( buf, sizeof(buf), "%s/fusion.%d.core",
+ fusion_config->tmpfs ? : "/dev/shm", world_index );
+
+ /* Open shared memory file. */
+ shared_fd = open( buf, O_RDWR | O_CREAT | O_TRUNC, 0660 );
+ if (shared_fd < 0) {
+ D_PERROR( "Fusion/Init: Couldn't open shared memory file!\n" );
+ ret = DR_INIT;
+ goto error;
+ }
+
+ if (fusion_config->shmfile_gid != (gid_t)-1) {
+ if (fchown( shared_fd, -1, fusion_config->shmfile_gid ) != 0)
+ D_INFO( "Fusion/Init: Changing owner on %s failed... continuing on.\n", buf );
+ }
+
+ fchmod( shared_fd, 0660 );
+ ftruncate( shared_fd, sizeof(FusionWorldShared) );
+
+ /* Map shared area. */
+ shared = mmap( (void*) 0x20000000 + 0x2000 * world_index, sizeof(FusionWorldShared),
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, shared_fd, 0 );
+ if (shared == MAP_FAILED) {
+ D_PERROR( "Fusion/Init: Mapping shared area failed!\n" );
+ close( shared_fd );
+ ret = DR_INIT;
+ goto error;
+ }
+
+ close( shared_fd );
+
+ D_DEBUG_AT( Fusion_Main, " -> shared area at %p, size %zu\n", shared, sizeof(FusionWorldShared) );
+
+ /* Initialize reference counter. */
+ shared->refs = 1;
+
+ /* Set ABI version. */
+ shared->world_abi = abi_version;
+
+ /* Set the world index. */
+ shared->world_index = world_index;
+
+ /* Set pool allocation base/max. */
+ shared->pool_base = (void*)0x20000000 + 0x2000 * FUSION_MAX_WORLDS + 0x8000000 * world_index;
+ shared->pool_max = shared->pool_base + 0x8000000 - 1;
+
+ /* Set start time of world clock. */
+ direct_monotonic_gettimeofday( &shared->start_time );
+
+ D_MAGIC_SET( shared, FusionWorldShared );
+ }
+ else {
+ FusionEnter enter;
+ int shared_fd;
+
+ /* Fill enter information. */
+ enter.type = FMT_ENTER;
+ enter.fusion_id = id;
+
+ snprintf( addr.sun_path, sizeof(addr.sun_path),
+ "/tmp/.fusion-%d/%lx", world_index, FUSION_ID_MASTER );
+
+ /* Send enter message (used to sync with the master) */
+ ret = _fusion_send_message( fd, &enter, sizeof(FusionEnter), &addr );
+ if (ret == DR_OK) {
+ ret = _fusion_recv_message( fd, &enter, sizeof(FusionEnter), NULL );
+ if (ret == DR_OK && enter.type != FMT_ENTER) {
+ D_ERROR( "Fusion/Init: Expected message ENTER, got '%d'!\n", enter.type );
+ ret = DR_FUSION;
+ }
+ }
+
+ if (ret) {
+ D_ERROR( "Fusion/Init: Could not enter world '%d'!\n", world_index );
+ goto error;
+ }
+
+ snprintf( buf, sizeof(buf), "%s/fusion.%d.core",
+ fusion_config->tmpfs ? : "/dev/shm", world_index );
+
+ /* Open shared memory file. */
+ shared_fd = open( buf, O_RDWR );
+ if (shared_fd < 0) {
+ D_PERROR( "Fusion/Init: Couldn't open shared memory file!\n" );
+ ret = DR_INIT;
+ goto error;
+ }
+
+ /* Map shared area. */
+ shared = mmap( (void*) 0x20000000 + 0x2000 * world_index, sizeof(FusionWorldShared),
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, shared_fd, 0 );
+ if (shared == MAP_FAILED) {
+ D_PERROR( "Fusion/Init: Mapping shared area failed!\n" );
+ close( shared_fd );
+ ret = DR_INIT;
+ goto error;
+ }
+
+ close( shared_fd );
+
+ D_DEBUG_AT( Fusion_Main, " -> shared area at %p, size %zu\n", shared, sizeof(FusionWorldShared) );
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ /* Check ABI version. */
+ if (shared->world_abi != abi_version) {
+ D_ERROR( "Fusion/Init: World ABI (%d) doesn't match own (%d)!\n",
+ shared->world_abi, abi_version );
+ ret = DR_VERSIONMISMATCH;
+ goto error;
+ }
+ }
+
+ /* Synchronize to world clock. */
+ direct_clock_set_start( &shared->start_time );
+
+ /* Allocate local data. */
+ world = D_CALLOC( 1, sizeof(FusionWorld) );
+ if (!world) {
+ ret = D_OOM();
+ goto error;
+ }
+
+ /* Initialize local data. */
+ world->refs = 1;
+ world->shared = shared;
+ world->fusion_fd = fd;
+ world->fusion_id = id;
+
+ D_MAGIC_SET( world, FusionWorld );
+
+ fusion_worlds[world_index] = world;
+
+ /* Initialize shared memory part. */
+ ret = fusion_shm_init( world );
+ if (ret)
+ goto error2;
+
+ D_DEBUG_AT( Fusion_Main, " -> initializing other parts...\n" );
+
+ /* Initialize other parts. */
+ if (world->fusion_id == FUSION_ID_MASTER) {
+ fusion_skirmish_init( &shared->arenas_lock, "Fusion Arenas", world );
+ fusion_skirmish_init( &shared->reactor_globals, "Fusion Reactor Globals", world );
+ fusion_skirmish_init( &shared->fusionees_lock, "Fusionees", world );
+
+ /* Create the main pool. */
+ ret = fusion_shm_pool_create( world, "Fusion Main Pool", 0x100000,
+ fusion_config->debugshm, &shared->main_pool );
+ if (ret)
+ goto error3;
+ }
+
+ /* Add ourselves to the list of fusionees. */
+ ret = _fusion_add_fusionee( world, id );
+ if (ret)
+ goto error4;
+
+ D_DEBUG_AT( Fusion_Main, " -> starting dispatcher loop...\n" );
+
+ /* Start the dispatcher thread. */
+ world->dispatch_loop = direct_thread_create( DTT_MESSAGING,
+ fusion_dispatch_loop,
+ world, "Fusion Dispatch" );
+ if (!world->dispatch_loop) {
+ ret = DR_FAILURE;
+ goto error5;
+ }
+
+ D_DEBUG_AT( Fusion_Main, " -> done. (%p)\n", world );
+
+ pthread_mutex_unlock( &fusion_worlds_lock );
+
+ /* Return the fusion world. */
+ *ret_world = world;
+
+ return DR_OK;
+
+
+error5:
+ if (world->dispatch_loop)
+ direct_thread_destroy( world->dispatch_loop );
+
+ _fusion_remove_fusionee( world, id );
+
+error4:
+ if (world->fusion_id == FUSION_ID_MASTER)
+ fusion_shm_pool_destroy( world, shared->main_pool );
+
+error3:
+ if (world->fusion_id == FUSION_ID_MASTER) {
+ fusion_skirmish_destroy( &shared->arenas_lock );
+ fusion_skirmish_destroy( &shared->reactor_globals );
+ fusion_skirmish_destroy( &shared->fusionees_lock );
+ }
+
+ fusion_shm_deinit( world );
+
+
+error2:
+ fusion_worlds[world_index] = world;
+
+ D_MAGIC_CLEAR( world );
+
+ D_FREE( world );
+
+error:
+ if (shared != MAP_FAILED) {
+ if (id == FUSION_ID_MASTER)
+ D_MAGIC_CLEAR( shared );
+
+ munmap( shared, sizeof(FusionWorldShared) );
+ }
+
+ if (fd != -1) {
+ /* Unbind. */
+ socklen_t len = sizeof(addr);
+ if (getsockname( fd, (struct sockaddr*)&addr, &len ) == 0)
+ unlink( addr.sun_path );
+
+ close( fd );
+ }
+
+ pthread_mutex_unlock( &fusion_worlds_lock );
+
+ direct_shutdown();
+
+ return ret;
+}
+
+DirectResult
+fusion_stop_dispatcher( FusionWorld *world,
+ bool emergency )
+{
+ if (!emergency) {
+ fusion_sync( world );
+
+ direct_thread_lock( world->dispatch_loop );
+ }
+
+ world->dispatch_stop = true;
+
+ if (!emergency) {
+ direct_thread_unlock( world->dispatch_loop );
+
+ fusion_sync( world );
+ }
+
+ return DR_OK;
+}
+
+/*
+ * Exits the fusion world.
+ *
+ * If 'emergency' is true the function won't join but kill the dispatcher thread.
+ */
+DirectResult
+fusion_exit( FusionWorld *world,
+ bool emergency )
+{
+ FusionWorldShared *shared;
+ int world_index;
+ bool clear = false;
+
+ D_DEBUG_AT( Fusion_Main, "%s( %p, %semergency )\n", __FUNCTION__, world, emergency ? "" : "no " );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ world_index = shared->world_index;
+
+ pthread_mutex_lock( &fusion_worlds_lock );
+
+ D_ASSERT( world->refs > 0 );
+
+ if (--world->refs) {
+ pthread_mutex_unlock( &fusion_worlds_lock );
+ return DR_OK;
+ }
+
+ if (!emergency) {
+ FusionMessageType msg = FMT_SEND;
+
+ /* Wakeup dispatcher. */
+ if (_fusion_send_message( world->fusion_fd, &msg, sizeof(msg), NULL ))
+ direct_thread_cancel( world->dispatch_loop );
+
+ /* Wait for its termination. */
+ direct_thread_join( world->dispatch_loop );
+ }
+
+ direct_thread_destroy( world->dispatch_loop );
+
+ /* Remove ourselves from list. */
+ if (!emergency || fusion_master( world )) {
+ _fusion_remove_fusionee( world, world->fusion_id );
+ }
+ else {
+ struct sockaddr_un addr;
+ FusionLeave leave;
+
+ addr.sun_family = AF_UNIX;
+ snprintf( addr.sun_path, sizeof(addr.sun_path),
+ "/tmp/.fusion-%d/%lx", world_index, FUSION_ID_MASTER );
+
+ leave.type = FMT_LEAVE;
+ leave.fusion_id = world->fusion_id;
+
+ _fusion_send_message( world->fusion_fd, &leave, sizeof(FusionLeave), &addr );
+ }
+
+ /* Master has to deinitialize shared data. */
+ if (fusion_master( world )) {
+ shared->refs--;
+ if (shared->refs == 0) {
+ fusion_skirmish_destroy( &shared->reactor_globals );
+ fusion_skirmish_destroy( &shared->arenas_lock );
+ fusion_skirmish_destroy( &shared->fusionees_lock );
+
+ fusion_shm_pool_destroy( world, shared->main_pool );
+
+ /* Deinitialize shared memory. */
+ fusion_shm_deinit( world );
+
+ clear = true;
+ }
+ }
+ else {
+ /* Leave shared memory. */
+ fusion_shm_deinit( world );
+ }
+
+ /* Reset local dispatch nodes. */
+ _fusion_reactor_free_all( world );
+
+ /* Remove world from global list. */
+ fusion_worlds[shared->world_index] = NULL;
+
+ /* Unmap shared area. */
+ if (clear)
+ D_MAGIC_CLEAR( shared );
+
+ munmap( shared, sizeof(FusionWorldShared) );
+
+ /* Close socket. */
+ close( world->fusion_fd );
+
+ if (clear) {
+ DIR *dir;
+ char buf[128];
+ int len;
+
+ /* Remove core shmfile. */
+ snprintf( buf, sizeof(buf), "%s/fusion.%d.core",
+ fusion_config->tmpfs ? : "/dev/shm", world_index );
+ D_DEBUG_AT( Fusion_Main, "Removing shmfile %s.\n", buf );
+ unlink( buf );
+
+ /* Cleanup socket directory. */
+ len = snprintf( buf, sizeof(buf), "/tmp/.fusion-%d/", world_index );
+ dir = opendir( buf );
+ if (dir) {
+ struct dirent *entry = NULL;
+ struct dirent tmp;
+
+ while (readdir_r( dir, &tmp, &entry ) == 0 && entry) {
+ if (entry->d_name[0] != '.') {
+ struct stat st;
+
+ direct_snputs( buf+len, entry->d_name, sizeof(buf)-len );
+ if (stat( buf, &st ) == 0 && S_ISSOCK(st.st_mode)) {
+ D_DEBUG_AT( Fusion_Main, "Removing socket %s.\n", buf );
+ unlink( buf );
+ }
+ }
+ }
+
+ closedir( dir );
+ }
+ else {
+ D_PERROR( "Fusion/Main: Couldn't open socket directory %s", buf );
+ }
+ }
+
+ /* Free local world data. */
+ D_MAGIC_CLEAR( world );
+ D_FREE( world );
+
+ D_DEBUG_AT( Fusion_Main, "%s( %p ) done.\n", __FUNCTION__, world );
+
+ pthread_mutex_unlock( &fusion_worlds_lock );
+
+ direct_shutdown();
+
+ return DR_OK;
+}
+
+/*
+ * Sends a signal to one or more fusionees and optionally waits
+ * for their processes to terminate.
+ *
+ * A fusion_id of zero means all fusionees but the calling one.
+ * A timeout of zero means infinite waiting while a negative value
+ * means no waiting at all.
+ */
+DirectResult
+fusion_kill( FusionWorld *world,
+ FusionID fusion_id,
+ int signal,
+ int timeout_ms )
+{
+ FusionWorldShared *shared;
+ __Fusionee *fusionee, *temp;
+ int result;
+
+ D_DEBUG_AT( Fusion_Main, "%s( %p, %lu, %d, %d )\n",
+ __FUNCTION__, world, fusion_id, signal, timeout_ms );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ fusion_skirmish_prevail( &shared->fusionees_lock );
+
+ direct_list_foreach_safe (fusionee, temp, shared->fusionees) {
+ if (fusion_id == 0 && fusionee->id == world->fusion_id)
+ continue;
+
+ if (fusion_id != 0 && fusionee->id != fusion_id)
+ continue;
+
+ D_DEBUG_AT( Fusion_Main, " -> killing fusionee %lu (%d)...\n", fusionee->id, fusionee->pid );
+
+ result = kill( fusionee->pid, signal );
+ if (result == 0 && timeout_ms >= 0) {
+ pid_t pid = fusionee->pid;
+ long long stop = timeout_ms ? (direct_clock_get_micros() + timeout_ms*1000) : 0;
+
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+
+ while (kill( pid, 0 ) == 0) {
+ usleep( 1000 );
+
+ if (timeout_ms && direct_clock_get_micros() >= stop)
+ break;
+ };
+
+ fusion_skirmish_prevail( &shared->fusionees_lock );
+ }
+ else if (result < 0) {
+ if (errno == ESRCH) {
+ D_DEBUG_AT( Fusion_Main, " ... fusionee %lu exited without removing itself!\n", fusionee->id );
+
+ _fusion_remove_fusionee( world, fusionee->id );
+ }
+ else {
+ D_PERROR( "Fusion/Main: kill(%d, %d)\n", fusionee->pid, signal );
+ }
+ }
+ }
+
+ fusion_skirmish_dismiss( &shared->fusionees_lock );
+
+ return DR_OK;
+}
+
+/**********************************************************************************************************************/
+
+static void *
+fusion_dispatch_loop( DirectThread *self, void *arg )
+{
+ FusionWorld *world = arg;
+ struct sockaddr_un addr;
+ socklen_t addr_len = sizeof(addr);
+ fd_set set;
+ char buf[FUSION_MESSAGE_SIZE];
+
+ D_DEBUG_AT( Fusion_Main_Dispatch, "%s() running...\n", __FUNCTION__ );
+
+ while (true) {
+ int result;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ FD_ZERO( &set );
+ FD_SET( world->fusion_fd, &set );
+
+ result = select( world->fusion_fd + 1, &set, NULL, NULL, NULL );
+ if (result < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ default:
+ D_PERROR( "Fusion/Dispatcher: select() failed!\n" );
+ return NULL;
+ }
+ }
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ if (FD_ISSET( world->fusion_fd, &set ) &&
+ recvfrom( world->fusion_fd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &addr_len ) > 0) {
+ FusionMessage *msg = (FusionMessage*)buf;
+
+ pthread_setcancelstate( PTHREAD_CANCEL_DISABLE, NULL );
+
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> message from '%s'...\n", addr.sun_path );
+
+ direct_thread_lock( world->dispatch_loop );
+
+ if (world->dispatch_stop) {
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> IGNORING (dispatch_stop!)\n" );
+ }
+ else {
+ switch (msg->type) {
+ case FMT_SEND:
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_SEND...\n" );
+ break;
+
+ case FMT_ENTER:
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_ENTER...\n" );
+ if (!fusion_master( world )) {
+ D_ERROR( "Fusion/Dispatch: Got ENTER request, but I'm not master!\n" );
+ break;
+ }
+ if (msg->enter.fusion_id == world->fusion_id) {
+ D_ERROR( "Fusion/Dispatch: Received ENTER request from myself!\n" );
+ break;
+ }
+ /* Nothing to do here. Send back message. */
+ _fusion_send_message( world->fusion_fd, msg, sizeof(FusionEnter), &addr );
+ break;
+
+ case FMT_LEAVE:
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_LEAVE...\n" );
+ if (!fusion_master( world )) {
+ D_ERROR( "Fusion/Dispatch: Got LEAVE request, but I'm not master!\n" );
+ break;
+ }
+ if (msg->leave.fusion_id == world->fusion_id) {
+ D_ERROR( "Fusion/Dispatch: Received LEAVE request from myself!\n" );
+ break;
+ }
+ _fusion_remove_fusionee( world, msg->leave.fusion_id );
+ break;
+
+ case FMT_CALL:
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_CALL...\n" );
+ _fusion_call_process( world, msg->call.call_id, &msg->call );
+ break;
+
+ case FMT_REACTOR:
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> FMT_REACTOR...\n" );
+ _fusion_reactor_process_message( world, msg->reactor.id, msg->reactor.channel,
+ &buf[sizeof(FusionReactorMessage)] );
+ if (msg->reactor.ref) {
+ fusion_ref_down( msg->reactor.ref, true );
+ if (fusion_ref_zero_trylock( msg->reactor.ref ) == DR_OK) {
+ fusion_ref_destroy( msg->reactor.ref );
+ SHFREE( world->shared->main_pool, msg->reactor.ref );
+ }
+ }
+ break;
+
+ default:
+ D_BUG( "unexpected message type (%d)", msg->type );
+ break;
+ }
+ }
+
+ direct_thread_unlock( world->dispatch_loop );
+
+ if (!world->refs) {
+ D_DEBUG_AT( Fusion_Main_Dispatch, " -> good bye!\n" );
+ return NULL;
+ }
+
+ D_DEBUG_AT( Fusion_Main_Dispatch, " ...done\n" );
+
+ pthread_setcancelstate( PTHREAD_CANCEL_ENABLE, NULL );
+ }
+ }
+
+ return NULL;
+}
+
+/**********************************************************************************************************************/
+
+#endif /* FUSION_BUILD_KERNEL */
+
+/*
+ * Wait until all pending messages are processed.
+ */
+DirectResult
+fusion_sync( const FusionWorld *world )
+{
+ int result;
+ fd_set set;
+ struct timeval tv;
+ int loops = 200;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ D_DEBUG_AT( Fusion_Main, "%s( %p )\n", __FUNCTION__, world );
+
+ D_DEBUG_AT( Fusion_Main, "syncing with fusion device...\n" );
+
+ while (loops--) {
+ FD_ZERO( &set );
+ FD_SET( world->fusion_fd, &set );
+
+ tv.tv_sec = 0;
+ tv.tv_usec = 20000;
+
+ result = select( world->fusion_fd + 1, &set, NULL, NULL, &tv );
+ D_DEBUG_AT( Fusion_Main, " -> select() returned %d...\n", result );
+ switch (result) {
+ case -1:
+ if (errno == EINTR)
+ return DR_OK;
+
+ D_PERROR( "Fusion/Sync: select() failed!\n");
+ return DR_FAILURE;
+
+ default:
+ D_DEBUG_AT( Fusion_Main, " -> FD_ISSET %d...\n", FD_ISSET( world->fusion_fd, &set ) );
+
+ if (FD_ISSET( world->fusion_fd, &set )) {
+ usleep( 20000 );
+ break;
+ }
+
+ case 0:
+ D_DEBUG_AT( Fusion_Main, " -> synced.\n");
+ return DR_OK;
+ }
+ }
+
+ D_DEBUG_AT( Fusion_Main, " -> timeout!\n");
+
+ D_ERROR( "Fusion/Main: Timeout waiting for empty message queue!\n" );
+
+ return DR_TIMEOUT;
+}
+
+/*
+ * Sets the fork() action of the calling Fusionee within the world.
+ */
+void
+fusion_world_set_fork_action( FusionWorld *world,
+ FusionForkAction action )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ world->fork_action = action;
+}
+
+/*
+ * Gets the current fork() action.
+ */
+FusionForkAction
+fusion_world_get_fork_action( FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return world->fork_action;
+}
+
+/*
+ * Registers a callback called upon fork().
+ */
+void
+fusion_world_set_fork_callback( FusionWorld *world,
+ FusionForkCallback callback )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ world->fork_callback = callback;
+}
+
+/*
+ * Return the index of the specified world.
+ */
+int
+fusion_world_index( const FusionWorld *world )
+{
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ return shared->world_index;
+}
+
+/*
+ * Return the own Fusion ID within the specified world.
+ */
+FusionID
+fusion_id( const FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return world->fusion_id;
+}
+
+/*
+ * Return if the world is a multi application world.
+ */
+bool
+fusion_is_multi( const FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return true;
+}
+
+/*
+ * Return the thread ID of the Fusion Dispatcher within the specified world.
+ */
+pid_t
+fusion_dispatcher_tid( const FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return direct_thread_get_tid( world->dispatch_loop );
+}
+
+/*
+ * Return true if this process is the master.
+ */
+bool
+fusion_master( const FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return world->fusion_id == FUSION_ID_MASTER;
+}
+
+/*
+ * Check if a pointer points to the shared memory.
+ */
+bool
+fusion_is_shared( FusionWorld *world,
+ const void *ptr )
+{
+ int i;
+ DirectResult ret;
+ FusionSHM *shm;
+ FusionSHMShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shm = &world->shm;
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+
+ shared = shm->shared;
+
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ if (ptr >= (void*) world->shared && ptr < (void*) world->shared + sizeof(FusionWorldShared))
+ return true;
+
+ ret = fusion_skirmish_prevail( &shared->lock );
+ if (ret)
+ return false;
+
+ for (i=0; i<FUSION_SHM_MAX_POOLS; i++) {
+ if (shared->pools[i].active) {
+ shmalloc_heap *heap;
+ FusionSHMPoolShared *pool = &shared->pools[i];
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ heap = pool->heap;
+
+ D_MAGIC_ASSERT( heap, shmalloc_heap );
+
+ if (ptr >= pool->addr_base && ptr < pool->addr_base + heap->size) {
+ fusion_skirmish_dismiss( &shared->lock );
+ return true;
+ }
+ }
+ }
+
+ fusion_skirmish_dismiss( &shared->lock );
+
+ return false;
+}
+
+#else /* FUSION_BUILD_MULTI */
+
+/*
+ * Enters a fusion world by joining or creating it.
+ *
+ * If <b>world_index</b> is negative, the next free index is used to create a new world.
+ * Otherwise the world with the specified index is joined or created.
+ */
+DirectResult fusion_enter( int world_index,
+ int abi_version,
+ FusionEnterRole role,
+ FusionWorld **ret_world )
+{
+ DirectResult ret;
+ FusionWorld *world = NULL;
+
+ D_ASSERT( ret_world != NULL );
+
+ ret = direct_initialize();
+ if (ret)
+ return ret;
+
+ world = D_CALLOC( 1, sizeof(FusionWorld) );
+ if (!world) {
+ ret = D_OOM();
+ goto error;
+ }
+
+ world->shared = D_CALLOC( 1, sizeof(FusionWorldShared) );
+ if (!world->shared) {
+ ret = D_OOM();
+ goto error;
+ }
+
+ /* Create the main pool. */
+ ret = fusion_shm_pool_create( world, "Fusion Main Pool", 0x100000,
+ fusion_config->debugshm, &world->shared->main_pool );
+ if (ret)
+ goto error;
+
+ D_MAGIC_SET( world, FusionWorld );
+ D_MAGIC_SET( world->shared, FusionWorldShared );
+
+ *ret_world = world;
+
+ return DR_OK;
+
+
+error:
+ if (world) {
+ if (world->shared)
+ D_FREE( world->shared );
+
+ D_FREE( world );
+ }
+
+ direct_shutdown();
+
+ return ret;
+}
+
+DirectResult
+fusion_stop_dispatcher( FusionWorld *world,
+ bool emergency )
+{
+ return DR_OK;
+}
+
+/*
+ * Exits the fusion world.
+ *
+ * If 'emergency' is true the function won't join but kill the dispatcher thread.
+ */
+DirectResult
+fusion_exit( FusionWorld *world,
+ bool emergency )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_MAGIC_ASSERT( world->shared, FusionWorldShared );
+
+ fusion_shm_pool_destroy( world, world->shared->main_pool );
+
+ D_MAGIC_CLEAR( world->shared );
+
+ D_FREE( world->shared );
+
+ D_MAGIC_CLEAR( world );
+
+ D_FREE( world );
+
+ direct_shutdown();
+
+ return DR_OK;
+}
+
+/*
+ * Sets the fork() action of the calling Fusionee within the world.
+ */
+void
+fusion_world_set_fork_action( FusionWorld *world,
+ FusionForkAction action )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+}
+
+/*
+ * Gets the current fork() action.
+ */
+FusionForkAction
+fusion_world_get_fork_action( FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return world->fork_action;
+}
+
+/*
+ * Registers a callback called upon fork().
+ */
+void
+fusion_world_set_fork_callback( FusionWorld *world,
+ FusionForkCallback callback )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+}
+
+/*
+ * Return the index of the specified world.
+ */
+int
+fusion_world_index( const FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return 0;
+}
+
+
+/*
+ * Return true if this process is the master.
+ */
+bool
+fusion_master( const FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return true;
+}
+
+/*
+ * Sends a signal to one or more fusionees and optionally waits
+ * for their processes to terminate.
+ *
+ * A fusion_id of zero means all fusionees but the calling one.
+ * A timeout of zero means infinite waiting while a negative value
+ * means no waiting at all.
+ */
+DirectResult
+fusion_kill( FusionWorld *world,
+ FusionID fusion_id,
+ int signal,
+ int timeout_ms )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return DR_OK;
+}
+
+/*
+ * Return the own Fusion ID within the specified world.
+ */
+FusionID
+fusion_id( const FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return 1;
+}
+
+/*
+ * Return if the world is a multi application world.
+ */
+bool
+fusion_is_multi( const FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return false;
+}
+
+/*
+ * Wait until all pending messages are processed.
+ */
+DirectResult
+fusion_sync( const FusionWorld *world )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return DR_OK;
+}
+
+/* Check if a pointer points to the shared memory. */
+bool
+fusion_is_shared( FusionWorld *world,
+ const void *ptr )
+{
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ return true;
+}
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/fusion.h b/Source/DirectFB/lib/fusion/fusion.h
new file mode 100755
index 0000000..bfe3da2
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/fusion.h
@@ -0,0 +1,142 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__FUSION_H__
+#define __FUSION__FUSION_H__
+
+#include <sys/types.h>
+
+#include <fusion/types.h>
+
+typedef enum {
+ FER_ANY,
+ FER_MASTER,
+ FER_SLAVE
+} FusionEnterRole;
+
+typedef enum {
+ FFA_CLOSE,
+ FFA_FORK
+} FusionForkAction;
+
+typedef enum {
+ FFS_PREPARE,
+ FFS_PARENT,
+ FFS_CHILD
+} FusionForkState;
+
+typedef void (*FusionForkCallback) ( FusionForkAction action, FusionForkState state );
+
+/*
+ * Enters a fusion world by joining or creating it.
+ *
+ * If <b>world_index</b> is negative, the next free index is used to create a new world.
+ * Otherwise the world with the specified index is joined or created.
+ */
+DirectResult fusion_enter( int world_index,
+ int abi_version,
+ FusionEnterRole role,
+ FusionWorld **ret_world );
+
+/*
+ * Exits the fusion world.
+ *
+ * If 'emergency' is true the function won't join but kill the dispatcher thread.
+ */
+DirectResult fusion_exit( FusionWorld *world,
+ bool emergency );
+
+DirectResult fusion_stop_dispatcher( FusionWorld *world,
+ bool emergency );
+
+/*
+ * Sets the fork() action of the calling Fusionee within the world.
+ */
+void fusion_world_set_fork_action( FusionWorld *world,
+ FusionForkAction action );
+
+/*
+ * Gets the current fork() action.
+ */
+FusionForkAction fusion_world_get_fork_action( FusionWorld *world );
+
+/*
+ * Registers a callback called upon fork().
+ */
+void fusion_world_set_fork_callback( FusionWorld *world,
+ FusionForkCallback callback );
+
+/*
+ * Return the index of the specified world.
+ */
+int fusion_world_index( const FusionWorld *world );
+
+/*
+ * Return the own Fusion ID within the specified world.
+ */
+FusionID fusion_id( const FusionWorld *world );
+
+/*
+ * Return if the world is a multi application world.
+ */
+bool fusion_is_multi( const FusionWorld *world );
+
+/*
+ * Return the thread ID of the Fusion Dispatcher within the specified world.
+ */
+pid_t fusion_dispatcher_tid( const FusionWorld *world );
+
+/*
+ * Return true if this process is the master.
+ */
+bool fusion_master( const FusionWorld *world );
+
+/*
+ * Wait until all pending messages are processed.
+ */
+DirectResult fusion_sync( const FusionWorld *world );
+
+/*
+ * Sends a signal to one or more fusionees and optionally waits
+ * for their processes to terminate.
+ *
+ * A fusion_id of zero means all fusionees but the calling one.
+ * A timeout of zero means infinite waiting while a negative value
+ * means no waiting at all.
+ */
+DirectResult fusion_kill( FusionWorld *world,
+ FusionID fusion_id,
+ int signal,
+ int timeout_ms );
+
+/* Check if a pointer points to the shared memory. */
+bool fusion_is_shared( FusionWorld *world,
+ const void *ptr );
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/fusion.pc.in b/Source/DirectFB/lib/fusion/fusion.pc.in
new file mode 100755
index 0000000..09cf78c
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/fusion.pc.in
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: Fusion IPC
+Description: High Level IPC Mechanisms
+Version: @VERSION@
+Requires: direct
+Libs: -L${libdir} -lfusion
+Cflags: -I@INCLUDEDIR@
diff --git a/Source/DirectFB/lib/fusion/fusion_internal.h b/Source/DirectFB/lib/fusion/fusion_internal.h
new file mode 100755
index 0000000..5e7c474
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/fusion_internal.h
@@ -0,0 +1,185 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__FUSION_INTERNAL_H__
+#define __FUSION__FUSION_INTERNAL_H__
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <string.h>
+
+#include <direct/list.h>
+
+#include <fusion/build.h>
+#include <fusion/fusion.h>
+#include <fusion/lock.h>
+#include <fusion/ref.h>
+#include <fusion/shm/shm_internal.h>
+
+#if FUSION_BUILD_MULTI
+# if FUSION_BUILD_KERNEL
+# include <sys/ioctl.h>
+# include <linux/fusion.h>
+# else
+# include <fusion/protocol.h>
+# endif
+#endif
+
+#define FUSION_MAX_WORLDS 8
+
+/***************************************
+ * Fusion internal type declarations *
+ ***************************************/
+
+struct __Fusion_FusionWorldShared {
+ int magic;
+
+ int refs; /* Increased by the master on fork(). */
+
+ int world_index;
+
+ int world_abi;
+
+ struct timeval start_time;
+
+ DirectLink *arenas;
+ FusionSkirmish arenas_lock;
+
+ FusionSkirmish reactor_globals;
+
+ FusionSHMShared shm;
+
+ FusionSHMPoolShared *main_pool;
+
+ DirectLink *fusionees; /* Connected fusionees. */
+ FusionSkirmish fusionees_lock;
+
+ unsigned int call_ids; /* Generates call ids. */
+ unsigned int lock_ids; /* Generates locks ids. */
+ unsigned int ref_ids; /* Generates refs ids. */
+ unsigned int reactor_ids; /* Generates reactors ids. */
+ unsigned int pool_ids; /* Generates pools ids. */
+
+ void *pool_base; /* SHM pool allocation base. */
+ void *pool_max; /* SHM pool max address. */
+};
+
+struct __Fusion_FusionWorld {
+ int magic;
+
+ int refs;
+
+ FusionWorldShared *shared;
+
+ int fusion_fd;
+ FusionID fusion_id;
+
+ DirectThread *dispatch_loop;
+ bool dispatch_stop;
+
+ /*
+ * List of reactors with at least one local reaction attached.
+ */
+ DirectLink *reactor_nodes;
+ pthread_mutex_t reactor_nodes_lock;
+
+ FusionSHM shm;
+
+ FusionForkAction fork_action;
+ FusionForkCallback fork_callback;
+
+ void *fusionee;
+};
+
+/*******************************************
+ * Fusion internal function declarations *
+ *******************************************/
+
+int _fusion_fd( const FusionWorldShared *shared );
+FusionID _fusion_id( const FusionWorldShared *shared );
+
+FusionWorld *_fusion_world( const FusionWorldShared *shared );
+
+/*
+ * from reactor.c
+ */
+void _fusion_reactor_free_all ( FusionWorld *world );
+void _fusion_reactor_process_message( FusionWorld *world,
+ int reactor_id,
+ int channel,
+ const void *msg_data );
+
+
+#if FUSION_BUILD_MULTI
+/*
+ * from call.c
+ */
+void _fusion_call_process( FusionWorld *world,
+ int call_id,
+ FusionCallMessage *call );
+
+#if FUSION_BUILD_KERNEL
+/*
+ * from shm.c
+ */
+void _fusion_shmpool_process( FusionWorld *world,
+ int pool_id,
+ FusionSHMPoolMessage *msg );
+#else
+/*
+ * form fusion.c
+ */
+void _fusion_add_local( FusionWorld *world,
+ FusionRef *ref,
+ int add );
+
+void _fusion_check_locals( FusionWorld *world,
+ FusionRef *ref );
+
+void _fusion_remove_all_locals( FusionWorld *world,
+ const FusionRef *ref );
+
+DirectResult _fusion_send_message( int fd,
+ const void *msg,
+ size_t msg_size,
+ struct sockaddr_un *addr );
+DirectResult _fusion_recv_message( int fd,
+ void *msg,
+ size_t msg_size,
+ struct sockaddr_un *addr );
+
+/*
+ * from ref.c
+ */
+DirectResult _fusion_ref_change( FusionRef *ref, int add, bool global );
+
+#endif /* FUSION_BUILD_KERNEL */
+#endif /* FUSION_BUILD_MULTI */
+
+#endif
diff --git a/Source/DirectFB/lib/fusion/hash.c b/Source/DirectFB/lib/fusion/hash.c
new file mode 100755
index 0000000..06723d2
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/hash.c
@@ -0,0 +1,560 @@
+/*
+ GLIB - Library of useful routines for C programming
+ Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi>,
+ Claudio Ciccani <klan@users.sf.net> and
+ Michael Emmel <mike.emmel@gmail.com>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <direct/debug.h>
+#include <direct/mem.h>
+#include <direct/memcpy.h>
+#include <direct/util.h>
+#include <fusion/object.h>
+#include <fusion/shmalloc.h>
+#include <fusion/hash.h>
+
+
+D_DEBUG_DOMAIN( Fusion_Hash, "Fusion/Hash", "Hash table implementation" );
+
+
+
+
+static const unsigned int primes[] =
+{
+ 11,
+ 19,
+ 37,
+ 73,
+ 109,
+ 163,
+ 251,
+ 367,
+ 557,
+ 823,
+ 1237,
+ 1861,
+ 2777,
+ 4177,
+ 6247,
+ 9371,
+ 14057,
+ 21089,
+ 31627,
+ 47431,
+ 71143,
+ 106721,
+ 160073,
+ 240101,
+ 360163,
+ 540217,
+ 810343,
+ 1215497,
+ 1823231,
+ 2734867,
+ 4102283,
+ 6153409,
+ 9230113,
+ 13845163,
+};
+
+
+static const unsigned int nprimes = D_ARRAY_SIZE( primes );
+
+static DirectResult
+fusion_hash_create_internal(bool type,FusionSHMPoolShared *pool,
+ FusionHashType key_type,
+ FusionHashType value_type,
+ int size, FusionHash **ret_hash );
+
+static void
+fusion_hash_node_destroy (FusionHash *hash,FusionHashNode *node,
+ void **old_key,void **old_value);
+
+static unsigned int
+spaced_primes_closest (unsigned int num)
+{
+ int i;
+ for (i = 0; i < nprimes; i++)
+ if (primes[i] > num)
+ return primes[i];
+ return primes[nprimes - 1];
+}
+
+/**
+ * fusion_hash_create_local:
+ * @key_type: Type of hash key the hash is optimized for strings ints and pointers
+ * @value_type: Type of hash data optimized for strings ints and pointers
+ * @size: Inital size of the hash table
+ * @ret_hash:the new hash table
+ * Creates a new #FusionHash that uses local memory
+ *
+ * Return value: a new #FusionHash.
+ **/
+DirectResult
+fusion_hash_create_local (FusionHashType key_type, FusionHashType value_type,
+ int size, FusionHash **ret_hash )
+{
+ return fusion_hash_create_internal(true,NULL,key_type,value_type,
+ size,ret_hash );
+
+}
+
+/**
+ * fusion_hash_create:
+ * @key_type: Type of hash key the hash is optimized for strings ints and pointers
+ * @value_type: Type of hash data optimized for strings ints and pointers
+ * @size: Inital size of the hash table
+ * @ret_hash:the new hash table
+ * Creates a new #FusionHash with a reference count of 1.
+ *
+ * Return value: a new #FusionHash.
+ **/
+DirectResult
+fusion_hash_create (FusionSHMPoolShared *pool,
+ FusionHashType key_type,
+ FusionHashType value_type,
+ int size, FusionHash **ret_hash )
+{
+ return fusion_hash_create_internal(false,pool,key_type,value_type,
+ size,ret_hash );
+}
+
+static DirectResult
+fusion_hash_create_internal (bool local,FusionSHMPoolShared *pool,
+ FusionHashType key_type,
+ FusionHashType value_type,
+ int size, FusionHash **ret_hash )
+{
+ FusionHash *hash;
+
+ if (!ret_hash)
+ return DR_BUG;
+ if (!local && !pool)
+ return DR_BUG;
+
+ if (size < FUSION_HASH_MIN_SIZE)
+ size = FUSION_HASH_MIN_SIZE;
+
+ if (local)
+ hash = D_CALLOC(1, sizeof (FusionHash) );
+ else
+ hash = SHCALLOC(pool, 1, sizeof (FusionHash) );
+
+ if (!hash)
+ return local ?DR_NOLOCALMEMORY:DR_NOSHAREDMEMORY;
+
+ hash->local = local;
+ hash->pool = pool;
+ hash->key_type = key_type;
+ hash->value_type = value_type;
+ hash->size = size;
+ hash->nnodes = 0;
+ if (local)
+ hash->nodes = D_CALLOC(size,sizeof (FusionHashNode*) );
+ else
+ hash->nodes = SHCALLOC(pool, size, sizeof(FusionHashNode*) );
+
+ if (!hash->nodes) {
+ if (local)
+ D_FREE(hash );
+ else
+ SHFREE(pool, hash );
+ return local?DR_NOLOCALMEMORY:DR_NOSHAREDMEMORY;
+ }
+
+ D_MAGIC_SET(hash, FusionHash );
+
+ *ret_hash = hash;
+
+ return DR_OK;
+}
+
+void
+fusion_hash_destroy( FusionHash *hash )
+{
+ int i;
+ FusionHashNode *node, *next;
+ D_MAGIC_ASSERT( hash, FusionHash );
+
+ for (i = 0; i < hash->size; i++) {
+ for (node = hash->nodes[i]; node; node = next) {
+ next = node->next;
+ fusion_hash_node_destroy(hash, node, NULL, NULL);
+ }
+ }
+ if (hash->local)
+ D_FREE(hash->nodes);
+ else
+ SHFREE( hash->pool, hash->nodes );
+ D_MAGIC_CLEAR( hash );
+ if (hash->local)
+ D_FREE(hash);
+ else
+ SHFREE( hash->pool, hash );
+}
+
+void
+fusion_hash_set_autofree( FusionHash *hash, bool free_keys, bool free_values )
+{
+ D_MAGIC_ASSERT( hash, FusionHash );
+
+ hash->free_keys = free_keys;
+ hash->free_values = free_values;
+}
+
+/**
+ * fusion_hash_lookup:
+ * @hash: a #FusionHash.
+ * @key: the key to look up.
+ *
+ * Looks up a key in a #FusionHash. Note that this function cannot
+ * distinguish between a key that is not present and one which is present
+ * and has the value %NULL. If you need this distinction, use
+ * hash_lookup_extended().
+ *
+ * Return value: the associated value, or %NULL if the key is not found.
+ **/
+void *
+fusion_hash_lookup (FusionHash *hash, const void * key)
+{
+ FusionHashNode *node;
+ D_MAGIC_ASSERT( hash, FusionHash );
+ node = *fusion_hash_lookup_node (hash, key);
+ return node ? node->value : NULL;
+}
+
+/**
+ * fusion_hash_insert:
+ * @hash: a #FusionHash.
+ * @key: a key to insert.
+ * @value: the value to associate with the key.
+ *
+ * Inserts a new key and value into a #FusionHash.
+ * If the key already exists in the #FusionHash DR_BUG is returned
+ * If you think a key may exist you should call fusion_hash_replace
+ * Generally this is only used on a new FusionHash
+ **/
+DirectResult
+fusion_hash_insert( FusionHash *hash,
+ void *key,
+ void *value )
+{
+ FusionHashNode **node;
+ D_MAGIC_ASSERT( hash, FusionHash );
+
+ node = fusion_hash_lookup_node (hash, key);
+
+ if (*node) {
+ D_BUG( "key already exists" );
+ return DR_BUG;
+ }
+ else {
+ if (hash->local)
+ (*node) = D_CALLOC(1,sizeof(FusionHashNode));
+ else
+ (*node) = SHCALLOC(hash->pool, 1, sizeof(FusionHashNode));
+ if ( !(*node) )
+ return hash->local?DR_NOLOCALMEMORY:DR_NOSHAREDMEMORY;
+
+ (*node)->key = key;
+ (*node)->value = value;
+ hash->nnodes++;
+ if ( fusion_hash_should_resize(hash) )
+ fusion_hash_resize(hash);
+ }
+ return DR_OK;
+}
+
+/**
+ * hash_replace:
+ * @hash: a #FusionHash.
+ * @key: a key to insert.
+ * @value: the value to associate with the key.
+ *
+ * Inserts a new key and value into a #FusionHash similar to
+ * hash_insert(). The difference is that if the key already exists
+ * in the #FusionHash, it gets replaced by the new key.
+ * If you supplied a oldkey pointer or oldkey value they are returned
+ * otherwise free is called the key if table type is not type HASH_INT
+ * and free is called on the old value if not supplied
+ **/
+DirectResult
+fusion_hash_replace (FusionHash *hash,
+ void * key,
+ void * value,
+ void **old_key,
+ void **old_value)
+{
+ FusionHashNode **node;
+ D_MAGIC_ASSERT( hash, FusionHash );
+
+ node = fusion_hash_lookup_node (hash, key);
+
+ if (*node) {
+ if ( old_key)
+ *old_key = (*node)->key;
+ else if ( hash->key_type != HASH_INT ) {
+ if (hash->free_keys) {
+ if (hash->local)
+ D_FREE((*node)->key);
+ else
+ SHFREE(hash->pool, (*node)->key );
+ }
+ }
+
+ if ( old_value)
+ *old_value = (*node)->value;
+ else if ( hash->value_type != HASH_INT ) {
+ if (hash->free_values) {
+ if (hash->local)
+ D_FREE((*node)->value);
+ else
+ SHFREE(hash->pool, (*node)->value );
+ }
+ }
+ }
+ else {
+ if (hash->local)
+ *node = D_CALLOC(1, sizeof(FusionHashNode));
+ else
+ *node = SHCALLOC(hash->pool, 1, sizeof(FusionHashNode));
+
+ if ( !(*node) )
+ return hash->local?DR_NOLOCALMEMORY:DR_NOSHAREDMEMORY;
+
+ hash->nnodes++;
+ }
+ (*node)->key = (void*)key;
+ (*node)->value = (void*)value;
+
+ return DR_OK;
+}
+
+/**
+ * fusion_hash_remove:
+ * @hash: a #FusionHash.
+ * @key: the key to remove.
+ * @old_key: returned old_key
+ * @old_value: returned old_value
+ * Removes a key and its associated value from a #FusionHash.
+ *
+ * If the #FusionHash was created using hash_new_full(), the
+ * key and value are freed using the supplied destroy functions, otherwise
+ * you have to make sure that any dynamically allocated values are freed
+ * yourself.
+ * If you supplied a oldkey pointer or oldkey value they are returned
+ * otherwise free is called the key if table type is not type HASH_INT
+ * and free is called on the old value if not supplied
+ *
+ **/
+DirectResult
+fusion_hash_remove (FusionHash *hash,
+ const void * key,
+ void **old_key,
+ void **old_value)
+{
+ FusionHashNode **node, *dest;
+ D_MAGIC_ASSERT( hash, FusionHash );
+
+ node = fusion_hash_lookup_node (hash, key);
+ if (*node) {
+ dest = *node;
+ (*node) = dest->next;
+ fusion_hash_node_destroy(hash, dest, old_key, old_value);
+ hash->nnodes--;
+ return DR_OK;
+ }
+ return DR_OK;
+}
+
+/**
+ * hash_foreach:
+ * @hash: a #FusionHash.
+ * @func: the function to call for each key/value pair.
+ * @user_data: user data to pass to the function.
+ *
+ * Calls the given function for each of the key/value pairs in the
+ * #FusionHash. The function is passed the key and value of each
+ * pair, and the given @user_data parameter. The hash table may not
+ * be modified while iterating over it (you can't add/remove
+ * items). To remove all items matching a predicate, use
+ * hash_foreach_remove().
+ **/
+void
+fusion_hash_iterate( FusionHash *hash,
+ FusionHashIteratorFunc func,
+ void *ctx )
+{
+ int i;
+ FusionHashNode *node;
+ FusionHashNode *next;
+
+ D_MAGIC_ASSERT( hash, FusionHash );
+
+ for (i = 0; i < hash->size; i++) {
+ for (node = hash->nodes[i]; node; node = next) {
+ next = node->next;
+
+ if ( func(hash, node->key, node->value, ctx))
+ return;
+ }
+ }
+}
+
+/**
+ * hash_size:
+ * @hash: a #FusionHash.
+ *
+ * Returns the number of elements contained in the #FusionHash.
+ *
+ * Return value: the number of key/value pairs in the #FusionHash.
+ **/
+unsigned int
+fusion_hash_size (FusionHash *hash)
+{
+ D_MAGIC_ASSERT( hash, FusionHash );
+ return hash->nnodes;
+}
+
+/**
+ * fusion_hash_should_resize:
+ * Call the function after adding or removing several
+ * values it has a decent heurisitc to determine if
+ * the hash has grown to large
+ */
+bool fusion_hash_should_resize ( FusionHash *hash)
+{
+ D_MAGIC_ASSERT( hash, FusionHash );
+ if ((hash->size >= 3 * hash->nnodes &&
+ hash->size > FUSION_HASH_MIN_SIZE) ||
+ (3 * hash->size <= hash->nnodes &&
+ hash->size < FUSION_HASH_MAX_SIZE))
+ return true;
+ return false;
+}
+
+/* Hash Functions
+ * Resize the hash to minumim for this number of entries
+ */
+DirectResult
+fusion_hash_resize (FusionHash *hash)
+{
+ FusionHashNode **new_nodes;
+ FusionHashNode *node;
+ FusionHashNode *next;
+ unsigned int hash_val;
+ int new_size;
+ int i;
+ D_MAGIC_ASSERT( hash, FusionHash );
+
+ new_size = spaced_primes_closest (hash->nnodes);
+ if (new_size > FUSION_HASH_MAX_SIZE )
+ new_size = FUSION_HASH_MAX_SIZE;
+ if (new_size < FUSION_HASH_MIN_SIZE)
+ new_size = FUSION_HASH_MIN_SIZE;
+
+ if (hash->local)
+ new_nodes = D_CALLOC (new_size, sizeof(FusionHashNode*));
+ else
+ new_nodes = SHCALLOC (hash->pool, new_size, sizeof(FusionHashNode*));
+ if (!new_nodes)
+ return hash->local?DR_NOLOCALMEMORY:DR_NOSHAREDMEMORY;
+
+ for (i = 0; i < hash->size; i++)
+ for (node = hash->nodes[i]; node; node = next) {
+ next = node->next;
+ /*TODO We could also optimize pointer hashing*/
+ if (hash->key_type == HASH_STRING ) {
+ unsigned int h;
+ const signed char *p = node->key;
+ HASH_STR(h, p)
+ hash_val = h % new_size;
+ }
+ else
+ hash_val = ((unsigned long)node->key) % new_size;
+
+ node->next = new_nodes[hash_val];
+ new_nodes[hash_val] = node;
+ }
+ if (hash->local)
+ D_FREE(hash->nodes);
+ else
+ SHFREE(hash->pool, hash->nodes);
+ hash->nodes = new_nodes;
+ hash->size = new_size;
+ return true;
+}
+
+
+static void
+fusion_hash_node_destroy (FusionHash *hash,FusionHashNode *node,
+ void **old_key,void **old_value)
+{
+ if (!node )
+ return;
+
+ if ( old_key)
+ *old_key = node->key;
+ else if ( hash->key_type != HASH_INT ) {
+ if (hash->free_keys) {
+ if ( hash->local)
+ D_FREE(node->key );
+ else
+ SHFREE(hash->pool,node->key );
+ }
+ }
+
+ if ( old_value)
+ *old_value = node->value;
+ else if ( hash->value_type != HASH_INT ) {
+ if (hash->free_values) {
+ if ( hash->local)
+ D_FREE(node->value );
+ else
+ SHFREE(hash->pool,node->value );
+ }
+ }
+
+ if ( hash->local)
+ D_FREE(node);
+ else
+ SHFREE(hash->pool,node);
+}
+
diff --git a/Source/DirectFB/lib/fusion/hash.h b/Source/DirectFB/lib/fusion/hash.h
new file mode 100755
index 0000000..8c8b459
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/hash.h
@@ -0,0 +1,179 @@
+/*
+ GLIB - Library of useful routines for C programming
+ Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi>,
+ Claudio Ciccani <klan@users.sf.net> and
+ Michael Emmel <memmel@gmail.com>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Modified by the GLib Team and others 1997-2000. See the AUTHORS
+ * file for a list of people on the GLib Team. See the ChangeLog
+ * files for a list of changes. These files are distributed with
+ * GLib at ftp://ftp.gtk.org/pub/gtk/.
+ */
+
+#ifndef __FUSION_HASH_H__
+#define __FUSION_HASH_H__
+
+#include <fusion/types.h>
+#include <fusion/shmalloc.h>
+#include <string.h>
+
+#define FUSION_HASH_MIN_SIZE 11
+#define FUSION_HASH_MAX_SIZE 13845163
+
+#define HASH_STR(h,p) \
+{\
+ h = *p;\
+ if (h)\
+ for (p += 1; *p != '\0'; p++)\
+ h = (h << 5) - h + *p;\
+}\
+
+typedef enum {
+HASH_PTR,
+HASH_STRING,
+HASH_INT
+}
+FusionHashType;
+
+typedef struct _FusionHashNode FusionHashNode;
+
+struct _FusionHashNode
+{
+ void *key;
+ void *value;
+ FusionHashNode *next;
+};
+
+struct __Fusion_FusionHash
+{
+ int magic;
+ bool local;
+ FusionHashType key_type;
+ FusionHashType value_type;
+ int size;
+ int nnodes;
+ FusionHashNode **nodes;
+ FusionSHMPoolShared *pool;
+
+ bool free_keys;
+ bool free_values;
+};
+
+typedef bool (*FusionHashIteratorFunc)( FusionHash *hash,
+ void *key,
+ void *value,
+ void *ctx );
+
+
+DirectResult
+fusion_hash_resize (FusionHash *hash);
+
+DirectResult
+fusion_hash_create (FusionSHMPoolShared *pool,
+ FusionHashType key_type,
+ FusionHashType value_type,
+ int size, FusionHash **ret_hash );
+
+DirectResult
+fusion_hash_create_local (FusionHashType key_type, FusionHashType value_type,
+ int size, FusionHash **ret_hash );
+
+DirectResult
+fusion_hash_remove (FusionHash *hash,
+ const void * key,
+ void **old_key,
+ void **old_value);
+
+DirectResult
+fusion_hash_insert( FusionHash *hash, void *key, void *value );
+
+DirectResult
+fusion_hash_replace (FusionHash *hash,
+ void * key,
+ void * value,
+ void **old_key,
+ void **old_value);
+void
+fusion_hash_destroy( FusionHash *hash );
+
+void
+fusion_hash_set_autofree( FusionHash *hash, bool free_keys, bool free_values );
+
+void *
+fusion_hash_lookup (FusionHash *hash, const void * key);
+
+void
+fusion_hash_iterate( FusionHash *hash,
+ FusionHashIteratorFunc func,
+ void *ctx );
+
+unsigned int
+fusion_hash_size (FusionHash *hash);
+
+bool fusion_hash_should_resize ( FusionHash *hash);
+
+
+static inline FusionHashNode**
+fusion_hash_lookup_node (FusionHash *hash,
+ const void * key)
+{
+ FusionHashNode **node;
+
+ /*TODO We could also optimize pointer hashing*/
+ if (hash->key_type == HASH_STRING )
+ {
+ unsigned int h;
+ const signed char *p = key;
+ HASH_STR(h,p)
+ node = &hash->nodes[h % hash->size];
+ }
+ else
+ node = &hash->nodes[((unsigned long)key) % hash->size];
+
+ /* Hash table lookup needs to be fast.
+ * We therefore remove the extra conditional of testing
+ * whether to call the key_equal_func or not from
+ * the inner loop.
+ */
+ if (hash->key_type == HASH_STRING ) {
+ while(*node && strcmp((const char *)(*node)->key,(const char*)key))
+ node = &(*node)->next;
+ }
+ else
+ while (*node && (*node)->key != key)
+ node = &(*node)->next;
+
+ return node;
+
+}
+
+
+
+#endif /*__FUSION_HASH_H__*/
+
diff --git a/Source/DirectFB/lib/fusion/lock.c b/Source/DirectFB/lib/fusion/lock.c
new file mode 100755
index 0000000..33945c5
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/lock.c
@@ -0,0 +1,687 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/param.h>
+
+#include <direct/debug.h>
+#include <direct/messages.h>
+#include <direct/util.h>
+
+#include <fusion/build.h>
+#include <fusion/types.h>
+#include <fusion/lock.h>
+#include <fusion/shmalloc.h>
+
+#include "fusion_internal.h"
+
+
+#if FUSION_BUILD_MULTI
+
+D_DEBUG_DOMAIN( Fusion_Skirmish, "Fusion/Skirmish", "Fusion's Skirmish (Mutex)" );
+
+
+#if FUSION_BUILD_KERNEL
+
+DirectResult
+fusion_skirmish_init( FusionSkirmish *skirmish,
+ const char *name,
+ const FusionWorld *world )
+{
+ FusionEntryInfo info;
+
+ D_ASSERT( skirmish != NULL );
+ D_ASSERT( name != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ D_DEBUG_AT( Fusion_Skirmish, "fusion_skirmish_init( %p, '%s' )\n", skirmish, name ? : "" );
+
+ while (ioctl( world->fusion_fd, FUSION_SKIRMISH_NEW, &skirmish->multi.id )) {
+ if (errno == EINTR)
+ continue;
+
+ D_PERROR( "FUSION_SKIRMISH_NEW" );
+ return DR_FUSION;
+ }
+
+ D_DEBUG_AT( Fusion_Skirmish, " -> new skirmish %p [%d]\n", skirmish, skirmish->multi.id );
+
+ info.type = FT_SKIRMISH;
+ info.id = skirmish->multi.id;
+
+ direct_snputs( info.name, name, sizeof(info.name) );
+
+ ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info );
+
+ /* Keep back pointer to shared world data. */
+ skirmish->multi.shared = world->shared;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_prevail( FusionSkirmish *skirmish )
+{
+ D_ASSERT( skirmish != NULL );
+
+ while (ioctl (_fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_PREVAIL, &skirmish->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR ("Fusion/Lock: invalid skirmish\n");
+ return DR_DESTROYED;
+ }
+
+ D_PERROR ("FUSION_SKIRMISH_PREVAIL");
+ return DR_FUSION;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_swoop( FusionSkirmish *skirmish )
+{
+ D_ASSERT( skirmish != NULL );
+
+ while (ioctl (_fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_SWOOP, &skirmish->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EAGAIN:
+ return DR_BUSY;
+
+ case EINVAL:
+ D_ERROR ("Fusion/Lock: invalid skirmish\n");
+ return DR_DESTROYED;
+ }
+
+ D_PERROR ("FUSION_SKIRMISH_SWOOP");
+ return DR_FUSION;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_lock_count( FusionSkirmish *skirmish, int *lock_count )
+{
+ int data[2];
+
+ D_ASSERT( skirmish != NULL );
+
+ data[0] = skirmish->multi.id;
+ data[1] = 0;
+
+ while (ioctl (_fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_LOCK_COUNT, data)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR ("Fusion/Lock: invalid skirmish\n");
+ return DR_DESTROYED;
+ }
+
+ D_PERROR ("FUSION_SKIRMISH_LOCK_COUNT");
+ return DR_FUSION;
+ }
+
+ *lock_count = data[1];
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_dismiss (FusionSkirmish *skirmish)
+{
+ D_ASSERT( skirmish != NULL );
+
+ while (ioctl (_fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_DISMISS, &skirmish->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR ("Fusion/Lock: invalid skirmish\n");
+ return DR_DESTROYED;
+ }
+
+ D_PERROR ("FUSION_SKIRMISH_DISMISS");
+ return DR_FUSION;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_destroy (FusionSkirmish *skirmish)
+{
+ D_ASSERT( skirmish != NULL );
+
+ D_DEBUG_AT( Fusion_Skirmish, "fusion_skirmish_destroy( %p [%d] )\n", skirmish, skirmish->multi.id );
+
+ while (ioctl( _fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_DESTROY, &skirmish->multi.id )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR ("Fusion/Lock: invalid skirmish\n");
+ return DR_DESTROYED;
+ }
+
+ D_PERROR ("FUSION_SKIRMISH_DESTROY");
+ return DR_FUSION;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_wait( FusionSkirmish *skirmish, unsigned int timeout )
+{
+ FusionSkirmishWait wait;
+
+ D_ASSERT( skirmish != NULL );
+
+ wait.id = skirmish->multi.id;
+ wait.timeout = timeout;
+ wait.lock_count = 0;
+
+ while (ioctl (_fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_WAIT, &wait)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case ETIMEDOUT:
+ return DR_TIMEOUT;
+
+ case EINVAL:
+ D_ERROR ("Fusion/Lock: invalid skirmish\n");
+ return DR_DESTROYED;
+ }
+
+ D_PERROR ("FUSION_SKIRMISH_WAIT");
+ return DR_FUSION;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_notify( FusionSkirmish *skirmish )
+{
+ D_ASSERT( skirmish != NULL );
+
+ while (ioctl (_fusion_fd( skirmish->multi.shared ), FUSION_SKIRMISH_NOTIFY, &skirmish->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR ("Fusion/Lock: invalid skirmish\n");
+ return DR_DESTROYED;
+ }
+
+ D_PERROR ("FUSION_SKIRMISH_NOTIFY");
+ return DR_FUSION;
+ }
+
+ return DR_OK;
+}
+
+#else /* FUSION_BUILD_KERNEL */
+
+#include <direct/clock.h>
+#include <direct/list.h>
+#include <direct/system.h>
+
+typedef struct {
+ DirectLink link;
+
+ pid_t pid;
+ bool notified;
+} WaitNode;
+
+
+DirectResult
+fusion_skirmish_init( FusionSkirmish *skirmish,
+ const char *name,
+ const FusionWorld *world )
+{
+ D_ASSERT( skirmish != NULL );
+ //D_ASSERT( name != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ D_DEBUG_AT( Fusion_Skirmish, "fusion_skirmish_init( %p, '%s' )\n",
+ skirmish, name ? : "" );
+
+ skirmish->multi.id = ++world->shared->lock_ids;
+
+ /* Set state to unlocked. */
+ skirmish->multi.builtin.locked = 0;
+ skirmish->multi.builtin.owner = 0;
+
+ skirmish->multi.builtin.waiting = NULL;
+
+ skirmish->multi.builtin.requested = false;
+ skirmish->multi.builtin.destroyed = false;
+
+ /* Keep back pointer to shared world data. */
+ skirmish->multi.shared = world->shared;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_prevail( FusionSkirmish *skirmish )
+{
+ D_ASSERT( skirmish != NULL );
+
+ if (skirmish->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ asm( "" ::: "memory" );
+
+ if (skirmish->multi.builtin.locked &&
+ skirmish->multi.builtin.owner != direct_gettid())
+ {
+ int count = 0;
+
+ while (skirmish->multi.builtin.locked) {
+ /* Check whether owner exited without unlocking. */
+ if (kill( skirmish->multi.builtin.owner, 0 ) < 0 && errno == ESRCH) {
+ skirmish->multi.builtin.locked = 0;
+ skirmish->multi.builtin.requested = false;
+ break;
+ }
+
+ skirmish->multi.builtin.requested = true;
+
+ asm( "" ::: "memory" );
+
+ if (++count > 1000) {
+ usleep( 10000 );
+ count = 0;
+ }
+ else {
+ direct_sched_yield();
+ }
+
+ if (skirmish->multi.builtin.destroyed)
+ return DR_DESTROYED;
+ }
+ }
+
+ skirmish->multi.builtin.locked++;
+ skirmish->multi.builtin.owner = direct_gettid();
+
+ asm( "" ::: "memory" );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_swoop( FusionSkirmish *skirmish )
+{
+ D_ASSERT( skirmish != NULL );
+
+ if (skirmish->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ asm( "" ::: "memory" );
+
+ if (skirmish->multi.builtin.locked &&
+ skirmish->multi.builtin.owner != direct_gettid()) {
+ /* Check whether owner exited without unlocking. */
+ if (kill( skirmish->multi.builtin.owner, 0 ) < 0 && errno == ESRCH) {
+ skirmish->multi.builtin.locked = 0;
+ skirmish->multi.builtin.requested = false;
+ }
+ else
+ return DR_BUSY;
+ }
+
+ skirmish->multi.builtin.locked++;
+ skirmish->multi.builtin.owner = direct_gettid();
+
+ asm( "" ::: "memory" );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_lock_count( FusionSkirmish *skirmish, int *lock_count )
+{
+ D_ASSERT( skirmish != NULL );
+
+ if (skirmish->multi.builtin.destroyed) {
+ *lock_count = 0;
+ return DR_DESTROYED;
+ }
+
+ *lock_count = skirmish->multi.builtin.locked;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_dismiss (FusionSkirmish *skirmish)
+{
+ D_ASSERT( skirmish != NULL );
+
+ if (skirmish->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ asm( "" ::: "memory" );
+
+ if (skirmish->multi.builtin.locked) {
+ if (skirmish->multi.builtin.owner != direct_gettid()) {
+ D_ERROR( "Fusion/Skirmish: "
+ "Tried to dismiss a skirmish not owned by current process!\n" );
+ return DR_ACCESSDENIED;
+ }
+
+ if (--skirmish->multi.builtin.locked == 0) {
+ skirmish->multi.builtin.owner = 0;
+
+ if (skirmish->multi.builtin.requested) {
+ skirmish->multi.builtin.requested = false;
+ direct_sched_yield();
+ }
+ }
+ }
+
+ asm( "" ::: "memory" );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_destroy (FusionSkirmish *skirmish)
+{
+ D_ASSERT( skirmish != NULL );
+
+ D_DEBUG_AT( Fusion_Skirmish, "fusion_skirmish_destroy( %p )\n", skirmish );
+
+ if (skirmish->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ if (skirmish->multi.builtin.waiting)
+ fusion_skirmish_notify( skirmish );
+
+ skirmish->multi.builtin.destroyed = true;
+
+ return DR_OK;
+}
+
+#ifdef SIGRTMAX
+# define SIGRESTART SIGRTMAX
+#else
+# define SIGRESTART SIGCONT
+#endif
+
+static void restart_handler( int s ) {}
+
+DirectResult
+fusion_skirmish_wait( FusionSkirmish *skirmish, unsigned int timeout )
+{
+ WaitNode *node;
+ long long stop;
+ struct sigaction act, oldact;
+ sigset_t mask, set;
+ DirectResult ret = DR_OK;
+
+ D_ASSERT( skirmish != NULL );
+
+ if (skirmish->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ /* Set timeout. */
+ stop = direct_clock_get_micros() + timeout * 1000ll;
+
+ /* Add ourself to the list of waiting processes. */
+ node = SHMALLOC( skirmish->multi.shared->main_pool, sizeof(WaitNode) );
+ if (!node)
+ return D_OOSHM();
+
+ node->pid = direct_gettid();
+ node->notified = false;
+
+ direct_list_append( &skirmish->multi.builtin.waiting, &node->link );
+
+ /* Install a (fake) signal handler for SIGRESTART. */
+ act.sa_handler = restart_handler;
+ act.sa_flags = SA_RESETHAND | SA_RESTART | SA_NOMASK;
+
+ sigaction( SIGRESTART, &act, &oldact );
+
+ /* Unblock SIGRESTART. */
+ sigprocmask( SIG_SETMASK, NULL, &mask );
+ sigdelset( &mask, SIGRESTART );
+
+ fusion_skirmish_dismiss( skirmish );
+
+ while (!node->notified) {
+ if (timeout) {
+ long long now = direct_clock_get_micros();
+
+ if (now >= stop) {
+ /* Stop notifying us. */
+ node->notified = true;
+ ret = DR_TIMEOUT;
+ break;
+ }
+
+ sigprocmask( SIG_SETMASK, &mask, &set );
+ usleep( stop - now );
+ sigprocmask( SIG_SETMASK, &set, NULL );
+ }
+ else {
+ sigsuspend( &mask );
+ }
+ }
+
+ /* Flush pending signals. */
+ if (!sigpending( &set ) && sigismember( &set, SIGRESTART ) > 0)
+ sigsuspend( &mask );
+
+ if (fusion_skirmish_prevail( skirmish ))
+ ret = DR_DESTROYED;
+
+ direct_list_remove( &skirmish->multi.builtin.waiting, &node->link );
+
+ SHFREE( skirmish->multi.shared->main_pool, node );
+
+ sigaction( SIGRESTART, &oldact, NULL );
+
+ return ret;
+}
+
+DirectResult
+fusion_skirmish_notify( FusionSkirmish *skirmish )
+{
+ WaitNode *node, *temp;
+
+ D_ASSERT( skirmish != NULL );
+
+ if (skirmish->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ direct_list_foreach_safe (node, temp, skirmish->multi.builtin.waiting) {
+ if (node->notified)
+ continue;
+
+ node->notified = true;
+
+ if (kill( node->pid, SIGRESTART ) < 0) {
+ if (errno == ESRCH) {
+ /* Remove dead process. */
+ direct_list_remove( &skirmish->multi.builtin.waiting, &node->link );
+ SHFREE( skirmish->multi.shared->main_pool, node );
+ }
+ else {
+ D_PERROR( "Fusion/Skirmish: Couldn't send notification signal!\n" );
+ }
+ }
+ }
+
+ return DR_OK;
+}
+
+#endif /* FUSION_BUILD_KERNEL */
+
+#else /* FUSION_BUILD_MULTI */
+
+DirectResult
+fusion_skirmish_init( FusionSkirmish *skirmish,
+ const char *name,
+ const FusionWorld *world )
+{
+ D_ASSERT( skirmish != NULL );
+
+ direct_util_recursive_pthread_mutex_init( &skirmish->single.lock );
+ pthread_cond_init( &skirmish->single.cond, NULL );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_prevail (FusionSkirmish *skirmish)
+{
+ D_ASSERT( skirmish != NULL );
+
+ if (pthread_mutex_lock( &skirmish->single.lock ))
+ return errno2result( errno );
+
+ skirmish->single.count++;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_swoop (FusionSkirmish *skirmish)
+{
+ D_ASSERT( skirmish != NULL );
+
+ if (pthread_mutex_trylock( &skirmish->single.lock ))
+ return errno2result( errno );
+
+ skirmish->single.count++;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_lock_count( FusionSkirmish *skirmish, int *lock_count )
+{
+ D_ASSERT( skirmish != NULL );
+ D_ASSERT( lock_count != NULL );
+
+ if (pthread_mutex_trylock( &skirmish->single.lock )) {
+ *lock_count = 0;
+ return errno2result( errno );
+ }
+
+ *lock_count = skirmish->single.count;
+
+ pthread_mutex_unlock( &skirmish->single.lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_dismiss (FusionSkirmish *skirmish)
+{
+ D_ASSERT( skirmish != NULL );
+
+ skirmish->single.count--;
+
+ if (pthread_mutex_unlock( &skirmish->single.lock ))
+ return errno2result( errno );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_skirmish_destroy (FusionSkirmish *skirmish)
+{
+ D_ASSERT( skirmish != NULL );
+
+ pthread_cond_broadcast( &skirmish->single.cond );
+ pthread_cond_destroy( &skirmish->single.cond );
+
+ return pthread_mutex_destroy( &skirmish->single.lock );
+}
+
+DirectResult
+fusion_skirmish_wait( FusionSkirmish *skirmish, unsigned int timeout )
+{
+ D_ASSERT( skirmish != NULL );
+
+ if (timeout) {
+ struct timespec ts;
+ struct timeval tv;
+ int ret;
+
+ gettimeofday( &tv, NULL );
+
+ ts.tv_nsec = tv.tv_usec*1000 + (timeout%1000)*1000000;
+ ts.tv_sec = tv.tv_sec + timeout/1000 + ts.tv_nsec/1000000000;
+ ts.tv_nsec = ts.tv_nsec % 1000000000;
+
+ ret = pthread_cond_timedwait( &skirmish->single.cond,
+ &skirmish->single.lock, &ts );
+
+ return (ret == ETIMEDOUT) ? DR_TIMEOUT : DR_OK;
+ }
+
+ return pthread_cond_wait( &skirmish->single.cond, &skirmish->single.lock );
+}
+
+DirectResult
+fusion_skirmish_notify( FusionSkirmish *skirmish )
+{
+ D_ASSERT( skirmish != NULL );
+
+ pthread_cond_broadcast( &skirmish->single.cond );
+
+ return DR_OK;
+}
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/lock.h b/Source/DirectFB/lib/fusion/lock.h
new file mode 100755
index 0000000..d5071bb
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/lock.h
@@ -0,0 +1,122 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__LOCK_H__
+#define __FUSION__LOCK_H__
+
+#include <pthread.h>
+
+#include <fusion/types.h>
+
+#include <direct/messages.h>
+#include <direct/util.h>
+
+
+typedef union {
+ /* multi app */
+ struct {
+ int id;
+ const FusionWorldShared *shared;
+ /* builtin impl */
+ struct {
+ unsigned int locked;
+ pid_t owner;
+ DirectLink *waiting;
+ bool requested;
+ bool destroyed;
+ } builtin;
+ } multi;
+
+ /* single app */
+ struct {
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ int count;
+ } single;
+} FusionSkirmish;
+
+/*
+ * Initialize.
+ */
+DirectResult fusion_skirmish_init ( FusionSkirmish *skirmish,
+ const char *name,
+ const FusionWorld *world );
+
+/*
+ * Lock.
+ */
+DirectResult fusion_skirmish_prevail( FusionSkirmish *skirmish );
+
+/*
+ * Try lock.
+ */
+DirectResult fusion_skirmish_swoop ( FusionSkirmish *skirmish );
+
+/*
+ * Find out how many times current thread has acquired lock.
+ */
+DirectResult fusion_skirmish_lock_count( FusionSkirmish *skirmish, int *lock_count );
+
+/*
+ * Unlock.
+ */
+DirectResult fusion_skirmish_dismiss( FusionSkirmish *skirmish );
+
+/*
+ * Deinitialize.
+ */
+DirectResult fusion_skirmish_destroy( FusionSkirmish *skirmish );
+
+/*
+ * Wait & Notify.
+ *
+ * Must be locked!
+ */
+DirectResult fusion_skirmish_wait ( FusionSkirmish *skirmish,
+ unsigned int timeout );
+DirectResult fusion_skirmish_notify ( FusionSkirmish *skirmish );
+
+
+#if D_DEBUG_ENABLED
+#define FUSION_SKIRMISH_ASSERT(skirmish) \
+ do { \
+ int lock_count; \
+ \
+ D_ASSERT( skirmish != NULL ); \
+ \
+ D_ASSERT( fusion_skirmish_lock_count( skirmish, &lock_count ) == DR_OK ); \
+ D_ASSERT( lock_count > 0 ); \
+ } while (0)
+#else
+#define FUSION_SKIRMISH_ASSERT(skirmish) \
+ do { \
+ } while (0)
+#endif
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/object.c b/Source/DirectFB/lib/fusion/object.c
new file mode 100755
index 0000000..9138889
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/object.c
@@ -0,0 +1,640 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#include <sys/param.h>
+
+#include <pthread.h>
+
+#include <direct/debug.h>
+#include <direct/messages.h>
+#include <direct/thread.h>
+
+#include <fusion/build.h>
+#include <fusion/object.h>
+#include <fusion/hash.h>
+#include <fusion/shmalloc.h>
+
+#include "fusion_internal.h"
+
+D_DEBUG_DOMAIN( Fusion_Object, "Fusion/Object", "Fusion Objects and Pools" );
+
+struct __Fusion_FusionObjectPool {
+ int magic;
+
+ FusionWorldShared *shared;
+
+ FusionSkirmish lock;
+ DirectLink *objects;
+ FusionObjectID id_pool;
+
+ char *name;
+ int object_size;
+ int message_size;
+ FusionObjectDestructor destructor;
+ void *ctx;
+
+ FusionCall call;
+};
+
+static FusionCallHandlerResult
+object_reference_watcher( int caller, int call_arg, void *call_ptr, void *ctx, unsigned int serial, int *ret_val )
+{
+ FusionObject *object;
+ FusionObjectPool *pool = ctx;
+
+ D_DEBUG_AT( Fusion_Object, "%s( %d, %d, %p, %p, %u, %p )\n",
+ __FUNCTION__, caller, call_arg, call_ptr, ctx, serial, ret_val );
+
+#if FUSION_BUILD_KERNEL
+ if (caller) {
+ D_BUG( "Call not from Fusion/Kernel (caller %d)", caller );
+ return FCHR_RETURN;
+ }
+#endif
+
+ D_MAGIC_ASSERT( pool, FusionObjectPool );
+
+ /* Lock the pool. */
+ if (fusion_skirmish_prevail( &pool->lock ))
+ return FCHR_RETURN;
+
+ /* Lookup the object. */
+ direct_list_foreach (object, pool->objects) {
+ if (object->id != call_arg)
+ continue;
+
+ D_MAGIC_ASSERT( object, FusionObject );
+
+ switch (fusion_ref_zero_trylock( &object->ref )) {
+ case DR_OK:
+ break;
+
+ case DR_DESTROYED:
+ D_BUG( "already destroyed %p [%ld] in '%s'", object, object->id, pool->name );
+
+ direct_list_remove( &pool->objects, &object->link );
+ fusion_skirmish_dismiss( &pool->lock );
+ return FCHR_RETURN;
+
+
+ default:
+ D_ERROR( "Fusion/ObjectPool: Error locking ref of %p [%ld] in '%s'\n",
+ object, object->id, pool->name );
+ /* fall through */
+
+ case DR_BUSY:
+ fusion_skirmish_dismiss( &pool->lock );
+ return FCHR_RETURN;
+ }
+
+ D_DEBUG_AT( Fusion_Object, "== %s ==\n", pool->name );
+ D_DEBUG_AT( Fusion_Object, " -> dead object %p [%ld]\n", object, object->id );
+
+ if (object->state == FOS_INIT) {
+ D_BUG( "== %s == incomplete object: %d (%p)", pool->name, call_arg, object );
+ D_WARN( "won't destroy incomplete object, leaking some memory" );
+ direct_list_remove( &pool->objects, &object->link );
+ fusion_skirmish_dismiss( &pool->lock );
+ return FCHR_RETURN;
+ }
+
+ /* Set "deinitializing" state. */
+ object->state = FOS_DEINIT;
+
+ /* Remove the object from the pool. */
+ object->pool = NULL;
+ direct_list_remove( &pool->objects, &object->link );
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+
+
+ D_DEBUG_AT( Fusion_Object, " -> calling destructor...\n" );
+
+ /* Call the destructor. */
+ pool->destructor( object, false, pool->ctx );
+
+ D_DEBUG_AT( Fusion_Object, " -> destructor done.\n" );
+
+ return FCHR_RETURN;
+ }
+
+ D_BUG( "unknown object [%d] in '%s'", call_arg, pool->name );
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return FCHR_RETURN;
+}
+
+FusionObjectPool *
+fusion_object_pool_create( const char *name,
+ int object_size,
+ int message_size,
+ FusionObjectDestructor destructor,
+ void *ctx,
+ const FusionWorld *world )
+{
+ FusionObjectPool *pool;
+ FusionWorldShared *shared;
+
+ D_ASSERT( name != NULL );
+ D_ASSERT( object_size >= sizeof(FusionObject) );
+ D_ASSERT( message_size > 0 );
+ D_ASSERT( destructor != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ /* Allocate shared memory for the pool. */
+ pool = SHCALLOC( shared->main_pool, 1, sizeof(FusionObjectPool) );
+ if (!pool) {
+ D_OOSHM();
+ return NULL;
+ }
+
+ /* Initialize the pool lock. */
+ fusion_skirmish_init( &pool->lock, name, world );
+
+ /* Fill information. */
+ pool->shared = shared;
+ pool->name = SHSTRDUP( shared->main_pool, name );
+ pool->object_size = object_size;
+ pool->message_size = message_size;
+ pool->destructor = destructor;
+ pool->ctx = ctx;
+
+ /* Destruction call from Fusion. */
+ fusion_call_init( &pool->call, object_reference_watcher, pool, world );
+
+ D_MAGIC_SET( pool, FusionObjectPool );
+
+ return pool;
+}
+
+DirectResult
+fusion_object_pool_destroy( FusionObjectPool *pool,
+ const FusionWorld *world )
+{
+ DirectResult ret;
+ DirectLink *n;
+ FusionObject *object;
+ FusionWorldShared *shared;
+
+ D_ASSERT( pool != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+ D_ASSERT( shared == pool->shared );
+
+ D_DEBUG_AT( Fusion_Object, "== %s ==\n", pool->name );
+ D_DEBUG_AT( Fusion_Object, " -> destroying pool...\n" );
+
+ D_DEBUG_AT( Fusion_Object, " -> syncing...\n" );
+
+ /* Wait for processing of pending messages. */
+ if (pool->objects)
+ fusion_sync( world );
+
+ D_DEBUG_AT( Fusion_Object, " -> locking...\n" );
+
+ /* Lock the pool. */
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret)
+ return ret;
+
+ /* Destroy the call. */
+ fusion_call_destroy( &pool->call );
+
+ if (pool->objects)
+ D_WARN( "still objects in '%s'", pool->name );
+
+ /* Destroy zombies */
+ direct_list_foreach_safe (object, n, pool->objects) {
+ int refs;
+
+ fusion_ref_stat( &object->ref, &refs );
+
+ D_DEBUG_AT( Fusion_Object, "== %s ==\n", pool->name );
+ D_DEBUG_AT( Fusion_Object, " -> zombie %p [%ld], refs %d\n", object, object->id, refs );
+
+ /* Set "deinitializing" state. */
+ object->state = FOS_DEINIT;
+
+ /* Remove the object from the pool. */
+ //direct_list_remove( &pool->objects, &object->link );
+ //object->pool = NULL;
+
+ D_DEBUG_AT( Fusion_Object, " -> calling destructor...\n" );
+
+ /* Call the destructor. */
+ pool->destructor( object, refs > 0, pool->ctx );
+
+ D_DEBUG_AT( Fusion_Object, " -> destructor done.\n" );
+
+ D_ASSERT( ! direct_list_contains_element_EXPENSIVE( pool->objects, (DirectLink*) object ) );
+ }
+
+ pool->objects = NULL;
+
+ /* Destroy the pool lock. */
+ fusion_skirmish_destroy( &pool->lock );
+
+ D_DEBUG_AT( Fusion_Object, " -> pool destroyed (%s)\n", pool->name );
+
+ D_MAGIC_CLEAR( pool );
+
+ /* Deallocate shared memory. */
+ SHFREE( shared->main_pool, pool->name );
+ SHFREE( shared->main_pool, pool );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_object_pool_enum( FusionObjectPool *pool,
+ FusionObjectCallback callback,
+ void *ctx )
+{
+ FusionObject *object;
+
+ D_MAGIC_ASSERT( pool, FusionObjectPool );
+ D_ASSERT( callback != NULL );
+
+ /* Lock the pool. */
+ if (fusion_skirmish_prevail( &pool->lock ))
+ return DR_FUSION;
+
+ direct_list_foreach (object, pool->objects) {
+ D_MAGIC_ASSERT( object, FusionObject );
+
+ if (!callback( pool, object, ctx ))
+ break;
+ }
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return DR_OK;
+}
+
+FusionObject *
+fusion_object_create( FusionObjectPool *pool,
+ const FusionWorld *world )
+{
+ FusionObject *object;
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( pool, FusionObjectPool );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+ D_ASSERT( shared == pool->shared );
+
+ /* Lock the pool. */
+ if (fusion_skirmish_prevail( &pool->lock ))
+ return NULL;
+
+ /* Allocate shared memory for the object. */
+ object = SHCALLOC( shared->main_pool, 1, pool->object_size );
+ if (!object) {
+ D_OOSHM();
+ fusion_skirmish_dismiss( &pool->lock );
+ return NULL;
+ }
+
+ /* Set "initializing" state. */
+ object->state = FOS_INIT;
+
+ /* Set object id. */
+ object->id = ++pool->id_pool;
+
+ /* Initialize the reference counter. */
+ if (fusion_ref_init( &object->ref, pool->name, world )) {
+ SHFREE( shared->main_pool, object );
+ fusion_skirmish_dismiss( &pool->lock );
+ return NULL;
+ }
+
+ /* Increase the object's reference counter. */
+ fusion_ref_up( &object->ref, false );
+
+ /* Install handler for automatic destruction. */
+ if (fusion_ref_watch( &object->ref, &pool->call, object->id )) {
+ fusion_ref_destroy( &object->ref );
+ SHFREE( shared->main_pool, object );
+ fusion_skirmish_dismiss( &pool->lock );
+ return NULL;
+ }
+
+ /* Create a reactor for message dispatching. */
+ object->reactor = fusion_reactor_new( pool->message_size, pool->name, world );
+ if (!object->reactor) {
+ fusion_ref_destroy( &object->ref );
+ SHFREE( shared->main_pool, object );
+ fusion_skirmish_dismiss( &pool->lock );
+ return NULL;
+ }
+
+ fusion_reactor_set_lock( object->reactor, &pool->lock );
+
+ /* Set pool/world back pointer. */
+ object->pool = pool;
+ object->shared = shared;
+
+ /* Add the object to the pool. */
+ direct_list_prepend( &pool->objects, &object->link );
+
+ D_DEBUG_AT( Fusion_Object, "== %s ==\n", pool->name );
+
+#if FUSION_BUILD_MULTI
+ D_DEBUG_AT( Fusion_Object, " -> added %p with ref [0x%x]\n", object, object->ref.multi.id );
+#else
+ D_DEBUG_AT( Fusion_Object, " -> added %p\n", object );
+#endif
+
+ D_MAGIC_SET( object, FusionObject );
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return object;
+}
+
+DirectResult
+fusion_object_get( FusionObjectPool *pool,
+ FusionObjectID object_id,
+ FusionObject **ret_object )
+{
+ DirectResult ret = DR_IDNOTFOUND;
+ FusionObject *object;
+
+ D_MAGIC_ASSERT( pool, FusionObjectPool );
+ D_ASSERT( ret_object != NULL );
+
+ /* Lock the pool. */
+ if (fusion_skirmish_prevail( &pool->lock ))
+ return DR_FUSION;
+
+ direct_list_foreach (object, pool->objects) {
+ D_MAGIC_ASSERT( object, FusionObject );
+
+ if (object->id == object_id) {
+ ret = fusion_object_ref( object );
+ break;
+ }
+ }
+
+ if (ret == DR_OK)
+ *ret_object = object;
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return ret;
+}
+
+DirectResult
+fusion_object_set_lock( FusionObject *object,
+ FusionSkirmish *lock )
+{
+ D_MAGIC_ASSERT( object, FusionObject );
+
+ D_ASSERT( lock != NULL );
+
+ D_ASSUME( object->state == FOS_INIT );
+
+ return fusion_reactor_set_lock_only( object->reactor, lock );
+}
+
+DirectResult
+fusion_object_activate( FusionObject *object )
+{
+ D_MAGIC_ASSERT( object, FusionObject );
+
+ /* Set "active" state. */
+ object->state = FOS_ACTIVE;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_object_destroy( FusionObject *object )
+{
+ FusionObjectPool *pool;
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( object, FusionObject );
+ D_ASSERT( object->state != FOS_ACTIVE );
+
+ shared = object->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ pool = object->pool;
+
+// D_ASSUME( pool != NULL );
+
+ /* Set "deinitializing" state. */
+ object->state = FOS_DEINIT;
+
+ /* Remove the object from the pool. */
+ if (pool) {
+ D_MAGIC_ASSERT( pool, FusionObjectPool );
+
+ /* Lock the pool. */
+ if (fusion_skirmish_prevail( &pool->lock ))
+ return DR_FAILURE;
+
+ D_MAGIC_ASSERT( pool, FusionObjectPool );
+
+ D_ASSUME( object->pool != NULL );
+
+ /* Remove the object from the pool. */
+ if (object->pool) {
+ D_ASSERT( object->pool == pool );
+
+ object->pool = NULL;
+
+ direct_list_remove( &pool->objects, &object->link );
+ }
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+ }
+
+ fusion_ref_destroy( &object->ref );
+
+ fusion_reactor_free( object->reactor );
+
+ if ( object->properties )
+ fusion_hash_destroy(object->properties);
+
+ D_MAGIC_CLEAR( object );
+ SHFREE( shared->main_pool, object );
+ return DR_OK;
+}
+
+/*
+ * Sets a value for a key.
+ * If the key currently has a value the old value is returned
+ * in old_value.
+ * If old_value is null the object is freed with SHFREE.
+ * If this is not the correct semantics for your data, if for example
+ * its reference counted you must pass in a old_value.
+ */
+DirectResult
+fusion_object_set_property( FusionObject *object,
+ const char *key,
+ void *value,
+ void **old_value )
+{
+ DirectResult ret;
+ char *sharedkey;
+
+ D_MAGIC_ASSERT( object, FusionObject );
+ D_ASSERT( object->shared != NULL );
+ D_ASSERT( key != NULL );
+ D_ASSERT( value != NULL );
+
+ /* Create property hash on demand. */
+ if (!object->properties) {
+ ret = fusion_hash_create( object->shared->main_pool,
+ HASH_STRING, HASH_PTR,
+ FUSION_HASH_MIN_SIZE,
+ &object->properties );
+ if (ret)
+ return ret;
+ }
+
+ /* Create a shared copy of the key. */
+ sharedkey = SHSTRDUP( object->shared->main_pool, key );
+ if (!sharedkey)
+ return D_OOSHM();
+
+ /* Put it into the hash. */
+ ret = fusion_hash_replace( object->properties, sharedkey,
+ value, NULL, old_value );
+ if (ret)
+ SHFREE( object->shared->main_pool, sharedkey );
+
+ return ret;
+}
+
+/*
+ * Helper function for int values
+ */
+DirectResult
+fusion_object_set_int_property( FusionObject *object,
+ const char *key,
+ int value )
+{
+ DirectResult ret;
+ int *iptr;
+
+ D_MAGIC_ASSERT( object, FusionObject );
+ D_ASSERT( key != NULL );
+
+ iptr = SHMALLOC( object->shared->main_pool, sizeof(int) );
+ if (!iptr)
+ return D_OOSHM();
+
+ *iptr = value;
+
+ ret = fusion_object_set_property( object, key, iptr, NULL );
+ if (ret)
+ SHFREE( object->shared->main_pool, iptr );
+
+ return ret;
+}
+
+/*
+ * Helper function for char* values use if the string
+ * is not in shared memory
+ * Assumes that the old value was a string and frees it.
+ */
+DirectResult
+fusion_object_set_string_property( FusionObject *object,
+ const char *key,
+ char *value )
+{
+ DirectResult ret;
+ char *copy;
+
+ D_MAGIC_ASSERT( object, FusionObject );
+ D_ASSERT( key != NULL );
+ D_ASSERT( value != NULL );
+
+ copy = SHSTRDUP( object->shared->main_pool, value );
+ if (!copy)
+ return D_OOSHM();
+
+ ret = fusion_object_set_property( object, key, copy, NULL );
+ if (ret)
+ SHFREE( object->shared->main_pool, copy );
+
+ return ret;
+}
+
+void *
+fusion_object_get_property( FusionObject *object, const char *key )
+{
+ D_MAGIC_ASSERT( object, FusionObject );
+ D_ASSERT( key != NULL );
+
+ if (!object->properties)
+ return NULL;
+
+ return fusion_hash_lookup( object->properties, key );
+}
+
+void
+fusion_object_remove_property( FusionObject *object,
+ const char *key,
+ void **old_value)
+{
+ D_MAGIC_ASSERT( object, FusionObject );
+ D_ASSERT( key != NULL );
+
+ if (!object->properties)
+ return;
+
+ fusion_hash_remove( object->properties, key, NULL, old_value );
+
+ if (fusion_hash_should_resize( object->properties ))
+ fusion_hash_resize( object->properties );
+}
+
diff --git a/Source/DirectFB/lib/fusion/object.h b/Source/DirectFB/lib/fusion/object.h
new file mode 100755
index 0000000..ae75374
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/object.h
@@ -0,0 +1,279 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__OBJECT_H__
+#define __FUSION__OBJECT_H__
+
+#include <fusion/types.h>
+
+#include <fusion/lock.h>
+#include <direct/list.h>
+#include <fusion/ref.h>
+#include <fusion/reactor.h>
+#include <direct/debug.h>
+
+typedef void (*FusionObjectDestructor)( FusionObject *object, bool zombie, void *ctx );
+
+typedef bool (*FusionPropIterator)( char *key, void *value, void *ctx);
+
+
+
+
+typedef unsigned long FusionObjectID;
+
+
+typedef enum {
+ FOS_INIT,
+ FOS_ACTIVE,
+ FOS_DEINIT
+} FusionObjectState;
+
+struct __Fusion_FusionObject {
+ DirectLink link;
+ FusionObjectPool *pool;
+
+ int magic;
+
+ FusionObjectID id;
+
+ FusionObjectState state;
+
+ FusionRef ref;
+ FusionReactor *reactor;
+
+ FusionWorldShared *shared;
+ FusionHash *properties;
+};
+
+
+typedef bool (*FusionObjectCallback)( FusionObjectPool *pool,
+ FusionObject *object,
+ void *ctx );
+
+
+FusionObjectPool *fusion_object_pool_create ( const char *name,
+ int object_size,
+ int message_size,
+ FusionObjectDestructor destructor,
+ void *ctx,
+ const FusionWorld *world );
+
+DirectResult fusion_object_pool_destroy( FusionObjectPool *pool,
+ const FusionWorld *world );
+
+
+DirectResult fusion_object_pool_enum ( FusionObjectPool *pool,
+ FusionObjectCallback callback,
+ void *ctx );
+
+
+FusionObject *fusion_object_create ( FusionObjectPool *pool,
+ const FusionWorld *world );
+
+DirectResult fusion_object_get ( FusionObjectPool *pool,
+ FusionObjectID object_id,
+ FusionObject **ret_object );
+
+DirectResult fusion_object_set_lock( FusionObject *object,
+ FusionSkirmish *lock );
+
+DirectResult fusion_object_activate( FusionObject *object );
+
+DirectResult fusion_object_destroy ( FusionObject *object );
+
+DirectResult fusion_object_set_property( FusionObject *object ,
+ const char *key, void *value, void **old_value);
+
+DirectResult fusion_object_set_int_property( FusionObject *object ,
+ const char *key,int value);
+
+DirectResult fusion_object_set_string_property( FusionObject *object ,
+ const char *key,char *value);
+
+void *fusion_object_get_property( FusionObject *object ,const char *key);
+void fusion_object_remove_property( FusionObject *object ,const char *key,void **ret_val);
+
+#define FUSION_OBJECT_METHODS(type, prefix) \
+ \
+static inline DirectResult \
+prefix##_attach( type *object, \
+ ReactionFunc func, \
+ void *ctx, \
+ Reaction *ret_reaction ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_reactor_attach( ((FusionObject*)object)->reactor, \
+ func, ctx, ret_reaction ); \
+} \
+ \
+static inline DirectResult \
+prefix##_attach_channel( type *object, \
+ int channel, \
+ ReactionFunc func, \
+ void *ctx, \
+ Reaction *ret_reaction ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_reactor_attach_channel( ((FusionObject*)object)->reactor, \
+ channel, func, ctx, ret_reaction ); \
+} \
+ \
+static inline DirectResult \
+prefix##_detach( type *object, \
+ Reaction *reaction ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_reactor_detach( ((FusionObject*)object)->reactor, \
+ reaction ); \
+} \
+ \
+static inline DirectResult \
+prefix##_attach_global( type *object, \
+ int index, \
+ void *ctx, \
+ GlobalReaction *reaction ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_reactor_attach_global( ((FusionObject*)object)->reactor, \
+ index, ctx, reaction ); \
+} \
+ \
+static inline DirectResult \
+prefix##_detach_global( type *object, \
+ GlobalReaction *reaction ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_reactor_detach_global( ((FusionObject*)object)->reactor, \
+ reaction ); \
+} \
+ \
+static inline DirectResult \
+prefix##_dispatch( type *object, \
+ void *message, \
+ const ReactionFunc *globals ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_reactor_dispatch( ((FusionObject*)object)->reactor, \
+ message, true, globals ); \
+} \
+ \
+static inline DirectResult \
+prefix##_dispatch_channel( type *object, \
+ int channel, \
+ void *message, \
+ int size, \
+ const ReactionFunc *globals ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_reactor_dispatch_channel( ((FusionObject*)object)->reactor, \
+ channel, message, size, true, globals ); \
+} \
+ \
+static inline DirectResult \
+prefix##_ref( type *object ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_ref_up( &((FusionObject*)object)->ref, false ); \
+} \
+ \
+static inline DirectResult \
+prefix##_unref( type *object ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_ref_down( &((FusionObject*)object)->ref, false ); \
+} \
+ \
+static inline DirectResult \
+prefix##_ref_stat( type *object, int *refs ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ return fusion_ref_stat ( &((FusionObject*)object)->ref, refs ); \
+} \
+ \
+static inline DirectResult \
+prefix##_link( type **link, \
+ type *object ) \
+{ \
+ DirectResult ret; \
+ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ \
+ ret = fusion_ref_up( &((FusionObject*)object)->ref, true ); \
+ if (ret) \
+ return ret; \
+ \
+ *link = object; \
+ \
+ return DR_OK; \
+} \
+ \
+static inline DirectResult \
+prefix##_unlink( type **link ) \
+{ \
+ type *object = *link; \
+ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ \
+ *link = NULL; \
+ \
+ return fusion_ref_down( &((FusionObject*)object)->ref, true ); \
+} \
+ \
+static inline DirectResult \
+prefix##_inherit( type *object, \
+ void *from ) \
+{ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ D_MAGIC_ASSERT( (FusionObject*) from, FusionObject ); \
+ \
+ return fusion_ref_inherit( &((FusionObject*)object)->ref, \
+ &((FusionObject*)from)->ref ); \
+} \
+ \
+static inline DirectResult \
+prefix##_globalize( type *object ) \
+{ \
+ DirectResult ret; \
+ \
+ D_MAGIC_ASSERT( (FusionObject*) object, FusionObject ); \
+ \
+ ret = fusion_ref_up( &((FusionObject*)object)->ref, true ); \
+ if (ret) \
+ return ret; \
+ \
+ ret = fusion_ref_down( &((FusionObject*)object)->ref, false ); \
+ if (ret) \
+ fusion_ref_down( &((FusionObject*)object)->ref, true ); \
+ \
+ return ret; \
+}
+
+FUSION_OBJECT_METHODS( void, fusion_object )
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/property.c b/Source/DirectFB/lib/fusion/property.c
new file mode 100755
index 0000000..640f572
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/property.c
@@ -0,0 +1,530 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <fusion/build.h>
+
+#include <direct/debug.h>
+#include <direct/messages.h>
+#include <direct/util.h>
+
+#include <fusion/types.h>
+#include <fusion/property.h>
+
+#include "fusion_internal.h"
+
+
+#if FUSION_BUILD_MULTI
+
+#if FUSION_BUILD_KERNEL
+
+DirectResult
+fusion_property_init (FusionProperty *property, const FusionWorld *world)
+{
+ D_ASSERT( property != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ while (ioctl (world->fusion_fd, FUSION_PROPERTY_NEW, &property->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_PROPERTY_NEW");
+
+ return DR_FAILURE;
+ }
+
+ /* Keep back pointer to shared world data. */
+ property->multi.shared = world->shared;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_lease (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ while (ioctl (_fusion_fd( property->multi.shared ), FUSION_PROPERTY_LEASE, &property->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EAGAIN:
+ return DR_BUSY;
+ case EINVAL:
+ D_ERROR ("Fusion/Property: invalid property\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_PROPERTY_LEASE");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_purchase (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ while (ioctl (_fusion_fd( property->multi.shared ), FUSION_PROPERTY_PURCHASE, &property->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EAGAIN:
+ return DR_BUSY;
+ case EINVAL:
+ D_ERROR ("Fusion/Property: invalid property\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_PROPERTY_PURCHASE");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_cede (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ while (ioctl (_fusion_fd( property->multi.shared ), FUSION_PROPERTY_CEDE, &property->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Property: invalid property\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_PROPERTY_CEDE");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_holdup (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ while (ioctl (_fusion_fd( property->multi.shared ), FUSION_PROPERTY_HOLDUP, &property->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Property: invalid property\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_PROPERTY_HOLDUP");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_destroy (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ while (ioctl (_fusion_fd( property->multi.shared ), FUSION_PROPERTY_DESTROY, &property->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Property: invalid property\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_PROPERTY_DESTROY");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+#else /* FUSION_BUILD_KERNEL */
+
+#include <direct/system.h>
+
+DirectResult
+fusion_property_init (FusionProperty *property, const FusionWorld *world)
+{
+ D_ASSERT( property != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ /* Set state to available. */
+ property->multi.builtin.state = FUSION_PROPERTY_AVAILABLE;
+ property->multi.builtin.owner = 0;
+
+ property->multi.builtin.requested = false;
+ property->multi.builtin.destroyed = false;
+
+ /* Keep back pointer to shared world data. */
+ property->multi.shared = world->shared;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_lease (FusionProperty *property)
+{
+ int count = 0;
+
+ D_ASSERT( property != NULL );
+
+ if (property->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ D_ASSUME( property->multi.builtin.owner != direct_gettid() );
+
+ asm( "" ::: "memory" );
+
+ while (property->multi.builtin.state == FUSION_PROPERTY_LEASED) {
+ /* Check whether owner exited without releasing. */
+ if (kill( property->multi.builtin.owner, 0 ) < 0 && errno == ESRCH) {
+ property->multi.builtin.state = FUSION_PROPERTY_AVAILABLE;
+ property->multi.builtin.requested = false;
+ break;
+ }
+
+ property->multi.builtin.requested = true;
+
+ asm( "" ::: "memory" );
+
+ if (++count > 1000) {
+ usleep( 10000 );
+ count = 0;
+ }
+ else {
+ direct_sched_yield();
+ }
+
+ if (property->multi.builtin.destroyed)
+ return DR_DESTROYED;
+ }
+
+ if (property->multi.builtin.state == FUSION_PROPERTY_PURCHASED) {
+ /* Check whether owner exited without releasing. */
+ if (!(kill( property->multi.builtin.owner, 0 ) < 0 && errno == ESRCH))
+ return DR_BUSY;
+ }
+
+ property->multi.builtin.state = FUSION_PROPERTY_LEASED;
+ property->multi.builtin.owner = direct_gettid();
+
+ asm( "" ::: "memory" );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_purchase (FusionProperty *property)
+{
+ int count = 0;
+
+ D_ASSERT( property != NULL );
+
+ if (property->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ D_ASSUME( property->multi.builtin.owner != direct_gettid() );
+
+ asm( "" ::: "memory" );
+
+ while (property->multi.builtin.state == FUSION_PROPERTY_LEASED) {
+ /* Check whether owner exited without releasing. */
+ if (kill( property->multi.builtin.owner, 0 ) < 0 && errno == ESRCH) {
+ property->multi.builtin.state = FUSION_PROPERTY_AVAILABLE;
+ property->multi.builtin.requested = false;
+ break;
+ }
+
+ property->multi.builtin.requested = true;
+
+ asm( "" ::: "memory" );
+
+ if (++count > 1000) {
+ usleep( 10000 );
+ count = 0;
+ }
+ else {
+ direct_sched_yield();
+ }
+
+ if (property->multi.builtin.destroyed)
+ return DR_DESTROYED;
+ }
+
+ if (property->multi.builtin.state == FUSION_PROPERTY_PURCHASED) {
+ /* Check whether owner exited without releasing. */
+ if (!(kill( property->multi.builtin.owner, 0 ) < 0 && errno == ESRCH))
+ return DR_BUSY;
+ }
+
+ property->multi.builtin.state = FUSION_PROPERTY_PURCHASED;
+ property->multi.builtin.owner = direct_gettid();
+
+ asm( "" ::: "memory" );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_cede (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ if (property->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ D_ASSUME( property->multi.builtin.state != FUSION_PROPERTY_AVAILABLE );
+ D_ASSUME( property->multi.builtin.owner == direct_gettid() );
+
+ property->multi.builtin.state = FUSION_PROPERTY_AVAILABLE;
+ property->multi.builtin.owner = 0;
+
+ asm( "" ::: "memory" );
+
+ if (property->multi.builtin.requested) {
+ property->multi.builtin.requested = false;
+ asm( "" ::: "memory" );
+ direct_sched_yield();
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_holdup (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ if (property->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ if (property->multi.builtin.state == FUSION_PROPERTY_PURCHASED &&
+ property->multi.builtin.owner != direct_gettid()) {
+ pid_t pid = property->multi.builtin.owner;
+
+ if (kill( pid, SIGKILL ) < 0 && errno != ESRCH)
+ return DR_UNSUPPORTED;
+
+ /* Wait process termination. */
+ while (kill( pid, 0 ) == 0) {
+ if (property->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ direct_sched_yield();
+ }
+
+ property->multi.builtin.state = FUSION_PROPERTY_AVAILABLE;
+ property->multi.builtin.owner = 0;
+ property->multi.builtin.requested = false;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_property_destroy (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ if (property->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ property->multi.builtin.destroyed = true;
+
+ return DR_OK;
+}
+
+#endif /* FUSION_BUILD_KERNEL */
+
+#else /* FUSION_BUILD_MULTI */
+
+#include <pthread.h>
+
+/*
+ * Initializes the property
+ */
+DirectResult
+fusion_property_init (FusionProperty *property, const FusionWorld *world)
+{
+ D_ASSERT( property != NULL );
+
+ direct_util_recursive_pthread_mutex_init (&property->single.lock);
+ pthread_cond_init (&property->single.cond, NULL);
+
+ property->single.state = FUSION_PROPERTY_AVAILABLE;
+
+ return DR_OK;
+}
+
+/*
+ * Lease the property causing others to wait before leasing or purchasing.
+ */
+DirectResult
+fusion_property_lease (FusionProperty *property)
+{
+ DirectResult ret = DR_OK;
+
+ D_ASSERT( property != NULL );
+
+ pthread_mutex_lock (&property->single.lock);
+
+ /* Wait as long as the property is leased by another party. */
+ while (property->single.state == FUSION_PROPERTY_LEASED)
+ pthread_cond_wait (&property->single.cond, &property->single.lock);
+
+ /* Fail if purchased by another party, otherwise succeed. */
+ if (property->single.state == FUSION_PROPERTY_PURCHASED)
+ ret = DR_BUSY;
+ else
+ property->single.state = FUSION_PROPERTY_LEASED;
+
+ pthread_mutex_unlock (&property->single.lock);
+
+ return ret;
+}
+
+/*
+ * Purchase the property disallowing others to lease or purchase it.
+ */
+DirectResult
+fusion_property_purchase (FusionProperty *property)
+{
+ DirectResult ret = DR_OK;
+
+ D_ASSERT( property != NULL );
+
+ pthread_mutex_lock (&property->single.lock);
+
+ /* Wait as long as the property is leased by another party. */
+ while (property->single.state == FUSION_PROPERTY_LEASED)
+ pthread_cond_wait (&property->single.cond, &property->single.lock);
+
+ /* Fail if purchased by another party, otherwise succeed. */
+ if (property->single.state == FUSION_PROPERTY_PURCHASED)
+ ret = DR_BUSY;
+ else {
+ property->single.state = FUSION_PROPERTY_PURCHASED;
+
+ /* Wake up any other waiting party. */
+ pthread_cond_broadcast (&property->single.cond);
+ }
+
+ pthread_mutex_unlock (&property->single.lock);
+
+ return ret;
+}
+
+/*
+ * Cede the property allowing others to lease or purchase it.
+ */
+DirectResult
+fusion_property_cede (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ pthread_mutex_lock (&property->single.lock);
+
+ /* Simple error checking, maybe we should also check the owner. */
+ D_ASSERT( property->single.state != FUSION_PROPERTY_AVAILABLE );
+
+ /* Put back into 'available' state. */
+ property->single.state = FUSION_PROPERTY_AVAILABLE;
+
+ /* Wake up one waiting party if there are any. */
+ pthread_cond_signal (&property->single.cond);
+
+ pthread_mutex_unlock (&property->single.lock);
+
+ return DR_OK;
+}
+
+/*
+ * Does nothing to avoid killing ourself.
+ */
+DirectResult
+fusion_property_holdup (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ return DR_OK;
+}
+
+/*
+ * Destroys the property
+ */
+DirectResult
+fusion_property_destroy (FusionProperty *property)
+{
+ D_ASSERT( property != NULL );
+
+ pthread_cond_destroy (&property->single.cond);
+ pthread_mutex_destroy (&property->single.lock);
+
+ return DR_OK;
+}
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/property.h b/Source/DirectFB/lib/fusion/property.h
new file mode 100755
index 0000000..74e3d1f
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/property.h
@@ -0,0 +1,114 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__PROPERTY_H__
+#define __FUSION__PROPERTY_H__
+
+#include <pthread.h>
+
+#include <fusion/types.h>
+
+typedef enum {
+ FUSION_PROPERTY_AVAILABLE,
+ FUSION_PROPERTY_LEASED,
+ FUSION_PROPERTY_PURCHASED
+} FusionPropertyState;
+
+
+typedef union {
+ /* multi app */
+ struct {
+ int id;
+ const FusionWorldShared *shared;
+ /* builtin impl */
+ struct {
+ FusionPropertyState state;
+ pid_t owner;
+ bool requested;
+ bool destroyed;
+ } builtin;
+ } multi;
+
+ /* single app */
+ struct {
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ FusionPropertyState state;
+ } single;
+} FusionProperty;
+
+/*
+ * Initializes the property
+ */
+DirectResult fusion_property_init (FusionProperty *property,
+ const FusionWorld *world);
+
+/*
+ * Lease the property causing others to wait before leasing or purchasing.
+ *
+ * Waits as long as property is leased by another party.
+ * Returns DR_BUSY if property is/gets purchased by another party.
+ *
+ * Succeeds if property is available,
+ * puts the property into 'leased' state.
+ */
+DirectResult fusion_property_lease (FusionProperty *property);
+
+/*
+ * Purchase the property disallowing others to lease or purchase it.
+ *
+ * Waits as long as property is leased by another party.
+ * Returns DR_BUSY if property is/gets purchased by another party.
+ *
+ * Succeeds if property is available,
+ * puts the property into 'purchased' state and wakes up any waiting party.
+ */
+DirectResult fusion_property_purchase (FusionProperty *property);
+
+/*
+ * Cede the property allowing others to lease or purchase it.
+ *
+ * Puts the property into 'available' state and wakes up one waiting party.
+ */
+DirectResult fusion_property_cede (FusionProperty *property);
+
+/*
+ * Kills the owner of the property.
+ *
+ * Tries to make a purchased property available again by killing
+ * the process that purchased it.
+ */
+DirectResult fusion_property_holdup (FusionProperty *property);
+
+/*
+ * Destroys the property
+ */
+DirectResult fusion_property_destroy (FusionProperty *property);
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/protocol.h b/Source/DirectFB/lib/fusion/protocol.h
new file mode 100755
index 0000000..8670b1d
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/protocol.h
@@ -0,0 +1,119 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION_PROTOCOL_H__
+#define __FUSION_PROTOCOL_H__
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <direct/types.h>
+
+
+typedef enum {
+ FMT_SEND,
+ FMT_ENTER,
+ FMT_LEAVE,
+ FMT_CALL,
+ FMT_CALLRET,
+ FMT_REACTOR
+} FusionMessageType;
+
+/*
+ * Enter world (slave).
+ */
+typedef struct {
+ FusionMessageType type;
+
+ FusionID fusion_id;
+} FusionEnter;
+
+/*
+ * Leave the world (slave).
+ */
+typedef struct {
+ FusionMessageType type;
+
+ FusionID fusion_id;
+} FusionLeave;
+
+/*
+ * Execute a call.
+ */
+typedef struct {
+ FusionMessageType type;
+
+ unsigned int serial;
+
+ FusionID caller;
+ int call_id;
+ int call_arg;
+ void *call_ptr;
+
+ void *handler;
+ void *ctx;
+
+ FusionCallExecFlags flags;
+} FusionCallMessage, FusionCallExecute;
+
+/*
+ * Send call return.
+ */
+typedef struct {
+ FusionMessageType type;
+
+ int val;
+} FusionCallReturn;
+
+/*
+ * Send reactor message.
+ */
+typedef struct {
+ FusionMessageType type;
+
+ int id;
+ int channel;
+
+ FusionRef *ref;
+} FusionReactorMessage;
+
+
+typedef union {
+ FusionMessageType type;
+
+ FusionEnter enter;
+ FusionLeave leave;
+ FusionCallMessage call;
+ FusionCallReturn callret;
+ FusionReactorMessage reactor;
+} FusionMessage;
+
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/reactor.c b/Source/DirectFB/lib/fusion/reactor.c
new file mode 100755
index 0000000..7e1feae
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/reactor.c
@@ -0,0 +1,1868 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+
+#include <sys/param.h>
+
+#include <pthread.h>
+
+#include <fusion/build.h>
+
+#include <direct/debug.h>
+#include <direct/list.h>
+#include <direct/mem.h>
+#include <direct/messages.h>
+#include <direct/thread.h>
+#include <direct/trace.h>
+#include <direct/util.h>
+
+#include <fusion/types.h>
+#include <fusion/lock.h>
+#include <fusion/shmalloc.h>
+#include <fusion/reactor.h>
+
+#include "fusion_internal.h"
+
+
+#if FUSION_BUILD_MULTI
+
+D_DEBUG_DOMAIN( Fusion_Reactor, "Fusion/Reactor", "Fusion's Reactor" );
+
+struct __Fusion_FusionReactor {
+ int magic;
+
+ int id; /* reactor id */
+ int msg_size; /* size of each message */
+ bool direct;
+ bool destroyed;
+
+ DirectLink *globals;
+ FusionSkirmish *globals_lock;
+
+ FusionWorldShared *shared;
+
+#if !FUSION_BUILD_KERNEL
+ DirectLink *listeners; /* list of attached listeners */
+ FusionSkirmish listeners_lock;
+
+ FusionCall *call;
+#endif
+};
+
+typedef struct {
+ DirectLink link;
+
+ int magic;
+
+ pthread_rwlock_t lock;
+
+ int reactor_id;
+ FusionReactor *reactor;
+
+ DirectLink *links; /* reactor listeners attached to node */
+} ReactorNode;
+
+typedef struct {
+ DirectLink link;
+
+ int magic;
+
+ Reaction *reaction;
+ int channel;
+} NodeLink;
+
+/**************************************************************************************************/
+
+static ReactorNode *lock_node ( int reactor_id,
+ bool add_it,
+ bool wlock,
+ FusionReactor *reactor, /* one of reactor and world must not be NULL */
+ FusionWorld *world );
+
+static void unlock_node ( ReactorNode *node );
+
+static void process_globals( FusionReactor *reactor,
+ const void *msg_data,
+ const ReactionFunc *globals );
+
+/**************************************************************************************************/
+
+#if FUSION_BUILD_KERNEL
+
+FusionReactor *
+fusion_reactor_new( int msg_size,
+ const char *name,
+ const FusionWorld *world )
+{
+ FusionEntryInfo info;
+ FusionReactor *reactor;
+ FusionWorldShared *shared;
+
+// D_ASSERT( msg_size > 0 );
+ D_ASSERT( name != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ D_DEBUG_AT( Fusion_Reactor, "fusion_reactor_new( '%s', size %d )\n", name ? : "", msg_size );
+
+ /* allocate shared reactor data */
+ reactor = SHCALLOC( shared->main_pool, 1, sizeof (FusionReactor) );
+ if (!reactor) {
+ D_OOSHM();
+ return NULL;
+ }
+
+ /* create a new reactor */
+ while (ioctl( world->fusion_fd, FUSION_REACTOR_NEW, &reactor->id )) {
+ if (errno == EINTR)
+ continue;
+
+ D_PERROR( "FUSION_REACTOR_NEW" );
+ SHFREE( shared->main_pool, reactor );
+ return NULL;
+ }
+
+ /* set the static message size, should we make dynamic? (TODO?) */
+ reactor->msg_size = msg_size;
+
+ /* Set default lock for global reactions. */
+ reactor->globals_lock = &shared->reactor_globals;
+
+ D_DEBUG_AT( Fusion_Reactor, " -> new reactor %p [%d] with lock %p [%d]\n",
+ reactor, reactor->id, reactor->globals_lock, reactor->globals_lock->multi.id );
+
+ reactor->shared = shared;
+ reactor->direct = true;
+
+ D_MAGIC_SET( reactor, FusionReactor );
+
+
+ info.type = FT_REACTOR;
+ info.id = reactor->id;
+
+ direct_snputs( info.name, name, sizeof(info.name) );
+
+ ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info );
+
+ return reactor;
+}
+
+DirectResult
+fusion_reactor_destroy( FusionReactor *reactor )
+{
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ shared = reactor->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ D_DEBUG_AT( Fusion_Reactor, "fusion_reactor_destroy( %p [%d] )\n", reactor, reactor->id );
+
+ D_ASSUME( !reactor->destroyed );
+
+ if (reactor->destroyed)
+ return DR_DESTROYED;
+
+ while (ioctl( _fusion_fd( shared ), FUSION_REACTOR_DESTROY, &reactor->id )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR( "Fusion/Reactor: invalid reactor\n" );
+ return DR_DESTROYED;
+ }
+
+ D_PERROR( "FUSION_REACTOR_DESTROY" );
+ return DR_FUSION;
+ }
+
+ reactor->destroyed = true;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_free( FusionReactor *reactor )
+{
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ shared = reactor->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ D_DEBUG_AT( Fusion_Reactor, "fusion_reactor_free( %p [%d] )\n", reactor, reactor->id );
+
+ D_MAGIC_CLEAR( reactor );
+
+// D_ASSUME( reactor->destroyed );
+
+ if (!reactor->destroyed)
+ while (ioctl( _fusion_fd( shared ), FUSION_REACTOR_DESTROY, &reactor->id ) && errno == EINTR);
+
+ /* free shared reactor data */
+ SHFREE( shared->main_pool, reactor );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_attach_channel( FusionReactor *reactor,
+ int channel,
+ ReactionFunc func,
+ void *ctx,
+ Reaction *reaction )
+{
+ ReactorNode *node;
+ NodeLink *link;
+ FusionReactorAttach attach;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+ D_ASSERT( func != NULL );
+ D_ASSERT( reaction != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_attach( %p [%d], func %p, ctx %p, reaction %p )\n",
+ reactor, reactor->id, func, ctx, reaction );
+
+ link = D_CALLOC( 1, sizeof(NodeLink) );
+ if (!link)
+ return D_OOM();
+
+ node = lock_node( reactor->id, true, true, reactor, NULL );
+ if (!node) {
+ D_FREE( link );
+ return DR_FUSION;
+ }
+
+ attach.reactor_id = reactor->id;
+ attach.channel = channel;
+
+ while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_ATTACH, &attach )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR( "Fusion/Reactor: invalid reactor\n" );
+ unlock_node( node );
+ D_FREE( link );
+ return DR_DESTROYED;
+ }
+
+ D_PERROR( "FUSION_REACTOR_ATTACH" );
+ unlock_node( node );
+ D_FREE( link );
+ return DR_FUSION;
+ }
+
+ /* fill out callback information */
+ reaction->func = func;
+ reaction->ctx = ctx;
+ reaction->node_link = link;
+
+ link->reaction = reaction;
+ link->channel = channel;
+
+ D_MAGIC_SET( link, NodeLink );
+
+ /* prepend the reaction to the local reaction list */
+ direct_list_prepend( &node->links, &link->link );
+
+ unlock_node( node );
+
+ return DR_OK;
+}
+
+static void
+remove_node_link( ReactorNode *node,
+ NodeLink *link )
+{
+ D_MAGIC_ASSERT( node, ReactorNode );
+ D_MAGIC_ASSERT( link, NodeLink );
+
+ D_ASSUME( link->reaction == NULL );
+
+ direct_list_remove( &node->links, &link->link );
+
+ D_MAGIC_CLEAR( link );
+
+ D_FREE( link );
+}
+
+DirectResult
+fusion_reactor_detach( FusionReactor *reactor,
+ Reaction *reaction )
+{
+ ReactorNode *node;
+ NodeLink *link;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+ D_ASSERT( reaction != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_detach( %p [%d], reaction %p ) <- func %p, ctx %p\n",
+ reactor, reactor->id, reaction, reaction->func, reaction->ctx );
+
+ node = lock_node( reactor->id, false, true, reactor, NULL );
+ if (!node) {
+ D_BUG( "node not found" );
+ return DR_BUG;
+ }
+
+ link = reaction->node_link;
+ D_ASSUME( link != NULL );
+
+ if (link) {
+ FusionReactorDetach detach;
+
+ D_ASSERT( link->reaction == reaction );
+
+ detach.reactor_id = reactor->id;
+ detach.channel = link->channel;
+
+ reaction->node_link = NULL;
+
+ link->reaction = NULL;
+
+ remove_node_link( node, link );
+
+ while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_DETACH, &detach )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR( "Fusion/Reactor: invalid reactor\n" );
+ unlock_node( node );
+ return DR_DESTROYED;
+ }
+
+ D_PERROR( "FUSION_REACTOR_DETACH" );
+ unlock_node( node );
+ return DR_FUSION;
+ }
+ }
+
+ unlock_node( node );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_dispatch_channel( FusionReactor *reactor,
+ int channel,
+ const void *msg_data,
+ int msg_size,
+ bool self,
+ const ReactionFunc *globals )
+{
+ FusionReactorDispatch dispatch;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ D_ASSERT( msg_data != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_dispatch( %p [%d], msg_data %p, self %s, globals %p)\n",
+ reactor, reactor->id, msg_data, self ? "true" : "false", globals );
+
+ /* Handle global reactions first. */
+ if (reactor->globals) {
+ if (globals)
+ process_globals( reactor, msg_data, globals );
+ else
+ D_ERROR( "Fusion/Reactor: global reactions exist but no "
+ "globals have been passed to dispatch()\n" );
+ }
+
+ /* Handle local reactions. */
+ if (self && reactor->direct) {
+ _fusion_reactor_process_message( _fusion_world(reactor->shared), reactor->id, channel, msg_data );
+ self = false;
+ }
+
+ /* Initialize dispatch data. */
+ dispatch.reactor_id = reactor->id;
+ dispatch.channel = channel;
+ dispatch.self = self;
+ dispatch.msg_size = msg_size;
+ dispatch.msg_data = msg_data;
+
+ /* Dispatch the message to handle foreign reactions. */
+ while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_DISPATCH, &dispatch )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR( "Fusion/Reactor: invalid reactor\n" );
+ return DR_DESTROYED;
+ }
+
+ D_PERROR( "FUSION_REACTOR_DISPATCH" );
+ return DR_FUSION;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_set_dispatch_callback( FusionReactor *reactor,
+ FusionCall *call,
+ void *call_ptr )
+{
+ FusionReactorSetCallback callback;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+ D_ASSERT( call != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_set_dispatch_callback( %p [%d], call %p [%d], ptr %p)\n",
+ reactor, reactor->id, call, call->call_id, call_ptr );
+
+ /* Fill callback info. */
+ callback.reactor_id = reactor->id;
+ callback.call_id = call->call_id;
+ callback.call_ptr = call_ptr;
+
+ /* Set the dispatch callback. */
+ while (ioctl( _fusion_fd( reactor->shared ), FUSION_REACTOR_SET_DISPATCH_CALLBACK, &callback )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR( "Fusion/Reactor: invalid reactor\n" );
+ return DR_DESTROYED;
+ }
+
+ D_PERROR( "FUSION_REACTOR_SET_DISPATCH_CALLBACK" );
+ return DR_FUSION;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_set_name( FusionReactor *reactor,
+ const char *name )
+{
+ FusionEntryInfo info;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+ D_ASSERT( name != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor, "%s( %p, '%s' )\n", __FUNCTION__, reactor, name );
+
+ /* Initialize reactor info. */
+ info.type = FT_REACTOR;
+ info.id = reactor->id;
+
+ /* Put reactor name into info. */
+ direct_snputs( info.name, name, sizeof(info.name) );
+
+ /* Set the reactor info. */
+ while (ioctl( _fusion_fd( reactor->shared ), FUSION_ENTRY_SET_INFO, &info )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR( "Fusion/Reactor: invalid reactor\n" );
+ return DR_IDNOTFOUND;
+ }
+
+ D_PERROR( "FUSION_ENTRY_SET_INFO( reactor 0x%08x, '%s' )\n", reactor->id, name );
+ return DR_FUSION;
+ }
+
+ return DR_OK;
+}
+
+void
+_fusion_reactor_process_message( FusionWorld *world,
+ int reactor_id,
+ int channel,
+ const void *msg_data )
+{
+ ReactorNode *node;
+ NodeLink *link;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_ASSERT( msg_data != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ " _fusion_reactor_process_message( [%d], msg_data %p )\n", reactor_id, msg_data );
+
+ /* Find the local counter part of the reactor. */
+ node = lock_node( reactor_id, false, false, NULL, world );
+ if (!node)
+ return;
+
+ D_DEBUG_AT( Fusion_Reactor, " -> node %p, reactor %p\n", node, node->reactor );
+
+ D_ASSUME( node->links != NULL );
+
+ if (!node->links) {
+ D_DEBUG_AT( Fusion_Reactor, " -> no local reactions!?!\n" );
+ unlock_node( node );
+ return;
+ }
+
+ direct_list_foreach (link, node->links) {
+ Reaction *reaction;
+
+ D_MAGIC_ASSERT( link, NodeLink );
+
+ if (link->channel != channel)
+ continue;
+
+ reaction = link->reaction;
+ if (!reaction)
+ continue;
+
+ if (reaction->func( msg_data, reaction->ctx ) == RS_REMOVE) {
+ FusionReactorDetach detach;
+
+ detach.reactor_id = reactor_id;
+ detach.channel = channel;
+
+ D_DEBUG_AT( Fusion_Reactor, " -> removing %p, func %p, ctx %p\n",
+ reaction, reaction->func, reaction->ctx );
+
+ link->reaction = NULL;
+
+ /* We can't remove the link as we only have read lock, to avoid dead locks. */
+
+ while (ioctl( world->fusion_fd, FUSION_REACTOR_DETACH, &detach )) {
+ switch (errno) {
+ case EINTR:
+ continue;
+
+ case EINVAL:
+ D_ERROR( "Fusion/Reactor: invalid reactor (DETACH)\n" );
+ break;
+
+ default:
+ D_PERROR( "FUSION_REACTOR_DETACH" );
+ break;
+ }
+
+ break;
+ }
+ }
+ }
+
+ unlock_node( node );
+}
+
+#else /* FUSION_BUILD_KERNEL */
+
+typedef struct {
+ DirectLink link;
+
+ unsigned int refs;
+
+ FusionID fusion_id;
+ int channel;
+} __Listener;
+
+
+FusionReactor *
+fusion_reactor_new( int msg_size,
+ const char *name,
+ const FusionWorld *world )
+{
+ FusionReactor *reactor;
+ FusionWorldShared *shared;
+
+ D_ASSERT( msg_size > 0 );
+ D_ASSERT( name != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ D_DEBUG_AT( Fusion_Reactor, "fusion_reactor_new( '%s', size %d )\n", name ? : "", msg_size );
+
+ /* allocate shared reactor data */
+ reactor = SHCALLOC( shared->main_pool, 1, sizeof (FusionReactor) );
+ if (!reactor) {
+ D_OOSHM();
+ return NULL;
+ }
+
+ /* Generate the reactor id */
+ reactor->id = ++shared->reactor_ids;
+
+ /* Set the static message size, should we make dynamic? (TODO?) */
+ reactor->msg_size = msg_size;
+
+ /* Set default lock for global reactions. */
+ reactor->globals_lock = &shared->reactor_globals;
+
+ fusion_skirmish_init( &reactor->listeners_lock, "Reactor Listeners", world );
+
+ D_DEBUG_AT( Fusion_Reactor, " -> new reactor %p [%d] with lock %p [%d]\n",
+ reactor, reactor->id, reactor->globals_lock, reactor->globals_lock->multi.id );
+
+ reactor->shared = shared;
+ reactor->direct = true;
+
+ D_MAGIC_SET( reactor, FusionReactor );
+
+ return reactor;
+}
+
+DirectResult
+fusion_reactor_destroy( FusionReactor *reactor )
+{
+ FusionWorldShared *shared;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ shared = reactor->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ D_DEBUG_AT( Fusion_Reactor, "fusion_reactor_destroy( %p [%d] )\n", reactor, reactor->id );
+
+ D_ASSUME( !reactor->destroyed );
+
+ if (reactor->destroyed)
+ return DR_DESTROYED;
+
+ fusion_skirmish_destroy( &reactor->listeners_lock );
+
+ reactor->destroyed = true;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_free( FusionReactor *reactor )
+{
+ FusionWorldShared *shared;
+ __Listener *listener, *temp;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ shared = reactor->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ D_DEBUG_AT( Fusion_Reactor, "fusion_reactor_free( %p [%d] )\n", reactor, reactor->id );
+
+ D_MAGIC_CLEAR( reactor );
+
+// D_ASSUME( reactor->destroyed );
+
+ direct_list_foreach_safe (listener, temp, reactor->listeners) {
+ direct_list_remove( &reactor->listeners, &listener->link );
+ SHFREE( shared->main_pool, listener );
+ }
+
+ /* free shared reactor data */
+ SHFREE( shared->main_pool, reactor );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_attach_channel( FusionReactor *reactor,
+ int channel,
+ ReactionFunc func,
+ void *ctx,
+ Reaction *reaction )
+{
+ FusionWorldShared *shared;
+ ReactorNode *node;
+ NodeLink *link;
+ FusionID fusion_id;
+ __Listener *listener;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+ D_ASSERT( func != NULL );
+ D_ASSERT( reaction != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_attach( %p [%d], func %p, ctx %p, reaction %p )\n",
+ reactor, reactor->id, func, ctx, reaction );
+
+ if (reactor->destroyed)
+ return DR_DESTROYED;
+
+ shared = reactor->shared;
+
+ link = D_CALLOC( 1, sizeof(NodeLink) );
+ if (!link)
+ return D_OOM();
+
+ node = lock_node( reactor->id, true, true, reactor, NULL );
+ if (!node) {
+ D_FREE( link );
+ return DR_FUSION;
+ }
+
+ fusion_id = _fusion_id( shared );
+
+ fusion_skirmish_prevail( &reactor->listeners_lock );
+
+ direct_list_foreach (listener, reactor->listeners) {
+ if (listener->fusion_id == fusion_id && listener->channel == channel) {
+ listener->refs++;
+ break;
+ }
+ }
+
+ if (!listener) {
+ listener = SHCALLOC( shared->main_pool, 1, sizeof(__Listener) );
+ if (!listener) {
+ D_OOSHM();
+ fusion_skirmish_dismiss( &reactor->listeners_lock );
+ unlock_node( node );
+ D_FREE( link );
+ return DR_NOSHAREDMEMORY;
+ }
+
+ listener->refs = 1;
+ listener->fusion_id = fusion_id;
+ listener->channel = channel;
+
+ direct_list_append( &reactor->listeners, &listener->link );
+ }
+
+ fusion_skirmish_dismiss( &reactor->listeners_lock );
+
+ /* fill out callback information */
+ reaction->func = func;
+ reaction->ctx = ctx;
+ reaction->node_link = link;
+
+ link->reaction = reaction;
+ link->channel = channel;
+
+ D_MAGIC_SET( link, NodeLink );
+
+ /* prepend the reaction to the local reaction list */
+ direct_list_prepend( &node->links, &link->link );
+
+ unlock_node( node );
+
+ return DR_OK;
+}
+
+static void
+remove_node_link( ReactorNode *node,
+ NodeLink *link )
+{
+ D_MAGIC_ASSERT( node, ReactorNode );
+ D_MAGIC_ASSERT( link, NodeLink );
+
+ D_ASSUME( link->reaction == NULL );
+
+ direct_list_remove( &node->links, &link->link );
+
+ D_MAGIC_CLEAR( link );
+
+ D_FREE( link );
+}
+
+DirectResult
+fusion_reactor_detach( FusionReactor *reactor,
+ Reaction *reaction )
+{
+ FusionWorldShared *shared;
+ ReactorNode *node;
+ NodeLink *link;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+ D_ASSERT( reaction != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_detach( %p [%d], reaction %p ) <- func %p, ctx %p\n",
+ reactor, reactor->id, reaction, reaction->func, reaction->ctx );
+
+ if (reactor->destroyed)
+ return DR_DESTROYED;
+
+ shared = reactor->shared;
+
+ node = lock_node( reactor->id, false, true, reactor, NULL );
+ if (!node) {
+ D_BUG( "node not found" );
+ return DR_BUG;
+ }
+
+ link = reaction->node_link;
+ D_ASSUME( link != NULL );
+
+ if (link) {
+ __Listener *listener;
+ FusionID fusion_id = _fusion_id( shared );
+
+ D_ASSERT( link->reaction == reaction );
+
+ reaction->node_link = NULL;
+
+ link->reaction = NULL;
+
+ remove_node_link( node, link );
+
+ fusion_skirmish_prevail( &reactor->listeners_lock );
+
+ direct_list_foreach (listener, reactor->listeners) {
+ if (listener->fusion_id == fusion_id && listener->channel == link->channel) {
+ if (--listener->refs == 0) {
+ direct_list_remove( &reactor->listeners, &listener->link );
+ SHFREE( shared->main_pool, listener );
+ }
+ break;
+ }
+ }
+
+ fusion_skirmish_dismiss( &reactor->listeners_lock );
+
+ if (!listener)
+ D_ERROR( "Fusion/Reactor: Couldn't detach listener!\n" );
+ }
+
+ unlock_node( node );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_dispatch_channel( FusionReactor *reactor,
+ int channel,
+ const void *msg_data,
+ int msg_size,
+ bool self,
+ const ReactionFunc *globals )
+{
+ FusionWorld *world;
+ __Listener *listener, *temp;
+ FusionRef *ref = NULL;
+ FusionReactorMessage *msg;
+ struct sockaddr_un addr;
+ int len;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ D_ASSERT( msg_data != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_dispatch( %p [%d], msg_data %p, self %s, globals %p)\n",
+ reactor, reactor->id, msg_data, self ? "true" : "false", globals );
+
+ if (reactor->destroyed)
+ return DR_DESTROYED;
+
+ if (msg_size > FUSION_MESSAGE_SIZE-sizeof(FusionReactorMessage)) {
+ D_ERROR( "Fusion/Reactor: Message too large (%d)!\n", msg_size );
+ return DR_UNSUPPORTED;
+ }
+
+ world = _fusion_world( reactor->shared );
+
+ if (reactor->call) {
+ ref = SHMALLOC( world->shared->main_pool, sizeof(FusionRef) );
+ if (!ref)
+ return D_OOSHM();
+
+ fusion_ref_init( ref, "Dispatch Ref", world );
+ fusion_ref_up( ref, true );
+ fusion_ref_watch( ref, reactor->call, 0 );
+ }
+
+ /* Handle global reactions first. */
+ if (reactor->globals) {
+ if (globals)
+ process_globals( reactor, msg_data, globals );
+ else
+ D_ERROR( "Fusion/Reactor: global reactions exist but no "
+ "globals have been passed to dispatch()\n" );
+ }
+
+ /* Handle local reactions. */
+ if (self && reactor->direct) {
+ _fusion_reactor_process_message( _fusion_world(reactor->shared), reactor->id, channel, msg_data );
+ self = false;
+ }
+
+ msg = alloca( sizeof(FusionReactorMessage) + msg_size );
+
+ msg->type = FMT_REACTOR;
+ msg->id = reactor->id;
+ msg->channel = channel;
+ msg->ref = ref;
+
+ memcpy( (void*)msg + sizeof(FusionReactorMessage), msg_data, msg_size );
+
+ addr.sun_family = AF_UNIX;
+ len = snprintf( addr.sun_path, sizeof(addr.sun_path),
+ "/tmp/.fusion-%d/", fusion_world_index( world ) );
+
+ fusion_skirmish_prevail( &reactor->listeners_lock );
+
+ direct_list_foreach_safe (listener, temp, reactor->listeners) {
+ if (listener->channel == channel) {
+ DirectResult ret;
+
+ if (!self && listener->fusion_id == world->fusion_id)
+ continue;
+
+ if (ref)
+ fusion_ref_up( ref, true );
+
+ snprintf( addr.sun_path+len, sizeof(addr.sun_path)-len, "%lx", listener->fusion_id );
+
+ D_DEBUG_AT( Fusion_Reactor, " -> sending to '%s'\n", addr.sun_path );
+
+ ret = _fusion_send_message( world->fusion_fd, msg, sizeof(FusionReactorMessage)+msg_size, &addr );
+ if (ret == DR_FUSION) {
+ D_DEBUG_AT( Fusion_Reactor, " -> removing dead listener %lu\n", listener->fusion_id );
+
+ if (ref)
+ fusion_ref_down( ref, true );
+
+ direct_list_remove( &reactor->listeners, &listener->link );
+
+ SHFREE( reactor->shared->main_pool, listener );
+ }
+ }
+ }
+
+ fusion_skirmish_dismiss( &reactor->listeners_lock );
+
+ if (ref) {
+ fusion_ref_down( ref, true );
+ if (fusion_ref_zero_trylock( ref ) == DR_OK) {
+ fusion_ref_destroy( ref );
+ SHFREE( world->shared->main_pool, ref );
+ }
+ }
+
+ D_DEBUG_AT( Fusion_Reactor, "fusion_reactor_dispatch( %p ) done.\n", reactor );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_set_dispatch_callback( FusionReactor *reactor,
+ FusionCall *call,
+ void *call_ptr )
+{
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+ D_ASSERT( call != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_set_dispatch_callback( %p [%d], call %p [%d], ptr %p)\n",
+ reactor, reactor->id, call, call->call_id, call_ptr );
+
+ if (reactor->destroyed)
+ return DR_DESTROYED;
+
+ if (call_ptr)
+ return DR_UNIMPLEMENTED;
+
+ reactor->call = call;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_set_name( FusionReactor *reactor,
+ const char *name )
+{
+ D_UNIMPLEMENTED();
+
+ return DR_UNIMPLEMENTED;
+}
+
+void
+_fusion_reactor_process_message( FusionWorld *world,
+ int reactor_id,
+ int channel,
+ const void *msg_data )
+{
+ ReactorNode *node;
+ NodeLink *link;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_ASSERT( msg_data != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ " _fusion_reactor_process_message( [%d], msg_data %p )\n", reactor_id, msg_data );
+
+ /* Find the local counter part of the reactor. */
+ node = lock_node( reactor_id, false, false, NULL, world );
+ if (!node)
+ return;
+
+ D_DEBUG_AT( Fusion_Reactor, " -> node %p, reactor %p\n", node, node->reactor );
+
+ D_ASSUME( node->links != NULL );
+
+ if (!node->links) {
+ D_DEBUG_AT( Fusion_Reactor, " -> no local reactions!?!\n" );
+ unlock_node( node );
+ return;
+ }
+
+ direct_list_foreach (link, node->links) {
+ Reaction *reaction;
+
+ D_MAGIC_ASSERT( link, NodeLink );
+
+ if (link->channel != channel)
+ continue;
+
+ reaction = link->reaction;
+ if (!reaction)
+ continue;
+
+ if (reaction->func( msg_data, reaction->ctx ) == RS_REMOVE) {
+ FusionReactor *reactor = node->reactor;
+ __Listener *listener;
+
+ D_DEBUG_AT( Fusion_Reactor, " -> removing %p, func %p, ctx %p\n",
+ reaction, reaction->func, reaction->ctx );
+
+ fusion_skirmish_prevail( &reactor->listeners_lock );
+
+ direct_list_foreach (listener, reactor->listeners) {
+ if (listener->fusion_id == world->fusion_id && listener->channel == channel) {
+ if (--listener->refs == 0) {
+ direct_list_remove( &reactor->listeners, &listener->link );
+ SHFREE( world->shared->main_pool, listener );
+ }
+ break;
+ }
+ }
+
+ fusion_skirmish_dismiss( &reactor->listeners_lock );
+ }
+ }
+
+ unlock_node( node );
+}
+
+#endif /* FUSION_BUILD_KERNEL */
+
+
+DirectResult
+fusion_reactor_set_lock( FusionReactor *reactor,
+ FusionSkirmish *lock )
+{
+ DirectResult ret;
+ FusionSkirmish *old;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ old = reactor->globals_lock;
+
+ D_ASSERT( lock != NULL );
+ D_ASSERT( old != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor, "fusion_reactor_set_lock( %p [%d], lock %p [%d] ) <- old %p [%d]\n",
+ reactor, reactor->id, lock, lock->multi.id, old, old->multi.id );
+
+ /*
+ * Acquire the old lock to make sure that changing the lock doesn't
+ * result in mismatching lock/unlock pairs in other functions.
+ */
+ ret = fusion_skirmish_prevail( old );
+ if (ret)
+ return ret;
+
+ D_ASSUME( reactor->globals_lock != lock );
+
+ /* Set the lock replacement. */
+ reactor->globals_lock = lock;
+
+ /* Release the old lock which is obsolete now. */
+ fusion_skirmish_dismiss( old );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_set_lock_only( FusionReactor *reactor,
+ FusionSkirmish *lock )
+{
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+ D_ASSERT( lock != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor, "fusion_reactor_set_lock_only( %p [%d], lock %p [%d] ) <- old %p [%d]\n",
+ reactor, reactor->id, lock, lock->multi.id, reactor->globals_lock, reactor->globals_lock->multi.id );
+
+ D_ASSUME( reactor->globals_lock != lock );
+
+ /* Set the lock replacement. */
+ reactor->globals_lock = lock;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_attach (FusionReactor *reactor,
+ ReactionFunc func,
+ void *ctx,
+ Reaction *reaction)
+{
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+ D_ASSERT( func != NULL );
+ D_ASSERT( reaction != NULL );
+
+ return fusion_reactor_attach_channel( reactor, 0, func, ctx, reaction );
+}
+
+DirectResult
+fusion_reactor_attach_global( FusionReactor *reactor,
+ int index,
+ void *ctx,
+ GlobalReaction *reaction )
+{
+ DirectResult ret;
+ FusionSkirmish *lock;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ D_ASSERT( index >= 0 );
+ D_ASSERT( reaction != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_attach_global( %p [%d], index %d, ctx %p, reaction %p )\n",
+ reactor, reactor->id, index, ctx, reaction );
+
+ /* Initialize reaction data. */
+ reaction->index = index;
+ reaction->ctx = ctx;
+ reaction->attached = true;
+
+ /* Remember for safety. */
+ lock = reactor->globals_lock;
+
+ D_ASSERT( lock != NULL );
+
+ /* Lock the list of global reactions. */
+ ret = fusion_skirmish_prevail( lock );
+ if (ret)
+ return ret;
+
+ /* FIXME: Might have changed while waiting for the lock. */
+ if (lock != reactor->globals_lock)
+ D_WARN( "using old lock once more" );
+
+ /* Prepend the reaction to the list. */
+ direct_list_prepend( &reactor->globals, &reaction->link );
+
+ /* Unlock the list of global reactions. */
+ fusion_skirmish_dismiss( lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_detach_global( FusionReactor *reactor,
+ GlobalReaction *reaction )
+{
+ DirectResult ret;
+ FusionSkirmish *lock;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ D_ASSERT( reaction != NULL );
+
+ D_DEBUG_AT( Fusion_Reactor,
+ "fusion_reactor_detach_global( %p [%d], reaction %p ) <- index %d, ctx %p\n",
+ reactor, reactor->id, reaction, reaction->index, reaction->ctx );
+
+ /* Remember for safety. */
+ lock = reactor->globals_lock;
+
+ D_ASSERT( lock != NULL );
+
+ /* Lock the list of global reactions. */
+ ret = fusion_skirmish_prevail( lock );
+ if (ret)
+ return ret;
+
+ /* FIXME: Might have changed while waiting for the lock. */
+ if (lock != reactor->globals_lock)
+ D_WARN( "using old lock once more" );
+
+ D_ASSUME( reaction->attached );
+
+ /* Check against multiple detach. */
+ if (reaction->attached) {
+ /* Mark as detached. */
+ reaction->attached = false;
+
+ /* Remove the reaction from the list. */
+ direct_list_remove( &reactor->globals, &reaction->link );
+ }
+
+ /* Unlock the list of global reactions. */
+ fusion_skirmish_dismiss( lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_dispatch( FusionReactor *reactor,
+ const void *msg_data,
+ bool self,
+ const ReactionFunc *globals )
+{
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ return fusion_reactor_dispatch_channel( reactor, 0, msg_data, reactor->msg_size, self, globals );
+}
+
+DirectResult
+fusion_reactor_sized_dispatch( FusionReactor *reactor,
+ const void *msg_data,
+ int msg_size,
+ bool self,
+ const ReactionFunc *globals )
+{
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ return fusion_reactor_dispatch_channel( reactor, 0, msg_data, msg_size, self, globals );
+}
+
+DirectResult
+fusion_reactor_direct( FusionReactor *reactor, bool direct )
+{
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ reactor->direct = direct;
+
+ return DR_OK;
+}
+
+
+void
+_fusion_reactor_free_all( FusionWorld *world )
+{
+ ReactorNode *node, *node_temp;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ D_DEBUG_AT( Fusion_Reactor, "_fusion_reactor_free_all() <- nodes %p\n", world->reactor_nodes );
+
+
+ pthread_mutex_lock( &world->reactor_nodes_lock );
+
+ direct_list_foreach_safe (node, node_temp, world->reactor_nodes) {
+ NodeLink *link, *link_temp;
+
+ D_MAGIC_ASSERT( node, ReactorNode );
+
+ pthread_rwlock_wrlock( &node->lock );
+
+ direct_list_foreach_safe (link, link_temp, node->links) {
+ D_MAGIC_ASSERT( link, NodeLink );
+
+ D_MAGIC_CLEAR( link );
+
+ D_FREE( link );
+ }
+
+ pthread_rwlock_unlock( &node->lock );
+ pthread_rwlock_destroy( &node->lock );
+
+ D_MAGIC_CLEAR( node );
+
+ D_FREE( node );
+ }
+
+ world->reactor_nodes = NULL;
+
+ pthread_mutex_unlock( &world->reactor_nodes_lock );
+}
+
+static void
+process_globals( FusionReactor *reactor,
+ const void *msg_data,
+ const ReactionFunc *globals )
+{
+ DirectLink *n;
+ GlobalReaction *global;
+ FusionSkirmish *lock;
+ int max_index = -1;
+
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ D_ASSERT( msg_data != NULL );
+ D_ASSERT( globals != NULL );
+
+/* D_DEBUG_AT( Fusion_Reactor, " process_globals( %p [%d], msg_data %p, globals %p )\n",
+ reactor, reactor->id, msg_data, globals );*/
+
+ /* Find maximum reaction index. */
+ while (globals[max_index+1])
+ max_index++;
+
+ if (max_index < 0)
+ return;
+
+ /* Remember for safety. */
+ lock = reactor->globals_lock;
+
+ D_ASSERT( lock != NULL );
+
+ /* Lock the list of global reactions. */
+ if (fusion_skirmish_prevail( lock ))
+ return;
+
+ /* FIXME: Might have changed while waiting for the lock. */
+ if (lock != reactor->globals_lock)
+ D_WARN( "using old lock once more" );
+
+ /* Loop through all global reactions. */
+ direct_list_foreach_safe (global, n, reactor->globals) {
+ int index = global->index;
+
+ /* Check if the index is valid. */
+ if (index < 0 || index > max_index) {
+ D_WARN( "index out of bounds (%d/%d)", global->index, max_index );
+ continue;
+ }
+
+ /* Call reaction and remove it if requested. */
+ if (globals[global->index]( msg_data, global->ctx ) == RS_REMOVE) {
+ /*D_DEBUG_AT( Fusion_Reactor, " -> removing %p, index %d, ctx %p\n",
+ global, global->index, global->ctx );*/
+
+ direct_list_remove( &reactor->globals, &global->link );
+ }
+ }
+
+ /* Unlock the list of global reactions. */
+ fusion_skirmish_dismiss( lock );
+}
+
+
+
+/*****************************
+ * File internal functions *
+ *****************************/
+
+static ReactorNode *
+lock_node( int reactor_id, bool add_it, bool wlock, FusionReactor *reactor, FusionWorld *world )
+{
+ DirectLink *n;
+ ReactorNode *node;
+ FusionWorldShared *shared;
+
+ D_DEBUG_AT( Fusion_Reactor, " lock_node( [%d], add %s, reactor %p )\n",
+ reactor_id, add_it ? "true" : "false", reactor );
+
+ D_ASSERT( reactor != NULL || (!add_it && world != NULL) );
+
+ if (reactor) {
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ shared = reactor->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+
+ world = _fusion_world( shared );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ }
+ else {
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shared = world->shared;
+
+ D_MAGIC_ASSERT( shared, FusionWorldShared );
+ }
+
+
+ pthread_mutex_lock( &world->reactor_nodes_lock );
+
+ direct_list_foreach_safe (node, n, world->reactor_nodes) {
+ D_MAGIC_ASSERT( node, ReactorNode );
+
+ if (node->reactor_id == reactor_id) {
+ if (wlock) {
+ DirectLink *n;
+ NodeLink *link;
+
+ pthread_rwlock_wrlock( &node->lock );
+
+ /* FIXME: don't cleanup asynchronously */
+ direct_list_foreach_safe (link, n, node->links) {
+ D_MAGIC_ASSERT( link, NodeLink );
+
+ if (!link->reaction) {
+ D_DEBUG_AT( Fusion_Reactor, " -> cleaning up %p\n", link );
+
+ remove_node_link( node, link );
+ }
+ else
+ D_ASSERT( link->reaction->node_link == link );
+ }
+ }
+ else
+ pthread_rwlock_rdlock( &node->lock );
+
+ /* FIXME: Don't cleanup asynchronously. */
+ if (!node->links && !add_it) {
+// D_DEBUG_AT( Fusion_Reactor, " -> cleaning up mine %p\n", node );
+
+ direct_list_remove( &world->reactor_nodes, &node->link );
+
+ pthread_rwlock_unlock( &node->lock );
+ pthread_rwlock_destroy( &node->lock );
+
+ D_MAGIC_CLEAR( node );
+
+ D_FREE( node );
+
+ node = NULL;
+ }
+ else {
+/* D_DEBUG_AT( Fusion_Reactor, " -> found %p (%d reactions)\n",
+ node, direct_list_count_elements_EXPENSIVE( node->reactions ) );*/
+
+ D_ASSERT( node->reactor == reactor || reactor == NULL );
+
+ direct_list_move_to_front( &world->reactor_nodes, &node->link );
+ }
+
+ pthread_mutex_unlock( &world->reactor_nodes_lock );
+
+ return node;
+ }
+
+ /* FIXME: Don't cleanup asynchronously. */
+ if (!pthread_rwlock_trywrlock( &node->lock )) {
+ if (!node->links) {
+// D_DEBUG_AT( Fusion_Reactor, " -> cleaning up other %p\n", node );
+
+ direct_list_remove( &world->reactor_nodes, &node->link );
+
+ pthread_rwlock_unlock( &node->lock );
+ pthread_rwlock_destroy( &node->lock );
+
+ D_MAGIC_CLEAR( node );
+
+ D_FREE( node );
+ }
+ else {
+ /*D_DEBUG_AT( Fusion_Reactor, " -> keeping other %p (%d reactions)\n",
+ node, direct_list_count_elements_EXPENSIVE( node->reactions ) );*/
+
+ pthread_rwlock_unlock( &node->lock );
+ }
+ }
+ }
+
+// D_DEBUG_AT( Fusion_Reactor, " -> not found%s adding\n", add_it ? ", but" : " and not" );
+
+ if (add_it) {
+ D_MAGIC_ASSERT( reactor, FusionReactor );
+
+ node = D_CALLOC( 1, sizeof(ReactorNode) );
+ if (!node) {
+ D_OOM();
+ return NULL;
+ }
+
+ //direct_util_recursive_pthread_mutex_init( &node->lock );
+ pthread_rwlock_init( &node->lock, NULL );
+
+
+ if (wlock)
+ pthread_rwlock_wrlock( &node->lock );
+ else
+ pthread_rwlock_rdlock( &node->lock );
+
+ node->reactor_id = reactor_id;
+ node->reactor = reactor;
+
+ D_MAGIC_SET( node, ReactorNode );
+
+ direct_list_prepend( &world->reactor_nodes, &node->link );
+
+ pthread_mutex_unlock( &world->reactor_nodes_lock );
+
+ return node;
+ }
+
+ pthread_mutex_unlock( &world->reactor_nodes_lock );
+
+ return NULL;
+}
+
+static void
+unlock_node( ReactorNode *node )
+{
+ D_ASSERT( node != NULL );
+
+// D_MAGIC_ASSERT( node->reactor, FusionReactor );
+
+/* D_DEBUG_AT( Fusion_Reactor, " unlock_node( %p, reactor %p [%d] )\n",
+ node, node->reactor, node->reactor->id );*/
+
+ pthread_rwlock_unlock( &node->lock );
+}
+
+#else /* FUSION_BUILD_MULTI */
+
+/***************************
+ * Internal declarations *
+ ***************************/
+
+/*
+ *
+ */
+struct __Fusion_FusionReactor {
+ DirectLink *reactions; /* reactor listeners attached to node */
+ pthread_mutex_t reactions_lock;
+
+ DirectLink *globals; /* global reactions attached to node */
+ pthread_mutex_t globals_lock;
+
+ bool destroyed;
+};
+
+static void
+process_globals( FusionReactor *reactor,
+ const void *msg_data,
+ const ReactionFunc *globals );
+
+/****************
+ * Public API *
+ ****************/
+
+FusionReactor *
+fusion_reactor_new( int msg_size,
+ const char *name,
+ const FusionWorld *world )
+{
+ FusionReactor *reactor;
+
+ D_ASSERT( msg_size > 0 );
+
+ reactor = D_CALLOC( 1, sizeof(FusionReactor) );
+ if (!reactor)
+ return NULL;
+
+ direct_util_recursive_pthread_mutex_init( &reactor->reactions_lock );
+ direct_util_recursive_pthread_mutex_init( &reactor->globals_lock );
+
+ return reactor;
+}
+
+DirectResult
+fusion_reactor_set_lock( FusionReactor *reactor,
+ FusionSkirmish *lock )
+{
+ D_ASSERT( reactor != NULL );
+ D_ASSERT( lock != NULL );
+
+// D_UNIMPLEMENTED();
+
+ return DR_UNIMPLEMENTED;
+}
+
+DirectResult
+fusion_reactor_set_lock_only( FusionReactor *reactor,
+ FusionSkirmish *lock )
+{
+ D_ASSERT( reactor != NULL );
+ D_ASSERT( lock != NULL );
+
+ return DR_UNIMPLEMENTED;
+}
+
+DirectResult
+fusion_reactor_attach (FusionReactor *reactor,
+ ReactionFunc func,
+ void *ctx,
+ Reaction *reaction)
+{
+ D_ASSERT( reactor != NULL );
+ D_ASSERT( func != NULL );
+ D_ASSERT( reaction != NULL );
+
+ reaction->func = func;
+ reaction->ctx = ctx;
+
+ pthread_mutex_lock( &reactor->reactions_lock );
+
+ direct_list_prepend( &reactor->reactions, &reaction->link );
+
+ pthread_mutex_unlock( &reactor->reactions_lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_detach (FusionReactor *reactor,
+ Reaction *reaction)
+{
+ D_ASSERT( reactor != NULL );
+ D_ASSERT( reaction != NULL );
+
+ pthread_mutex_lock( &reactor->reactions_lock );
+
+ direct_list_remove( &reactor->reactions, &reaction->link );
+
+ pthread_mutex_unlock( &reactor->reactions_lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_attach_global (FusionReactor *reactor,
+ int index,
+ void *ctx,
+ GlobalReaction *reaction)
+{
+ D_ASSERT( reactor != NULL );
+ D_ASSERT( index >= 0 );
+ D_ASSERT( reaction != NULL );
+
+ reaction->index = index;
+ reaction->ctx = ctx;
+
+ pthread_mutex_lock( &reactor->globals_lock );
+
+ direct_list_prepend( &reactor->globals, &reaction->link );
+
+ pthread_mutex_unlock( &reactor->globals_lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_detach_global (FusionReactor *reactor,
+ GlobalReaction *reaction)
+{
+ D_ASSERT( reactor != NULL );
+ D_ASSERT( reaction != NULL );
+
+ pthread_mutex_lock( &reactor->globals_lock );
+
+ direct_list_remove( &reactor->globals, &reaction->link );
+
+ pthread_mutex_unlock( &reactor->globals_lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_attach_channel( FusionReactor *reactor,
+ int channel,
+ ReactionFunc func,
+ void *ctx,
+ Reaction *reaction )
+{
+ D_UNIMPLEMENTED();
+
+ return DR_UNIMPLEMENTED;
+}
+
+DirectResult
+fusion_reactor_dispatch_channel( FusionReactor *reactor,
+ int channel,
+ const void *msg_data,
+ int msg_size,
+ bool self,
+ const ReactionFunc *globals )
+{
+ D_UNIMPLEMENTED();
+
+ return DR_UNIMPLEMENTED;
+}
+
+DirectResult
+fusion_reactor_set_dispatch_callback( FusionReactor *reactor,
+ FusionCall *call,
+ void *call_ptr )
+{
+ D_UNIMPLEMENTED();
+
+ return DR_UNIMPLEMENTED;
+}
+
+DirectResult
+fusion_reactor_set_name( FusionReactor *reactor,
+ const char *name )
+{
+ D_UNIMPLEMENTED();
+
+ return DR_UNIMPLEMENTED;
+}
+
+DirectResult
+fusion_reactor_dispatch (FusionReactor *reactor,
+ const void *msg_data,
+ bool self,
+ const ReactionFunc *globals)
+{
+ DirectLink *l;
+
+ D_ASSERT( reactor != NULL );
+ D_ASSERT( msg_data != NULL );
+
+ if (reactor->globals) {
+ if (globals)
+ process_globals( reactor, msg_data, globals );
+ else
+ D_ERROR( "Fusion/Reactor: global reactions exist but no "
+ "globals have been passed to dispatch()\n" );
+ }
+
+ if (!self)
+ return DR_OK;
+
+ pthread_mutex_lock( &reactor->reactions_lock );
+
+ l = reactor->reactions;
+ while (l) {
+ DirectLink *next = l->next;
+ Reaction *reaction = (Reaction*) l;
+
+ switch (reaction->func( msg_data, reaction->ctx )) {
+ case RS_REMOVE:
+ direct_list_remove( &reactor->reactions, l );
+ break;
+
+ case RS_DROP:
+ pthread_mutex_unlock( &reactor->reactions_lock );
+ return DR_OK;
+
+ default:
+ break;
+ }
+
+ l = next;
+ }
+
+ pthread_mutex_unlock( &reactor->reactions_lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_direct( FusionReactor *reactor, bool direct )
+{
+ D_ASSERT( reactor != NULL );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_destroy (FusionReactor *reactor)
+{
+ D_ASSERT( reactor != NULL );
+
+ D_ASSUME( !reactor->destroyed );
+
+ reactor->destroyed = true;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_reactor_free (FusionReactor *reactor)
+{
+ D_ASSERT( reactor != NULL );
+
+// D_ASSUME( reactor->destroyed );
+
+ reactor->reactions = NULL;
+
+ pthread_mutex_destroy( &reactor->reactions_lock );
+
+ D_FREE( reactor );
+
+ return DR_OK;
+}
+
+/******************************************************************************/
+
+static void
+process_globals( FusionReactor *reactor,
+ const void *msg_data,
+ const ReactionFunc *globals )
+{
+ DirectLink *n;
+ GlobalReaction *global;
+ int max_index = -1;
+
+ D_ASSERT( reactor != NULL );
+ D_ASSERT( msg_data != NULL );
+ D_ASSERT( globals != NULL );
+
+ while (globals[max_index+1])
+ max_index++;
+
+ if (max_index < 0)
+ return;
+
+ pthread_mutex_lock( &reactor->globals_lock );
+
+ direct_list_foreach_safe (global, n, reactor->globals) {
+ if (global->index < 0 || global->index > max_index) {
+ D_WARN( "global reaction index out of bounds (%d/%d)", global->index, max_index );
+ }
+ else {
+ if (globals[ global->index ]( msg_data, global->ctx ) == RS_REMOVE)
+ direct_list_remove( &reactor->globals, &global->link );
+ }
+ }
+
+ pthread_mutex_unlock( &reactor->globals_lock );
+}
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/reactor.h b/Source/DirectFB/lib/fusion/reactor.h
new file mode 100755
index 0000000..3466c5a
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/reactor.h
@@ -0,0 +1,197 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__REACTOR_H__
+#define __FUSION__REACTOR_H__
+
+#include <direct/list.h>
+
+#include <fusion/types.h>
+#include <fusion/call.h>
+#include <fusion/lock.h>
+
+typedef enum {
+ RS_OK,
+ RS_REMOVE,
+ RS_DROP
+} ReactionResult;
+
+typedef ReactionResult (*ReactionFunc)( const void *msg_data,
+ void *ctx );
+
+typedef struct {
+ DirectLink link;
+ ReactionFunc func;
+ void *ctx;
+ void *node_link;
+} Reaction;
+
+typedef struct {
+ DirectLink link;
+ int index;
+ void *ctx;
+ bool attached;
+} GlobalReaction;
+
+
+/*
+ * Create a new reactor configured for the specified message data size.
+ */
+FusionReactor *fusion_reactor_new ( int msg_size,
+ const char *name,
+ const FusionWorld *world );
+
+/*
+ * Destroy the reactor.
+ */
+DirectResult fusion_reactor_destroy ( FusionReactor *reactor );
+
+/*
+ * Free the reactor.
+ */
+DirectResult fusion_reactor_free ( FusionReactor *reactor );
+
+
+/*
+ * Makes the reactor use the specified lock for managing global reactions.
+ *
+ * After creating the reactor a global default lock is set which is created
+ * by Fusion once during initialization.
+ *
+ * To avoid dead locks caused by alternating lock orders of the global reaction
+ * lock and another lock, the default lock is replaced by the other lock.
+ */
+DirectResult fusion_reactor_set_lock ( FusionReactor *reactor,
+ FusionSkirmish *skirmish );
+
+DirectResult fusion_reactor_set_lock_only( FusionReactor *reactor,
+ FusionSkirmish *lock );
+
+/*
+ * Attach a local reaction to the reactor (channel 0).
+ */
+DirectResult fusion_reactor_attach ( FusionReactor *reactor,
+ ReactionFunc func,
+ void *ctx,
+ Reaction *reaction );
+
+/*
+ * Attach a local reaction to a specific reactor channel (0-1023).
+ */
+DirectResult fusion_reactor_attach_channel( FusionReactor *reactor,
+ int channel,
+ ReactionFunc func,
+ void *ctx,
+ Reaction *reaction );
+
+/*
+ * Detach an attached local reaction from the reactor.
+ */
+DirectResult fusion_reactor_detach ( FusionReactor *reactor,
+ Reaction *reaction );
+
+
+/*
+ * Attach a global reaction to the reactor.
+ *
+ * It's always called directly, no matter which Fusionee calls fusion_reactor_dispatch().
+ * Any data referenced by the reaction function has to be in shared memory, unless it uses a
+ * mechanism to lookup a local counter part or representative, based on shared information.
+ *
+ * A global reaction is not defined directly as a function pointer, because that's always a
+ * local address. Instead, it's specified by an index into a built in function table that
+ * must be passed to fusion_reactor_dispatch() each time it is called.
+ */
+DirectResult fusion_reactor_attach_global( FusionReactor *reactor,
+ int index,
+ void *ctx,
+ GlobalReaction *reaction );
+
+/*
+ * Detach an attached global reaction from the reactor.
+ */
+DirectResult fusion_reactor_detach_global( FusionReactor *reactor,
+ GlobalReaction *reaction );
+
+/*
+ * Dispatch a message to any attached reaction (channel 0).
+ *
+ * Setting 'self' to false excludes the caller's local reactions.
+ */
+DirectResult fusion_reactor_dispatch ( FusionReactor *reactor,
+ const void *msg_data,
+ bool self,
+ const ReactionFunc *globals );
+
+/*
+ * Dispatch a message to any attached reaction with a given size. Instead of
+ * using the size defined by the reactor, the caller can specify the size of
+ * the data.
+ *
+ * Setting 'self' to false excludes the caller's local reactions.
+ */
+DirectResult fusion_reactor_sized_dispatch( FusionReactor *reactor,
+ const void *msg_data,
+ int msg_size,
+ bool self,
+ const ReactionFunc *globals );
+
+/*
+ * Dispatch a message via a specific channel (0-1023).
+ *
+ * Setting 'self' to false excludes the caller's local reactions.
+ */
+DirectResult fusion_reactor_dispatch_channel( FusionReactor *reactor,
+ int channel,
+ const void *msg_data,
+ int msg_size,
+ bool self,
+ const ReactionFunc *globals );
+
+
+/*
+ * Have the call executed when a dispatched message has been processed by all recipients.
+ */
+DirectResult fusion_reactor_set_dispatch_callback( FusionReactor *reactor,
+ FusionCall *call,
+ void *call_ptr );
+
+/*
+ * Change the name of the reactor (debug).
+ */
+DirectResult fusion_reactor_set_name ( FusionReactor *reactor,
+ const char *name );
+
+/*
+ * Specify whether local message handlers (reactions) should be called directly.
+ */
+DirectResult fusion_reactor_direct ( FusionReactor *reactor,
+ bool direct );
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/ref.c b/Source/DirectFB/lib/fusion/ref.c
new file mode 100755
index 0000000..6c278e6
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/ref.c
@@ -0,0 +1,849 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#include <fusion/build.h>
+
+#include <direct/debug.h>
+#include <direct/messages.h>
+#include <direct/util.h>
+
+#include <fusion/types.h>
+#include <fusion/ref.h>
+
+#include "fusion_internal.h"
+
+#include <signal.h>
+
+
+#if FUSION_BUILD_MULTI
+
+D_DEBUG_DOMAIN( Fusion_Ref, "Fusion/Ref", "Fusion's Reference Counter" );
+
+
+#if FUSION_BUILD_KERNEL
+
+DirectResult
+fusion_ref_init (FusionRef *ref,
+ const char *name,
+ const FusionWorld *world)
+{
+ FusionEntryInfo info;
+
+ D_ASSERT( ref != NULL );
+ D_ASSERT( name != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ D_DEBUG_AT( Fusion_Ref, "fusion_ref_init( %p, '%s' )\n", ref, name ? : "" );
+
+ while (ioctl( world->fusion_fd, FUSION_REF_NEW, &ref->multi.id )) {
+ if (errno == EINTR)
+ continue;
+
+ D_PERROR( "FUSION_REF_NEW" );
+ return DR_FUSION;
+ }
+
+ D_DEBUG_AT( Fusion_Ref, " -> new ref %p [%d]\n", ref, ref->multi.id );
+
+ info.type = FT_REF;
+ info.id = ref->multi.id;
+
+ direct_snputs( info.name, name, sizeof(info.name) );
+
+ ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info );
+
+ /* Keep back pointer to shared world data. */
+ ref->multi.shared = world->shared;
+ ref->multi.creator = fusion_id( world );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_set_name (FusionRef *ref,
+ const char *name)
+{
+ FusionEntryInfo info;
+
+ D_ASSERT( ref != NULL );
+ D_ASSERT( name != NULL );
+
+ info.type = FT_REF;
+ info.id = ref->multi.id;
+
+ direct_snputs( info.name, name, sizeof(info.name) );
+
+ while (ioctl (_fusion_fd( ref->multi.shared ), FUSION_ENTRY_SET_INFO, &info)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EAGAIN:
+ return DR_LOCKED;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_ENTRY_SET_NAME");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_up (FusionRef *ref, bool global)
+{
+ D_ASSERT( ref != NULL );
+
+ while (ioctl (_fusion_fd( ref->multi.shared ), global ?
+ FUSION_REF_UP_GLOBAL : FUSION_REF_UP, &ref->multi.id))
+ {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EAGAIN:
+ return DR_LOCKED;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ if (global)
+ D_PERROR ("FUSION_REF_UP_GLOBAL");
+ else
+ D_PERROR ("FUSION_REF_UP");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_down (FusionRef *ref, bool global)
+{
+ D_ASSERT( ref != NULL );
+
+ while (ioctl (_fusion_fd( ref->multi.shared ), global ?
+ FUSION_REF_DOWN_GLOBAL : FUSION_REF_DOWN, &ref->multi.id))
+ {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ if (global)
+ D_PERROR ("FUSION_REF_DOWN_GLOBAL");
+ else
+ D_PERROR ("FUSION_REF_DOWN");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_stat (FusionRef *ref, int *refs)
+{
+ int val;
+
+ D_ASSERT( ref != NULL );
+ D_ASSERT( refs != NULL );
+
+ while ((val = ioctl (_fusion_fd( ref->multi.shared ), FUSION_REF_STAT, &ref->multi.id)) < 0) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_REF_STAT");
+
+ return DR_FAILURE;
+ }
+
+ *refs = val;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_zero_lock (FusionRef *ref)
+{
+ D_ASSERT( ref != NULL );
+
+ while (ioctl (_fusion_fd( ref->multi.shared ), FUSION_REF_ZERO_LOCK, &ref->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_REF_ZERO_LOCK");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_zero_trylock (FusionRef *ref)
+{
+ D_ASSERT( ref != NULL );
+
+ while (ioctl (_fusion_fd( ref->multi.shared ), FUSION_REF_ZERO_TRYLOCK, &ref->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case ETOOMANYREFS:
+ return DR_BUSY;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_REF_ZERO_TRYLOCK");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_unlock (FusionRef *ref)
+{
+ D_ASSERT( ref != NULL );
+
+ while (ioctl (_fusion_fd( ref->multi.shared ), FUSION_REF_UNLOCK, &ref->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_REF_UNLOCK");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_watch (FusionRef *ref, FusionCall *call, int call_arg)
+{
+ FusionRefWatch watch;
+
+ D_ASSERT( ref != NULL );
+ D_ASSERT( call != NULL );
+
+ watch.id = ref->multi.id;
+ watch.call_id = call->call_id;
+ watch.call_arg = call_arg;
+
+ while (ioctl (_fusion_fd( ref->multi.shared ), FUSION_REF_WATCH, &watch)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_REF_WATCH");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_inherit (FusionRef *ref, FusionRef *from)
+{
+ FusionRefInherit inherit;
+
+ D_ASSERT( ref != NULL );
+ D_ASSERT( from != NULL );
+
+ inherit.id = ref->multi.id;
+ inherit.from = from->multi.id;
+
+ while (ioctl (_fusion_fd( ref->multi.shared ), FUSION_REF_INHERIT, &inherit)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_REF_INHERIT");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_destroy (FusionRef *ref)
+{
+ D_ASSERT( ref != NULL );
+
+ D_DEBUG_AT( Fusion_Ref, "fusion_ref_destroy( %p [%d] )\n", ref, ref->multi.id );
+
+ while (ioctl (_fusion_fd( ref->multi.shared ), FUSION_REF_DESTROY, &ref->multi.id)) {
+ switch (errno) {
+ case EINTR:
+ continue;
+ case EINVAL:
+ D_ERROR ("Fusion/Reference: invalid reference\n");
+ return DR_DESTROYED;
+ default:
+ break;
+ }
+
+ D_PERROR ("FUSION_REF_DESTROY");
+
+ return DR_FAILURE;
+ }
+
+ return DR_OK;
+}
+
+#else /* FUSION_BUILD_KERNEL */
+
+DirectResult
+fusion_ref_init (FusionRef *ref,
+ const char *name,
+ const FusionWorld *world)
+{
+ D_ASSERT( ref != NULL );
+ D_ASSERT( name != NULL );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ D_DEBUG_AT( Fusion_Ref, "fusion_ref_init( %p, '%s' )\n", ref, name ? : "" );
+
+ ref->multi.id = ++world->shared->ref_ids;
+
+ ref->multi.builtin.local = 0;
+ ref->multi.builtin.global = 0;
+
+ fusion_skirmish_init( &ref->multi.builtin.lock, name, world );
+
+ ref->multi.builtin.call = NULL;
+
+ /* Keep back pointer to shared world data. */
+ ref->multi.shared = world->shared;
+ ref->multi.creator = fusion_id( world );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_set_name (FusionRef *ref,
+ const char *name)
+{
+ return DR_OK;
+}
+
+DirectResult
+_fusion_ref_change (FusionRef *ref, int add, bool global)
+{
+ DirectResult ret;
+
+ D_ASSERT( ref != NULL );
+ D_ASSERT( add != 0 );
+
+ ret = fusion_skirmish_prevail( &ref->multi.builtin.lock );
+ if (ret)
+ return ret;
+
+ if (global) {
+ if (ref->multi.builtin.global+add < 0) {
+ D_BUG( "ref has no global references" );
+ fusion_skirmish_dismiss( &ref->multi.builtin.lock );
+ return DR_BUG;
+ }
+
+ ref->multi.builtin.global += add;
+ }
+ else {
+ if (ref->multi.builtin.local+add < 0) {
+ D_BUG( "ref has no local references" );
+ fusion_skirmish_dismiss( &ref->multi.builtin.lock );
+ return DR_BUG;
+ }
+
+ ref->multi.builtin.local += add;
+
+ _fusion_add_local( _fusion_world(ref->multi.shared), ref, add );
+ }
+
+ if (ref->multi.builtin.local+ref->multi.builtin.global == 0) {
+ fusion_skirmish_notify( &ref->multi.builtin.lock );
+
+ if (ref->multi.builtin.call) {
+ fusion_skirmish_dismiss( &ref->multi.builtin.lock );
+ return fusion_call_execute( ref->multi.builtin.call, FCEF_ONEWAY,
+ ref->multi.builtin.call_arg, NULL, NULL );
+ }
+ }
+
+ fusion_skirmish_dismiss( &ref->multi.builtin.lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_up (FusionRef *ref, bool global)
+{
+ return _fusion_ref_change( ref, +1, global );
+}
+
+DirectResult
+fusion_ref_down (FusionRef *ref, bool global)
+{
+ return _fusion_ref_change( ref, -1, global );
+}
+
+DirectResult
+fusion_ref_stat (FusionRef *ref, int *refs)
+{
+ D_ASSERT( ref != NULL );
+ D_ASSERT( refs != NULL );
+
+ *refs = ref->multi.builtin.local + ref->multi.builtin.global;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_zero_lock (FusionRef *ref)
+{
+ DirectResult ret;
+
+ D_ASSERT( ref != NULL );
+
+ ret = fusion_skirmish_prevail( &ref->multi.builtin.lock );
+ if (ret)
+ return ret;
+
+ if (ref->multi.builtin.call) {
+ ret = DR_ACCESSDENIED;
+ }
+ else {
+ if (ref->multi.builtin.local)
+ _fusion_check_locals( _fusion_world(ref->multi.shared), ref );
+
+ while (ref->multi.builtin.local+ref->multi.builtin.global) {
+ ret = fusion_skirmish_wait( &ref->multi.builtin.lock, 1000 ); /* 1 second */
+ if (ret && ret != DR_TIMEOUT);
+ return ret;
+
+ if (ref->multi.builtin.call) {
+ ret = DR_ACCESSDENIED;
+ break;
+ }
+
+ if (ref->multi.builtin.local)
+ _fusion_check_locals( _fusion_world(ref->multi.shared), ref );
+ }
+ }
+
+ if (ret)
+ fusion_skirmish_dismiss( &ref->multi.builtin.lock );
+
+ return ret;
+}
+
+DirectResult
+fusion_ref_zero_trylock (FusionRef *ref)
+{
+ DirectResult ret;
+
+ D_ASSERT( ref != NULL );
+
+ ret = fusion_skirmish_prevail( &ref->multi.builtin.lock );
+ if (ret)
+ return ret;
+
+ if (ref->multi.builtin.local)
+ _fusion_check_locals( _fusion_world(ref->multi.shared), ref );
+
+ if (ref->multi.builtin.local+ref->multi.builtin.global)
+ ret = DR_BUSY;
+
+ if (ret)
+ fusion_skirmish_dismiss( &ref->multi.builtin.lock );
+
+ return ret;
+}
+
+DirectResult
+fusion_ref_unlock (FusionRef *ref)
+{
+ D_ASSERT( ref != NULL );
+
+ fusion_skirmish_dismiss( &ref->multi.builtin.lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_watch (FusionRef *ref, FusionCall *call, int call_arg)
+{
+ DirectResult ret;
+
+ D_ASSERT( ref != NULL );
+ D_ASSERT( call != NULL );
+
+ ret = fusion_skirmish_prevail( &ref->multi.builtin.lock );
+ if (ret)
+ return ret;
+
+ if (ref->multi.builtin.local+ref->multi.builtin.global == 0) {
+ D_BUG( "ref has no references" );
+ ret = DR_BUG;
+ }
+ else if (ref->multi.builtin.call) {
+ ret = DR_BUSY;
+ }
+ else {
+ ref->multi.builtin.call = call;
+ ref->multi.builtin.call_arg = call_arg;
+ fusion_skirmish_notify( &ref->multi.builtin.lock );
+ }
+
+ fusion_skirmish_dismiss( &ref->multi.builtin.lock );
+
+ return ret;
+}
+
+DirectResult
+fusion_ref_inherit (FusionRef *ref, FusionRef *from)
+{
+ D_ASSERT( ref != NULL );
+ D_ASSERT( from != NULL );
+
+ D_UNIMPLEMENTED();
+
+ return fusion_ref_up( ref, true );
+}
+
+DirectResult
+fusion_ref_destroy (FusionRef *ref)
+{
+ FusionSkirmish *skirmish;
+
+ D_ASSERT( ref != NULL );
+
+ D_DEBUG_AT( Fusion_Ref, "fusion_ref_destroy( %p )\n", ref );
+
+ skirmish = &ref->multi.builtin.lock;
+ if (skirmish->multi.builtin.destroyed)
+ return DR_DESTROYED;
+
+ _fusion_remove_all_locals( _fusion_world(ref->multi.shared), ref );
+
+ fusion_skirmish_destroy( skirmish );
+
+ return DR_OK;
+}
+
+#endif /* FUSION_BUILD_KERNEL */
+
+#else /* FUSION_BUILD_MULTI */
+
+DirectResult
+fusion_ref_init (FusionRef *ref,
+ const char *name,
+ const FusionWorld *world)
+{
+ D_ASSERT( ref != NULL );
+ D_ASSERT( name != NULL );
+
+ direct_util_recursive_pthread_mutex_init (&ref->single.lock);
+ pthread_cond_init (&ref->single.cond, NULL);
+
+ ref->single.refs = 0;
+ ref->single.destroyed = false;
+ ref->single.locked = 0;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_set_name (FusionRef *ref,
+ const char *name)
+{
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_up (FusionRef *ref, bool global)
+{
+ DirectResult ret = DR_OK;
+
+ D_ASSERT( ref != NULL );
+
+ pthread_mutex_lock (&ref->single.lock);
+
+ if (ref->single.destroyed)
+ ret = DR_DESTROYED;
+ else if (ref->single.locked)
+ ret = DR_LOCKED;
+ else
+ ref->single.refs++;
+
+ pthread_mutex_unlock (&ref->single.lock);
+
+ return ret;
+}
+
+DirectResult
+fusion_ref_down (FusionRef *ref, bool global)
+{
+ D_ASSERT( ref != NULL );
+
+ pthread_mutex_lock (&ref->single.lock);
+
+ if (!ref->single.refs) {
+ D_BUG( "no more references" );
+ pthread_mutex_unlock (&ref->single.lock);
+ return DR_BUG;
+ }
+
+ if (ref->single.destroyed) {
+ pthread_mutex_unlock (&ref->single.lock);
+ return DR_DESTROYED;
+ }
+
+ if (! --ref->single.refs) {
+ if (ref->single.call) {
+ FusionCall *call = ref->single.call;
+
+ if (call->handler) {
+ int ret;
+ pthread_mutex_unlock (&ref->single.lock);
+ call->handler( 0, ref->single.call_arg, NULL, call->ctx, 0, &ret );
+ return DR_OK;
+ }
+ }
+ else
+ pthread_cond_broadcast (&ref->single.cond);
+ }
+
+ pthread_mutex_unlock (&ref->single.lock);
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_stat (FusionRef *ref, int *refs)
+{
+ D_ASSERT( ref != NULL );
+ D_ASSERT( refs != NULL );
+
+ if (ref->single.destroyed)
+ return DR_DESTROYED;
+
+ *refs = ref->single.refs;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_ref_zero_lock (FusionRef *ref)
+{
+ DirectResult ret = DR_OK;
+
+ D_ASSERT( ref != NULL );
+
+ pthread_mutex_lock (&ref->single.lock);
+
+ do {
+ if (ref->single.destroyed)
+ ret = DR_DESTROYED;
+ else if (ref->single.locked)
+ ret = DR_LOCKED;
+ else if (ref->single.refs)
+ pthread_cond_wait (&ref->single.cond, &ref->single.lock);
+ else {
+ ref->single.locked = direct_gettid();
+ break;
+ }
+ } while (ret == DR_OK);
+
+ pthread_mutex_unlock (&ref->single.lock);
+
+ return ret;
+}
+
+DirectResult
+fusion_ref_zero_trylock (FusionRef *ref)
+{
+ DirectResult ret = DR_OK;
+
+ D_ASSERT( ref != NULL );
+
+ pthread_mutex_lock (&ref->single.lock);
+
+ if (ref->single.destroyed)
+ ret = DR_DESTROYED;
+ else if (ref->single.locked)
+ ret = DR_LOCKED;
+ else if (ref->single.refs)
+ ret = DR_BUSY;
+ else
+ ref->single.locked = direct_gettid();
+
+ pthread_mutex_unlock (&ref->single.lock);
+
+ return ret;
+}
+
+DirectResult
+fusion_ref_unlock (FusionRef *ref)
+{
+ DirectResult ret = DR_OK;
+
+ D_ASSERT( ref != NULL );
+
+ pthread_mutex_lock (&ref->single.lock);
+
+ if (ref->single.locked == direct_gettid()) {
+ ref->single.locked = 0;
+
+ pthread_cond_broadcast (&ref->single.cond);
+ }
+ else
+ ret = DR_ACCESSDENIED;
+
+ pthread_mutex_unlock (&ref->single.lock);
+
+ return ret;
+}
+
+DirectResult
+fusion_ref_watch (FusionRef *ref, FusionCall *call, int call_arg)
+{
+ DirectResult ret = DR_OK;
+
+ D_ASSERT( ref != NULL );
+ D_ASSERT( call != NULL );
+
+ pthread_mutex_lock (&ref->single.lock);
+
+ if (ref->single.destroyed)
+ ret = DR_DESTROYED;
+ else if (!ref->single.refs)
+ ret = DR_BUG;
+ else if (ref->single.call)
+ ret = DR_BUSY;
+ else {
+ ref->single.call = call;
+ ref->single.call_arg = call_arg;
+ }
+
+ pthread_mutex_unlock (&ref->single.lock);
+
+ return ret;
+}
+
+DirectResult
+fusion_ref_inherit (FusionRef *ref, FusionRef *from)
+{
+ D_ASSERT( ref != NULL );
+ D_ASSERT( from != NULL );
+
+ D_UNIMPLEMENTED();
+
+ /* FIXME */
+ return fusion_ref_up( ref, true );
+}
+
+DirectResult
+fusion_ref_destroy (FusionRef *ref)
+{
+ D_ASSERT( ref != NULL );
+
+ ref->single.destroyed = true;
+
+ pthread_cond_broadcast (&ref->single.cond);
+
+ pthread_mutex_destroy (&ref->single.lock);
+ pthread_cond_destroy (&ref->single.cond);
+
+ return DR_OK;
+}
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/ref.h b/Source/DirectFB/lib/fusion/ref.h
new file mode 100755
index 0000000..b9beda7
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/ref.h
@@ -0,0 +1,134 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__REF_H__
+#define __FUSION__REF_H__
+
+#include <pthread.h>
+
+#include <fusion/types.h>
+#include <fusion/call.h>
+#include <fusion/lock.h>
+
+typedef union {
+ /* multi app */
+ struct {
+ int id;
+ const FusionWorldShared *shared;
+ FusionID creator;
+ /* builtin impl */
+ struct {
+ int local;
+ int global;
+ FusionSkirmish lock;
+
+ FusionCall *call;
+ int call_arg;
+ } builtin;
+ } multi;
+
+ /* single app */
+ struct {
+ int refs;
+ pthread_cond_t cond;
+ pthread_mutex_t lock;
+ bool destroyed;
+ int locked;
+
+ FusionCall *call;
+ int call_arg;
+ } single;
+} FusionRef;
+
+/*
+ * Initialize.
+ */
+DirectResult fusion_ref_init (FusionRef *ref,
+ const char *name,
+ const FusionWorld *world);
+
+DirectResult fusion_ref_set_name (FusionRef *ref,
+ const char *name);
+
+/*
+ * Lock, increase, unlock.
+ */
+DirectResult fusion_ref_up (FusionRef *ref, bool global);
+
+/*
+ * Lock, decrease, unlock.
+ */
+DirectResult fusion_ref_down (FusionRef *ref, bool global);
+
+/*
+ * Get the current reference count. Meant for debugging only.
+ * This value is not reliable, because no locking will be performed
+ * and the value may change after or even while returning it.
+ */
+DirectResult fusion_ref_stat (FusionRef *ref, int *refs);
+
+/*
+ * Wait for zero and lock.
+ */
+DirectResult fusion_ref_zero_lock (FusionRef *ref);
+
+/*
+ * Check for zero and lock if true.
+ */
+DirectResult fusion_ref_zero_trylock (FusionRef *ref);
+
+/*
+ * Unlock the counter.
+ * Only to be called after successful zero_lock or zero_trylock.
+ */
+DirectResult fusion_ref_unlock (FusionRef *ref);
+
+/*
+ * Have the call executed when reference counter reaches zero.
+ */
+DirectResult fusion_ref_watch (FusionRef *ref,
+ FusionCall *call,
+ int call_arg);
+
+/*
+ * Inherit local reference count from another reference.
+ *
+ * The local count of the other reference (and its inherited references) is added to this reference.
+ */
+DirectResult fusion_ref_inherit (FusionRef *ref,
+ FusionRef *from);
+
+/*
+ * Deinitialize.
+ * Can be called after successful zero_lock or zero_trylock
+ * so that waiting fusion_ref_up calls return with DR_DESTROYED.
+ */
+DirectResult fusion_ref_destroy (FusionRef *ref);
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/shm/Makefile.am b/Source/DirectFB/lib/fusion/shm/Makefile.am
new file mode 100755
index 0000000..23ed4a5
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shm/Makefile.am
@@ -0,0 +1,31 @@
+## Makefile.am for DirectFB/lib/fusion/shm
+
+INCLUDES = \
+ -I$(top_builddir)/include \
+ -I$(top_builddir)/lib \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"@DATADIR@\" \
+ -DMODULEDIR=\"@MODULEDIR@\"
+
+if ENABLE_MULTI
+SHMSOURCES = heap.c pool.c shm.c
+else
+SHMSOURCES = fake.c
+endif
+
+EXTRA_DIST = fake.c
+
+noinst_LTLIBRARIES = libfusion_shm.la
+
+libfusion_shm_la_SOURCES = \
+ $(SHMSOURCES)
+
+includedir = @INCLUDEDIR@/fusion/shm
+
+include_HEADERS = \
+ pool.h \
+ shm.h \
+ shm_internal.h
diff --git a/Source/DirectFB/lib/fusion/shm/Makefile.in b/Source/DirectFB/lib/fusion/shm/Makefile.in
new file mode 100755
index 0000000..987fa8f
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shm/Makefile.in
@@ -0,0 +1,565 @@
+# Makefile.in generated by automake 1.10.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+subdir = lib/fusion/shm
+DIST_COMMON = $(include_HEADERS) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libfusion_shm_la_LIBADD =
+am__libfusion_shm_la_SOURCES_DIST = fake.c heap.c pool.c shm.c
+@ENABLE_MULTI_FALSE@am__objects_1 = fake.lo
+@ENABLE_MULTI_TRUE@am__objects_1 = heap.lo pool.lo shm.lo
+am_libfusion_shm_la_OBJECTS = $(am__objects_1)
+libfusion_shm_la_OBJECTS = $(am_libfusion_shm_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libfusion_shm_la_SOURCES)
+DIST_SOURCES = $(am__libfusion_shm_la_SOURCES_DIST)
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(includedir)"
+includeHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(include_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+ASFLAGS = @ASFLAGS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIR = @DATADIR@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DFB_CFLAGS_OMIT_FRAME_POINTER = @DFB_CFLAGS_OMIT_FRAME_POINTER@
+DFB_INTERNAL_CFLAGS = @DFB_INTERNAL_CFLAGS@
+DFB_LDFLAGS = @DFB_LDFLAGS@
+DFB_SMOOTH_SCALING = @DFB_SMOOTH_SCALING@
+DIRECTFB_BINARY_AGE = @DIRECTFB_BINARY_AGE@
+DIRECTFB_CSOURCE = @DIRECTFB_CSOURCE@
+DIRECTFB_INTERFACE_AGE = @DIRECTFB_INTERFACE_AGE@
+DIRECTFB_MAJOR_VERSION = @DIRECTFB_MAJOR_VERSION@
+DIRECTFB_MICRO_VERSION = @DIRECTFB_MICRO_VERSION@
+DIRECTFB_MINOR_VERSION = @DIRECTFB_MINOR_VERSION@
+DIRECTFB_VERSION = @DIRECTFB_VERSION@
+DIRECT_BUILD_DEBUG = @DIRECT_BUILD_DEBUG@
+DIRECT_BUILD_DEBUGS = @DIRECT_BUILD_DEBUGS@
+DIRECT_BUILD_GETTID = @DIRECT_BUILD_GETTID@
+DIRECT_BUILD_NETWORK = @DIRECT_BUILD_NETWORK@
+DIRECT_BUILD_STDBOOL = @DIRECT_BUILD_STDBOOL@
+DIRECT_BUILD_TEXT = @DIRECT_BUILD_TEXT@
+DIRECT_BUILD_TRACE = @DIRECT_BUILD_TRACE@
+DSYMUTIL = @DSYMUTIL@
+DYNLIB = @DYNLIB@
+ECHO = @ECHO@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+F77 = @F77@
+FFLAGS = @FFLAGS@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+FREETYPE_PROVIDER = @FREETYPE_PROVIDER@
+FUSION_BUILD_KERNEL = @FUSION_BUILD_KERNEL@
+FUSION_BUILD_MULTI = @FUSION_BUILD_MULTI@
+FUSION_MESSAGE_SIZE = @FUSION_MESSAGE_SIZE@
+GIF_PROVIDER = @GIF_PROVIDER@
+GREP = @GREP@
+HAVE_LINUX = @HAVE_LINUX@
+INCLUDEDIR = @INCLUDEDIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTERNALINCLUDEDIR = @INTERNALINCLUDEDIR@
+JPEG_PROVIDER = @JPEG_PROVIDER@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBJPEG = @LIBJPEG@
+LIBOBJS = @LIBOBJS@
+LIBPNG = @LIBPNG@
+LIBPNG_CONFIG = @LIBPNG_CONFIG@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_AGE = @LT_AGE@
+LT_BINARY = @LT_BINARY@
+LT_CURRENT = @LT_CURRENT@
+LT_RELEASE = @LT_RELEASE@
+LT_REVISION = @LT_REVISION@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MAN2HTML = @MAN2HTML@
+MKDIR_P = @MKDIR_P@
+MODULEDIR = @MODULEDIR@
+MODULEDIRNAME = @MODULEDIRNAME@
+NMEDIT = @NMEDIT@
+OBJEXT = @OBJEXT@
+OSX_LIBS = @OSX_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKG_CONFIG = @PKG_CONFIG@
+PNG_PROVIDER = @PNG_PROVIDER@
+RANLIB = @RANLIB@
+RUNTIME_SYSROOT = @RUNTIME_SYSROOT@
+SDL_CFLAGS = @SDL_CFLAGS@
+SDL_LIBS = @SDL_LIBS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOPATH = @SOPATH@
+STRIP = @STRIP@
+SYSCONFDIR = @SYSCONFDIR@
+SYSFS_LIBS = @SYSFS_LIBS@
+THREADFLAGS = @THREADFLAGS@
+THREADLIB = @THREADLIB@
+TSLIB_CFLAGS = @TSLIB_CFLAGS@
+TSLIB_LIBS = @TSLIB_LIBS@
+VERSION = @VERSION@
+VNC_CFLAGS = @VNC_CFLAGS@
+VNC_CONFIG = @VNC_CONFIG@
+VNC_LIBS = @VNC_LIBS@
+X11_CFLAGS = @X11_CFLAGS@
+X11_LIBS = @X11_LIBS@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_F77 = @ac_ct_F77@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @INCLUDEDIR@/fusion/shm
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = \
+ -I$(top_builddir)/include \
+ -I$(top_builddir)/lib \
+ -I$(top_srcdir)/include \
+ -I$(top_srcdir)/lib
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"@DATADIR@\" \
+ -DMODULEDIR=\"@MODULEDIR@\"
+
+@ENABLE_MULTI_FALSE@SHMSOURCES = fake.c
+@ENABLE_MULTI_TRUE@SHMSOURCES = heap.c pool.c shm.c
+EXTRA_DIST = fake.c
+noinst_LTLIBRARIES = libfusion_shm.la
+libfusion_shm_la_SOURCES = \
+ $(SHMSOURCES)
+
+include_HEADERS = \
+ pool.h \
+ shm.h \
+ shm_internal.h
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/fusion/shm/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu lib/fusion/shm/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libfusion_shm.la: $(libfusion_shm_la_OBJECTS) $(libfusion_shm_la_DEPENDENCIES)
+ $(LINK) $(libfusion_shm_la_OBJECTS) $(libfusion_shm_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fake.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pool.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/shm.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-includeHEADERS: $(include_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(includeHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(includedir)/$$f'"; \
+ $(includeHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+uninstall-includeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(include_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(includedir)/$$f'"; \
+ rm -f "$(DESTDIR)$(includedir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(includedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-includeHEADERS
+
+install-dvi: install-dvi-am
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-info: install-info-am
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-ps: install-ps-am
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-includeHEADERS
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-includeHEADERS install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am uninstall-includeHEADERS
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/Source/DirectFB/lib/fusion/shm/fake.c b/Source/DirectFB/lib/fusion/shm/fake.c
new file mode 100755
index 0000000..32e25cd
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shm/fake.c
@@ -0,0 +1,163 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#include <direct/debug.h>
+#include <direct/mem.h>
+#include <direct/messages.h>
+
+#include <fusion/shm/shm.h>
+#include <fusion/shm/pool.h>
+
+#include <fusion/shm/shm_internal.h>
+
+
+DirectResult
+fusion_shm_pool_create( FusionWorld *world,
+ const char *name,
+ unsigned int max_size,
+ bool debug,
+ FusionSHMPoolShared **ret_pool )
+{
+ FusionSHMPoolShared *pool;
+
+#if !DIRECT_BUILD_DEBUGS
+ debug = false;
+#endif
+
+ pool = D_CALLOC( 1, sizeof(FusionSHMPoolShared) );
+ if (!pool)
+ return D_OOM();
+
+ pool->debug = debug;
+
+ D_MAGIC_SET( pool, FusionSHMPoolShared );
+
+ *ret_pool = pool;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_destroy( FusionWorld *world,
+ FusionSHMPoolShared *pool )
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ D_MAGIC_CLEAR( pool );
+
+ D_FREE( pool );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_attach( FusionSHM *shm,
+ FusionSHMPoolShared *pool )
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ pool->index++;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_detach( FusionSHM *shm,
+ FusionSHMPoolShared *pool )
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ D_ASSERT( pool->index > 0 );
+
+ pool->index--;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_allocate( FusionSHMPoolShared *pool,
+ int size,
+ bool clear,
+ bool lock,
+ void **ret_data )
+{
+ void *data;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ data = clear ? D_CALLOC( 1, size ) : D_MALLOC( size );
+ if (!data)
+ return DR_NOSHAREDMEMORY;
+
+ *ret_data = data;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_reallocate( FusionSHMPoolShared *pool,
+ void *data,
+ int size,
+ bool lock,
+ void **ret_data )
+{
+ void *new_data;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ new_data = D_REALLOC( data, size );
+ if (!new_data)
+ return DR_NOSHAREDMEMORY;
+
+ *ret_data = new_data;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_deallocate( FusionSHMPoolShared *pool,
+ void *data,
+ bool lock )
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ D_FREE( data );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_enum_pools( FusionWorld *world,
+ FusionSHMPoolCallback callback,
+ void *ctx )
+{
+ return DR_OK;
+}
+
diff --git a/Source/DirectFB/lib/fusion/shm/heap.c b/Source/DirectFB/lib/fusion/shm/heap.c
new file mode 100755
index 0000000..4a76229
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shm/heap.c
@@ -0,0 +1,802 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/* Heap management adapted from libc
+ Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
+ Written May 1989 by Mike Haertel.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with this library; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+ The author may be reached (Email) at the address mike@ai.mit.edu,
+ or (US mail) as Mike Haertel c/o Free Software Foundation. */
+
+#include <config.h>
+
+#include <unistd.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#include <direct/debug.h>
+#include <direct/list.h>
+#include <direct/mem.h>
+#include <direct/memcpy.h>
+#include <direct/messages.h>
+#include <direct/util.h>
+
+#include <fusion/conf.h>
+#include <fusion/shmalloc.h>
+#include <fusion/fusion_internal.h>
+
+#include <fusion/shm/pool.h>
+#include <fusion/shm/shm_internal.h>
+
+
+D_DEBUG_DOMAIN( Fusion_SHMHeap, "Fusion/SHMHeap", "Fusion Shared Memory Heap" );
+
+/**********************************************************************************************************************/
+
+/* Aligned allocation. */
+static void *
+align( shmalloc_heap *heap, size_t size )
+{
+ void *result;
+ unsigned long adj;
+
+ D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %zu )\n", __FUNCTION__, heap, size );
+
+ D_MAGIC_ASSERT( heap, shmalloc_heap );
+
+ result = __shmalloc_brk( heap, size );
+
+ adj = (unsigned long) result % BLOCKSIZE;
+ if (adj != 0) {
+ adj = BLOCKSIZE - adj;
+ __shmalloc_brk( heap, adj );
+ result = (char *) result + adj;
+ }
+
+ return result;
+}
+
+/* Get neatly aligned memory, initializing or
+ growing the heap info table as necessary. */
+static void *
+morecore( shmalloc_heap *heap, size_t size )
+{
+ void *result;
+ shmalloc_info *newinfo, *oldinfo;
+ size_t newsize;
+
+ D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %zu )\n", __FUNCTION__, heap, size );
+
+ D_MAGIC_ASSERT( heap, shmalloc_heap );
+
+ result = align( heap, size );
+ if (result == NULL)
+ return NULL;
+
+ /* Check if we need to grow the info table. */
+ if ((size_t) BLOCK ((char *) result + size) > heap->heapsize) {
+ newsize = heap->heapsize;
+
+ while ((size_t) BLOCK ((char *) result + size) > newsize)
+ newsize *= 2;
+
+ newinfo = (shmalloc_info *) align( heap, newsize * sizeof (shmalloc_info) );
+ if (newinfo == NULL) {
+ __shmalloc_brk( heap, -size );
+ return NULL;
+ }
+
+ direct_memcpy( newinfo, heap->heapinfo,
+ heap->heapsize * sizeof (shmalloc_info) );
+
+ memset (newinfo + heap->heapsize,
+ 0, (newsize - heap->heapsize) * sizeof (shmalloc_info));
+
+ oldinfo = heap->heapinfo;
+
+ newinfo[BLOCK (oldinfo)].busy.type = 0;
+ newinfo[BLOCK (oldinfo)].busy.info.size = BLOCKIFY (heap->heapsize * sizeof (shmalloc_info));
+
+ heap->heapinfo = newinfo;
+
+ _fusion_shfree( heap, oldinfo );
+
+ heap->heapsize = newsize;
+ }
+
+ heap->heaplimit = BLOCK ((char *) result + size);
+
+ return result;
+}
+
+/**********************************************************************************************************************/
+
+/* Allocate memory from the heap. */
+void *
+_fusion_shmalloc( shmalloc_heap *heap, size_t size )
+{
+ void *result;
+ size_t block, blocks, lastblocks, start;
+ register size_t i;
+ struct list *next;
+
+ D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %zu )\n", __FUNCTION__, heap, size );
+
+ D_MAGIC_ASSERT( heap, shmalloc_heap );
+
+ /* Some programs will call shmalloc (0). We let them pass. */
+ if (size == 0)
+ return NULL;
+
+ if (size < sizeof (struct list))
+ size = sizeof (struct list);
+
+ /* Determine the allocation policy based on the request size. */
+ if (size <= BLOCKSIZE / 2) {
+ /* Small allocation to receive a fragment of a block.
+ Determine the logarithm to base two of the fragment size. */
+ register size_t log = 1;
+ --size;
+ while ((size /= 2) != 0)
+ ++log;
+
+ /* Look in the fragment lists for a
+ free fragment of the desired size. */
+ next = heap->fraghead[log].next;
+ if (next != NULL) {
+ /* There are free fragments of this size.
+ Pop a fragment out of the fragment list and return it.
+ Update the block's nfree and first counters. */
+ result = (void *) next;
+ next->prev->next = next->next;
+ if (next->next != NULL)
+ next->next->prev = next->prev;
+ block = BLOCK (result);
+ if (--(heap->heapinfo[block].busy.info.frag.nfree) != 0)
+ heap->heapinfo[block].busy.info.frag.first = (unsigned long int)
+ ((unsigned long int) ((char *) next->next - (char *) NULL)
+ % BLOCKSIZE) >> log;
+
+ /* Update the statistics. */
+ heap->chunks_used++;
+ heap->bytes_used += 1 << log;
+ heap->chunks_free--;
+ heap->bytes_free -= 1 << log;
+ }
+ else {
+ /* No free fragments of the desired size, so get a new block
+ and break it into fragments, returning the first. */
+ result = _fusion_shmalloc( heap, BLOCKSIZE );
+ if (result == NULL)
+ return NULL;
+#if 1 /* Adapted from Mike */
+ heap->fragblocks[log]++;
+#endif
+
+ /* Link all fragments but the first into the free list. */
+ for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i) {
+ next = (struct list *) ((char *) result + (i << log));
+ next->next = heap->fraghead[log].next;
+ next->prev = &heap->fraghead[log];
+ next->prev->next = next;
+ if (next->next != NULL)
+ next->next->prev = next;
+ }
+
+ /* Initialize the nfree and first counters for this block. */
+ block = BLOCK (result);
+ heap->heapinfo[block].busy.type = log;
+ heap->heapinfo[block].busy.info.frag.nfree = i - 1;
+ heap->heapinfo[block].busy.info.frag.first = i - 1;
+
+ heap->chunks_free += (BLOCKSIZE >> log) - 1;
+ heap->bytes_free += BLOCKSIZE - (1 << log);
+ heap->bytes_used -= BLOCKSIZE - (1 << log);
+ }
+ }
+ else {
+ /* Large allocation to receive one or more blocks.
+ Search the free list in a circle starting at the last place visited.
+ If we loop completely around without finding a large enough
+ space we will have to get more memory from the system. */
+ blocks = BLOCKIFY (size);
+ start = block = heap->heapindex;
+ while (heap->heapinfo[block].free.size < blocks) {
+ block = heap->heapinfo[block].free.next;
+ if (block == start) {
+ /* Need to get more from the system. Check to see if
+ the new core will be contiguous with the final free
+ block; if so we don't need to get as much. */
+ block = heap->heapinfo[0].free.prev;
+ lastblocks = heap->heapinfo[block].free.size;
+ if (heap->heaplimit != 0 && block + lastblocks == heap->heaplimit &&
+ __shmalloc_brk( heap, 0 ) == ADDRESS (block + lastblocks) &&
+ (morecore( heap, (blocks - lastblocks) * BLOCKSIZE) ) != NULL) {
+#if 1 /* Adapted from Mike */
+
+ /* Note that morecore() can change the location of
+ the final block if it moves the info table and the
+ old one gets coalesced into the final block. */
+ block = heap->heapinfo[0].free.prev;
+ heap->heapinfo[block].free.size += blocks - lastblocks;
+#else
+ heap->heapinfo[block].free.size = blocks;
+#endif
+ heap->bytes_free += (blocks - lastblocks) * BLOCKSIZE;
+ continue;
+ }
+ result = morecore( heap, blocks * BLOCKSIZE );
+ if (result == NULL)
+ return NULL;
+ block = BLOCK (result);
+ heap->heapinfo[block].busy.type = 0;
+ heap->heapinfo[block].busy.info.size = blocks;
+ heap->chunks_used++;
+ heap->bytes_used += blocks * BLOCKSIZE;
+ return result;
+ }
+ }
+
+ /* At this point we have found a suitable free list entry.
+ Figure out how to remove what we need from the list. */
+ result = ADDRESS (block);
+ if (heap->heapinfo[block].free.size > blocks) {
+ /* The block we found has a bit left over,
+ so relink the tail end back into the free list. */
+ heap->heapinfo[block + blocks].free.size
+ = heap->heapinfo[block].free.size - blocks;
+ heap->heapinfo[block + blocks].free.next
+ = heap->heapinfo[block].free.next;
+ heap->heapinfo[block + blocks].free.prev
+ = heap->heapinfo[block].free.prev;
+ heap->heapinfo[heap->heapinfo[block].free.prev].free.next
+ = heap->heapinfo[heap->heapinfo[block].free.next].free.prev
+ = heap->heapindex = block + blocks;
+ }
+ else {
+ /* The block exactly matches our requirements,
+ so just remove it from the list. */
+ heap->heapinfo[heap->heapinfo[block].free.next].free.prev
+ = heap->heapinfo[block].free.prev;
+ heap->heapinfo[heap->heapinfo[block].free.prev].free.next
+ = heap->heapindex = heap->heapinfo[block].free.next;
+ heap->chunks_free--;
+ }
+
+ heap->heapinfo[block].busy.type = 0;
+ heap->heapinfo[block].busy.info.size = blocks;
+ heap->chunks_used++;
+ heap->bytes_used += blocks * BLOCKSIZE;
+ heap->bytes_free -= blocks * BLOCKSIZE;
+ }
+
+ return result;
+}
+
+/* Resize the given region to the new size, returning a pointer
+ to the (possibly moved) region. This is optimized for speed;
+ some benchmarks seem to indicate that greater compactness is
+ achieved by unconditionally allocating and copying to a
+ new region. This module has incestuous knowledge of the
+ internals of both free and shmalloc. */
+void *
+_fusion_shrealloc( shmalloc_heap *heap, void *ptr, size_t size )
+{
+ void *result;
+ int type;
+ size_t block, blocks, oldlimit;
+
+ D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %p, %zu )\n", __FUNCTION__, heap, ptr, size );
+
+ D_MAGIC_ASSERT( heap, shmalloc_heap );
+
+ if (ptr == NULL)
+ return _fusion_shmalloc( heap, size );
+ else if (size == 0) {
+ _fusion_shfree( heap, ptr );
+ return NULL;
+ }
+
+ block = BLOCK (ptr);
+
+ type = heap->heapinfo[block].busy.type;
+ switch (type) {
+ case 0:
+ /* Maybe reallocate a large block to a small fragment. */
+ if (size <= BLOCKSIZE / 2) {
+ result = _fusion_shmalloc( heap, size );
+ if (result != NULL) {
+ direct_memcpy (result, ptr, size);
+ _fusion_shfree( heap, ptr );
+ return result;
+ }
+ }
+
+ /* The new size is a large allocation as well;
+ see if we can hold it in place. */
+ blocks = BLOCKIFY (size);
+ if (blocks < heap->heapinfo[block].busy.info.size) {
+ /* The new size is smaller; return
+ excess memory to the free list. */
+ heap->heapinfo[block + blocks].busy.type = 0;
+ heap->heapinfo[block + blocks].busy.info.size
+ = heap->heapinfo[block].busy.info.size - blocks;
+ heap->heapinfo[block].busy.info.size = blocks;
+ _fusion_shfree( heap, ADDRESS (block + blocks) );
+ result = ptr;
+ }
+ else if (blocks == heap->heapinfo[block].busy.info.size)
+ /* No size change necessary. */
+ result = ptr;
+ else {
+ /* Won't fit, so allocate a new region that will.
+ Free the old region first in case there is sufficient
+ adjacent free space to grow without moving. */
+ blocks = heap->heapinfo[block].busy.info.size;
+ /* Prevent free from actually returning memory to the system. */
+ oldlimit = heap->heaplimit;
+ heap->heaplimit = 0;
+ _fusion_shfree( heap, ptr );
+ heap->heaplimit = oldlimit;
+ result = _fusion_shmalloc( heap, size );
+ if (result == NULL) {
+ /* Now we're really in trouble. We have to unfree
+ the thing we just freed. Unfortunately it might
+ have been coalesced with its neighbors. */
+ if (heap->heapindex == block)
+ (void) _fusion_shmalloc( heap, blocks * BLOCKSIZE );
+ else {
+ void *previous = _fusion_shmalloc( heap, (block - heap->heapindex) * BLOCKSIZE );
+ (void) _fusion_shmalloc( heap, blocks * BLOCKSIZE );
+ _fusion_shfree( heap, previous );
+ }
+ return NULL;
+ }
+ if (ptr != result)
+ direct_memmove (result, ptr, blocks * BLOCKSIZE);
+ }
+ break;
+
+ default:
+ /* Old size is a fragment; type is logarithm
+ to base two of the fragment size. */
+ if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
+ /* The new size is the same kind of fragment. */
+ result = ptr;
+ else {
+ /* The new size is different; allocate a new space,
+ and copy the lesser of the new size and the old. */
+ result = _fusion_shmalloc( heap, size );
+ if (result == NULL)
+ return NULL;
+ direct_memcpy (result, ptr, MIN (size, (size_t) 1 << type));
+ _fusion_shfree( heap, ptr );
+ }
+ break;
+ }
+
+ return result;
+}
+
+/* Return memory to the heap. */
+void
+_fusion_shfree( shmalloc_heap *heap, void *ptr )
+{
+ int type;
+ size_t block, blocks;
+ register size_t i;
+ struct list *prev, *next;
+
+ D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %p )\n", __FUNCTION__, heap, ptr );
+
+ D_MAGIC_ASSERT( heap, shmalloc_heap );
+
+ if (ptr == NULL)
+ return;
+
+ block = BLOCK (ptr);
+
+ type = heap->heapinfo[block].busy.type;
+ switch (type) {
+ case 0:
+ /* Get as many statistics as early as we can. */
+ heap->chunks_used--;
+ heap->bytes_used -= heap->heapinfo[block].busy.info.size * BLOCKSIZE;
+ heap->bytes_free += heap->heapinfo[block].busy.info.size * BLOCKSIZE;
+
+ /* Find the free cluster previous to this one in the free list.
+ Start searching at the last block referenced; this may benefit
+ programs with locality of allocation. */
+ i = heap->heapindex;
+ if (i > block)
+ while (i > block)
+ i = heap->heapinfo[i].free.prev;
+ else {
+ do
+ i = heap->heapinfo[i].free.next;
+ while (i > 0 && i < block);
+ i = heap->heapinfo[i].free.prev;
+ }
+
+ /* Determine how to link this block into the free list. */
+ if (block == i + heap->heapinfo[i].free.size) {
+ /* Coalesce this block with its predecessor. */
+ heap->heapinfo[i].free.size += heap->heapinfo[block].busy.info.size;
+ block = i;
+ }
+ else {
+ /* Really link this block back into the free list. */
+ heap->heapinfo[block].free.size = heap->heapinfo[block].busy.info.size;
+ heap->heapinfo[block].free.next = heap->heapinfo[i].free.next;
+ heap->heapinfo[block].free.prev = i;
+ heap->heapinfo[i].free.next = block;
+ heap->heapinfo[heap->heapinfo[block].free.next].free.prev = block;
+ heap->chunks_free++;
+ }
+
+ /* Now that the block is linked in, see if we can coalesce it
+ with its successor (by deleting its successor from the list
+ and adding in its size). */
+ if (block + heap->heapinfo[block].free.size == heap->heapinfo[block].free.next) {
+ heap->heapinfo[block].free.size
+ += heap->heapinfo[heap->heapinfo[block].free.next].free.size;
+ heap->heapinfo[block].free.next
+ = heap->heapinfo[heap->heapinfo[block].free.next].free.next;
+ heap->heapinfo[heap->heapinfo[block].free.next].free.prev = block;
+ heap->chunks_free--;
+ }
+
+ blocks = heap->heapinfo[block].free.size;
+
+/* FIXME: as this is used when kernel is detected as >= 2.6.19.2 only, this fallback definition should be ok for now */
+#ifndef MADV_REMOVE
+#define MADV_REMOVE 9
+#endif
+ /* Punch a hole into the tmpfs file to really free RAM. */
+ if (fusion_config->madv_remove)
+ madvise( ADDRESS(block), blocks * BLOCKSIZE, MADV_REMOVE );
+
+ /* Now see if we can truncate the end. */
+ if (blocks >= FINAL_FREE_BLOCKS && block + blocks == heap->heaplimit
+ && __shmalloc_brk( heap, 0 ) == ADDRESS (block + blocks))
+ {
+ register size_t bytes = blocks * BLOCKSIZE;
+ heap->heaplimit -= blocks;
+ __shmalloc_brk( heap, -bytes );
+ heap->heapinfo[heap->heapinfo[block].free.prev].free.next = heap->heapinfo[block].free.next;
+ heap->heapinfo[heap->heapinfo[block].free.next].free.prev = heap->heapinfo[block].free.prev;
+ block = heap->heapinfo[block].free.prev;
+ heap->chunks_free--;
+ heap->bytes_free -= bytes;
+ }
+
+ /* Set the next search to begin at this block. */
+ heap->heapindex = block;
+ break;
+
+ default:
+ /* Do some of the statistics. */
+ heap->chunks_used--;
+ heap->bytes_used -= 1 << type;
+ heap->chunks_free++;
+ heap->bytes_free += 1 << type;
+
+ /* Get the address of the first free fragment in this block. */
+ prev = (struct list *) ((char *) ADDRESS (block) +
+ (heap->heapinfo[block].busy.info.frag.first << type));
+
+#if 1 /* Adapted from Mike */
+ if ((int)heap->heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1
+ && heap->fragblocks[type] > 1)
+#else
+ if ((int)heap->heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
+#endif
+ {
+ /* If all fragments of this block are free, remove them
+ from the fragment list and free the whole block. */
+#if 1 /* Adapted from Mike */
+ heap->fragblocks[type]--;
+#endif
+ next = prev;
+ for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
+ next = next->next;
+ prev->prev->next = next;
+ if (next != NULL)
+ next->prev = prev->prev;
+ heap->heapinfo[block].busy.type = 0;
+ heap->heapinfo[block].busy.info.size = 1;
+
+ /* Keep the statistics accurate. */
+ heap->chunks_used++;
+ heap->bytes_used += BLOCKSIZE;
+ heap->chunks_free -= BLOCKSIZE >> type;
+ heap->bytes_free -= BLOCKSIZE;
+
+ _fusion_shfree( heap, ADDRESS (block) );
+ }
+ else if (heap->heapinfo[block].busy.info.frag.nfree != 0) {
+ /* If some fragments of this block are free, link this
+ fragment into the fragment list after the first free
+ fragment of this block. */
+ next = (struct list *) ptr;
+ next->next = prev->next;
+ next->prev = prev;
+ prev->next = next;
+ if (next->next != NULL)
+ next->next->prev = next;
+ heap->heapinfo[block].busy.info.frag.nfree++;
+ }
+ else {
+ /* No fragments of this block are free, so link this
+ fragment into the fragment list and announce that
+ it is the first free fragment of this block. */
+ prev = (struct list *) ptr;
+ heap->heapinfo[block].busy.info.frag.nfree = 1;
+ heap->heapinfo[block].busy.info.frag.first = (unsigned long int)
+ ((unsigned long int) ((char *) ptr - (char *) NULL)
+ % BLOCKSIZE >> type);
+ prev->next = heap->fraghead[type].next;
+ prev->prev = &heap->fraghead[type];
+ prev->prev->next = prev;
+ if (prev->next != NULL)
+ prev->next->prev = prev;
+ }
+ break;
+ }
+}
+
+/**********************************************************************************************************************/
+
+DirectResult
+__shmalloc_init_heap( FusionSHM *shm,
+ const char *filename,
+ void *addr_base,
+ int space,
+ int *ret_fd,
+ int *ret_size )
+{
+ DirectResult ret;
+ int size;
+ FusionSHMShared *shared;
+ int heapsize = (space + BLOCKSIZE-1) / BLOCKSIZE;
+ int fd = -1;
+ shmalloc_heap *heap = NULL;
+
+ D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, '%s', %p, %d, %p, %p )\n",
+ __FUNCTION__, shm, filename, addr_base, space, ret_fd, ret_size );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_ASSERT( filename != NULL );
+ D_ASSERT( addr_base != NULL );
+ D_ASSERT( ret_fd != NULL );
+ D_ASSERT( ret_size != NULL );
+
+ shared = shm->shared;
+
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+ D_ASSERT( shared->tmpfs[0] != 0 );
+
+ size = BLOCKALIGN(sizeof(shmalloc_heap)) + BLOCKALIGN( heapsize * sizeof(shmalloc_info) );
+
+
+ D_DEBUG_AT( Fusion_SHMHeap, " -> opening shared memory file '%s'...\n", filename );
+
+ /* open the virtual file */
+ fd = open( filename, O_RDWR | O_CREAT | O_TRUNC, 0660 );
+ if (fd < 0) {
+ ret = errno2result(errno);
+ D_PERROR( "Fusion/SHM: Could not open shared memory file '%s'!\n", filename );
+ goto error;
+ }
+
+ if (fusion_config->shmfile_gid != (gid_t)-1) {
+ /* chgrp the SH_FILE dev entry */
+ if (fchown( fd, -1, fusion_config->shmfile_gid ) != 0)
+ D_WARN( "Fusion/SHM: Changing owner on %s failed... continuing on.", filename );
+ }
+
+ fchmod( fd, 0660 );
+ ftruncate( fd, size );
+
+ D_DEBUG_AT( Fusion_SHMHeap, " -> mmaping shared memory file... (%d bytes)\n", size );
+
+ /* map it shared */
+ heap = mmap( addr_base, size + space, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0 );
+ if (heap == MAP_FAILED) {
+ ret = errno2result(errno);
+ D_PERROR( "Fusion/SHM: Could not mmap shared memory file '%s'!\n", filename );
+ goto error;
+ }
+
+ if (heap != addr_base) {
+ D_ERROR( "Fusion/SHM: mmap() returned address (%p) differs from requested (%p)\n", heap, addr_base );
+ ret = DR_FUSION;
+ goto error;
+ }
+
+ D_DEBUG_AT( Fusion_SHMHeap, " -> done.\n" );
+
+ heap->size = size;
+ heap->heapsize = heapsize;
+ heap->heapinfo = (void*) heap + BLOCKALIGN(sizeof(shmalloc_heap));
+ heap->heapbase = (char*) heap->heapinfo;
+
+ D_MAGIC_SET( heap, shmalloc_heap );
+
+ *ret_fd = fd;
+ *ret_size = size;
+
+ return DR_OK;
+
+
+error:
+ if (heap)
+ munmap( heap, size );
+
+ if (fd != -1) {
+ close( fd );
+ unlink( filename );
+ }
+
+ return ret;
+}
+
+DirectResult
+__shmalloc_join_heap( FusionSHM *shm,
+ const char *filename,
+ void *addr_base,
+ int size,
+ int *ret_fd )
+{
+ DirectResult ret;
+ FusionSHMShared *shared;
+ int fd = -1;
+ shmalloc_heap *heap = NULL;
+
+ D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, '%s', %p, %d, %p )\n",
+ __FUNCTION__, shm, filename, addr_base, size, ret_fd );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_ASSERT( filename != NULL );
+ D_ASSERT( addr_base != NULL );
+ D_ASSERT( size >= sizeof(shmalloc_heap) );
+ D_ASSERT( ret_fd != NULL );
+
+ shared = shm->shared;
+
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+ D_ASSERT( shared->tmpfs[0] != 0 );
+
+ D_DEBUG_AT( Fusion_SHMHeap, " -> opening shared memory file '%s'...\n", filename );
+
+ /* open the virtual file */
+ fd = open( filename, O_RDWR );
+ if (fd < 0) {
+ ret = errno2result(errno);
+ D_PERROR( "Fusion/SHM: Could not open shared memory file '%s'!\n", filename );
+ goto error;
+ }
+
+ D_DEBUG_AT( Fusion_SHMHeap, " -> mmaping shared memory file... (%d bytes)\n", size );
+
+ /* map it shared */
+ heap = mmap( addr_base, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, 0 );
+ if (heap == MAP_FAILED) {
+ ret = errno2result(errno);
+ D_PERROR( "Fusion/SHM: Could not mmap shared memory file '%s'!\n", filename );
+ goto error;
+ }
+
+ if (heap != addr_base) {
+ D_ERROR( "Fusion/SHM: mmap() returned address (%p) differs from requested (%p)\n", heap, addr_base );
+ ret = DR_FUSION;
+ goto error;
+ }
+
+ D_MAGIC_ASSERT( heap, shmalloc_heap );
+
+ D_DEBUG_AT( Fusion_SHMHeap, " -> done.\n" );
+
+ *ret_fd = fd;
+
+ return DR_OK;
+
+
+error:
+ if (heap)
+ munmap( heap, size );
+
+ if (fd != -1)
+ close( fd );
+
+ return ret;
+}
+
+void *
+__shmalloc_brk( shmalloc_heap *heap, int increment )
+{
+ FusionSHMShared *shm;
+ FusionWorld *world;
+ FusionSHMPool *pool;
+ FusionSHMPoolShared *shared;
+
+ D_DEBUG_AT( Fusion_SHMHeap, "%s( %p, %d )\n", __FUNCTION__, heap, increment );
+
+ D_MAGIC_ASSERT( heap, shmalloc_heap );
+
+ shared = heap->pool;
+ D_MAGIC_ASSERT( shared, FusionSHMPoolShared );
+
+ shm = shared->shm;
+ D_MAGIC_ASSERT( shm, FusionSHMShared );
+
+ world = _fusion_world( shm->world );
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ pool = &world->shm.pools[shared->index];
+ D_MAGIC_ASSERT( pool, FusionSHMPool );
+
+ if (increment) {
+ int new_size = heap->size + increment;
+
+ if (new_size > shared->max_size) {
+ D_WARN( "maximum shared memory size exceeded!" );
+ fusion_dbg_print_memleaks( shared );
+ return NULL;
+ }
+
+ if (ftruncate( pool->fd, new_size ) < 0) {
+ D_PERROR( "Fusion/SHM: ftruncating shared memory file failed!\n" );
+ return NULL;
+ }
+
+ heap->size = new_size;
+ }
+
+ return shared->addr_base + heap->size - increment;
+}
+
diff --git a/Source/DirectFB/lib/fusion/shm/pool.c b/Source/DirectFB/lib/fusion/shm/pool.c
new file mode 100755
index 0000000..030314f
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shm/pool.c
@@ -0,0 +1,954 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include <direct/debug.h>
+#include <direct/list.h>
+#include <direct/mem.h>
+#include <direct/messages.h>
+
+#include <fusion/shmalloc.h>
+#include <fusion/fusion_internal.h>
+
+#include <fusion/shm/pool.h>
+#include <fusion/shm/shm_internal.h>
+
+
+D_DEBUG_DOMAIN( Fusion_SHMPool, "Fusion/SHMPool", "Fusion Shared Memory Pool" );
+
+/**********************************************************************************************************************/
+
+static DirectResult init_pool ( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared,
+ const char *name,
+ unsigned int max_size,
+ bool debug );
+
+static DirectResult join_pool ( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared );
+
+static void leave_pool ( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared );
+
+static void shutdown_pool( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared );
+
+/**********************************************************************************************************************/
+
+DirectResult
+fusion_shm_pool_create( FusionWorld *world,
+ const char *name,
+ unsigned int max_size,
+ bool debug,
+ FusionSHMPoolShared **ret_pool )
+{
+ int i;
+ DirectResult ret;
+ FusionSHM *shm;
+ FusionSHMShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_MAGIC_ASSERT( world->shared, FusionWorldShared );
+ D_ASSERT( name != NULL );
+ D_ASSERT( max_size > 0 );
+ D_ASSERT( ret_pool != NULL );
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p [%d], '%s', %d, %p, %sdebug )\n", __FUNCTION__,
+ world, world->shared->world_index, name, max_size, ret_pool, debug ? "" : "non-" );
+
+#if !DIRECT_BUILD_DEBUGS
+ debug = false;
+#endif
+
+ shm = &world->shm;
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+
+ shared = shm->shared;
+
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ if (max_size < 8192) {
+ D_ERROR( "Fusion/SHMPool: Maximum size (%d) should be 8192 at least!\n", max_size );
+ return DR_INVARG;
+ }
+
+ ret = fusion_skirmish_prevail( &shared->lock );
+ if (ret)
+ goto error;
+
+ if (shared->num_pools == FUSION_SHM_MAX_POOLS) {
+ D_ERROR( "Fusion/SHMPool: Maximum number of pools (%d) already reached!\n", FUSION_SHM_MAX_POOLS );
+ ret = DR_LIMITEXCEEDED;
+ goto error;
+ }
+
+ for (i=0; i<FUSION_SHM_MAX_POOLS; i++) {
+ if (!shared->pools[i].active)
+ break;
+
+ D_MAGIC_ASSERT( &shared->pools[i], FusionSHMPoolShared );
+ D_MAGIC_ASSUME( &shm->pools[i], FusionSHMPool );
+ }
+
+ D_ASSERT( i < FUSION_SHM_MAX_POOLS );
+
+ D_DEBUG_AT( Fusion_SHMPool, " -> index %d\n", i );
+
+ memset( &shm->pools[i], 0, sizeof(FusionSHMPool) );
+ memset( &shared->pools[i], 0, sizeof(FusionSHMPoolShared) );
+
+ shared->pools[i].index = i;
+
+ ret = init_pool( shm, &shm->pools[i], &shared->pools[i], name, max_size, debug );
+ if (ret)
+ goto error;
+
+ shared->num_pools++;
+
+ fusion_skirmish_dismiss( &shared->lock );
+
+ *ret_pool = &shared->pools[i];
+
+ D_DEBUG_AT( Fusion_SHMPool, " -> %p\n", *ret_pool );
+
+ return DR_OK;
+
+
+error:
+ fusion_skirmish_dismiss( &shared->lock );
+
+ return ret;
+}
+
+DirectResult
+fusion_shm_pool_destroy( FusionWorld *world,
+ FusionSHMPoolShared *pool )
+{
+ DirectResult ret;
+ FusionSHM *shm;
+ FusionSHMShared *shared;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p )\n", __FUNCTION__, world, pool );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ shm = &world->shm;
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+
+ shared = shm->shared;
+
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ D_ASSERT( shared == pool->shm );
+
+ ret = fusion_skirmish_prevail( &shared->lock );
+ if (ret)
+ return ret;
+
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret) {
+ fusion_skirmish_dismiss( &shared->lock );
+ return ret;
+ }
+
+ D_ASSERT( pool->active );
+ D_ASSERT( pool->index >= 0 );
+ D_ASSERT( pool->index < FUSION_SHM_MAX_POOLS );
+ D_ASSERT( pool->pool_id == shm->pools[pool->index].pool_id );
+ D_ASSERT( pool == &shared->pools[pool->index] );
+
+ D_MAGIC_ASSERT( &shm->pools[pool->index], FusionSHMPool );
+
+ shutdown_pool( shm, &shm->pools[pool->index], pool );
+
+ shared->num_pools--;
+
+ fusion_skirmish_dismiss( &shared->lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_attach( FusionSHM *shm,
+ FusionSHMPoolShared *pool )
+{
+ DirectResult ret;
+ FusionSHMShared *shared;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p )\n", __FUNCTION__, shm, pool );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ shared = shm->shared;
+
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ D_ASSERT( shared == pool->shm );
+
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret) {
+ return ret;
+ }
+
+ D_ASSERT( pool->active );
+ D_ASSERT( pool->index >= 0 );
+ D_ASSERT( pool->index < FUSION_SHM_MAX_POOLS );
+ D_ASSERT( pool == &shared->pools[pool->index] );
+ D_ASSERT( !shm->pools[pool->index].attached );
+
+ ret = join_pool( shm, &shm->pools[pool->index], pool );
+
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return ret;
+}
+
+DirectResult
+fusion_shm_pool_detach( FusionSHM *shm,
+ FusionSHMPoolShared *pool )
+{
+ DirectResult ret;
+ FusionSHMShared *shared;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p )\n", __FUNCTION__, shm, pool );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ shared = shm->shared;
+
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ D_ASSERT( shared == pool->shm );
+
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret) {
+ fusion_skirmish_dismiss( &shared->lock );
+ return ret;
+ }
+
+ D_ASSERT( pool->active );
+ D_ASSERT( pool->index >= 0 );
+ D_ASSERT( pool->index < FUSION_SHM_MAX_POOLS );
+ D_ASSERT( pool->pool_id == shm->pools[pool->index].pool_id );
+ D_ASSERT( pool == &shared->pools[pool->index] );
+ D_ASSERT( shm->pools[pool->index].attached );
+
+ D_MAGIC_ASSERT( &shm->pools[pool->index], FusionSHMPool );
+
+ leave_pool( shm, &shm->pools[pool->index], pool );
+
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_allocate( FusionSHMPoolShared *pool,
+ int size,
+ bool clear,
+ bool lock,
+ void **ret_data )
+{
+ DirectResult ret;
+ void *data;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %d, %sclear, %p )\n", __FUNCTION__,
+ pool, size, clear ? "" : "un", ret_data );
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ D_ASSERT( size > 0 );
+ D_ASSERT( ret_data != NULL );
+
+ if (lock) {
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret)
+ return ret;
+ }
+
+ __shmalloc_brk( pool->heap, 0 );
+
+ data = _fusion_shmalloc( pool->heap, size );
+ if (!data) {
+ if (lock)
+ fusion_skirmish_dismiss( &pool->lock );
+ return DR_NOSHAREDMEMORY;
+ }
+
+ if (clear)
+ memset( data, 0, size );
+
+ *ret_data = data;
+
+ if (lock)
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_reallocate( FusionSHMPoolShared *pool,
+ void *data,
+ int size,
+ bool lock,
+ void **ret_data )
+{
+ DirectResult ret;
+ void *new_data;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %d, %p )\n",
+ __FUNCTION__, pool, data, size, ret_data );
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ D_ASSERT( data != NULL );
+ D_ASSERT( data >= pool->addr_base );
+ D_ASSERT( data < pool->addr_base + pool->max_size );
+ D_ASSERT( size > 0 );
+ D_ASSERT( ret_data != NULL );
+
+ if (lock) {
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret)
+ return ret;
+ }
+
+ __shmalloc_brk( pool->heap, 0 );
+
+ new_data = _fusion_shrealloc( pool->heap, data, size );
+ if (!new_data) {
+ if (lock)
+ fusion_skirmish_dismiss( &pool->lock );
+ return DR_NOSHAREDMEMORY;
+ }
+
+ *ret_data = new_data;
+
+ if (lock)
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_pool_deallocate( FusionSHMPoolShared *pool,
+ void *data,
+ bool lock )
+{
+ DirectResult ret;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p )\n", __FUNCTION__, pool, data );
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ D_ASSERT( data != NULL );
+ D_ASSERT( data >= pool->addr_base );
+ D_ASSERT( data < pool->addr_base + pool->max_size );
+
+ if (lock) {
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret)
+ return ret;
+ }
+
+ __shmalloc_brk( pool->heap, 0 );
+
+ _fusion_shfree( pool->heap, data );
+
+ if (lock)
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return DR_OK;
+}
+
+/**********************************************************************************************************************/
+
+#if FUSION_BUILD_KERNEL
+
+static DirectResult
+init_pool( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared,
+ const char *name,
+ unsigned int max_size,
+ bool debug )
+{
+ DirectResult ret;
+ int fd;
+ int size;
+ FusionWorld *world;
+ FusionSHMPoolNew pool_new = { .pool_id = 0 };
+ FusionSHMPoolAttach pool_attach = { .pool_id = 0 };
+ FusionEntryInfo info;
+ char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32];
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p, '%s', %d, %sdebug )\n",
+ __FUNCTION__, shm, pool, shared, name, max_size, debug ? "" : "non-" );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( shm->shared, FusionSHMShared );
+ D_ASSERT( name != NULL );
+ D_ASSERT( max_size > sizeof(shmalloc_heap) );
+
+ world = shm->world;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ D_ASSERT( pool != NULL );
+ D_ASSERT( shared != NULL );
+
+ /* Fill out information for new pool. */
+ pool_new.max_size = max_size;
+
+ pool_new.max_size += BLOCKALIGN(sizeof(shmalloc_heap)) +
+ BLOCKALIGN( (max_size + BLOCKSIZE-1) / BLOCKSIZE * sizeof(shmalloc_info) );
+
+ /* Create the new pool. */
+ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_NEW, &pool_new )) {
+ if (errno == EINTR)
+ continue;
+
+ D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_NEW failed!\n" );
+ return DR_FUSION;
+ }
+
+ /* Set the pool info. */
+ info.type = FT_SHMPOOL;
+ info.id = pool_new.pool_id;
+
+ snprintf( info.name, sizeof(info.name), "%s", name );
+
+ ioctl( world->fusion_fd, FUSION_ENTRY_SET_INFO, &info );
+
+
+ /* Set pool to attach to. */
+ pool_attach.pool_id = pool_new.pool_id;
+
+ /* Attach to the pool. */
+ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_ATTACH, &pool_attach )) {
+ if (errno == EINTR)
+ continue;
+
+ D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_ATTACH failed!\n" );
+
+ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DESTROY, &shared->pool_id )) {
+ if (errno != EINTR) {
+ D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DESTROY failed!\n" );
+ break;
+ }
+ }
+
+ return DR_FUSION;
+ }
+
+
+ /* Generate filename. */
+ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs,
+ fusion_world_index( shm->world ), pool_new.pool_id );
+
+ /* Initialize the heap. */
+ ret = __shmalloc_init_heap( shm, buf, pool_new.addr_base, max_size, &fd, &size );
+ if (ret) {
+ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DESTROY, &shared->pool_id )) {
+ if (errno != EINTR) {
+ D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DESTROY failed!\n" );
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+
+ /* Initialize local data. */
+ pool->attached = true;
+ pool->shm = shm;
+ pool->shared = shared;
+ pool->pool_id = pool_new.pool_id;
+ pool->fd = fd;
+ pool->filename = D_STRDUP( buf );
+
+ /* Initialize shared data. */
+ shared->active = true;
+ shared->debug = debug;
+ shared->shm = shm->shared;
+ shared->max_size = pool_new.max_size;
+ shared->pool_id = pool_new.pool_id;
+ shared->addr_base = pool_new.addr_base;
+ shared->heap = pool_new.addr_base;
+ shared->heap->pool = shared;
+
+ fusion_skirmish_init( &shared->lock, name, world );
+
+
+ D_MAGIC_SET( pool, FusionSHMPool );
+ D_MAGIC_SET( shared, FusionSHMPoolShared );
+
+
+ shared->name = SHSTRDUP( shared, name );
+
+ return DR_OK;
+}
+
+static DirectResult
+join_pool( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared )
+{
+ DirectResult ret;
+ int fd;
+ FusionWorld *world;
+ FusionSHMPoolAttach pool_attach = { .pool_id = 0 };
+ char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32];
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( shm->shared, FusionSHMShared );
+ D_MAGIC_ASSERT( shared, FusionSHMPoolShared );
+
+#if !DIRECT_BUILD_DEBUGS
+ if (shared->debug) {
+ D_ERROR( "Fusion/SHM: Can't join debug enabled pool with pure-release library!\n" );
+ return DR_UNSUPPORTED;
+ }
+#endif
+
+ world = shm->world;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+
+ /* Set pool to attach to. */
+ pool_attach.pool_id = shared->pool_id;
+
+ /* Attach to the pool. */
+ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_ATTACH, &pool_attach )) {
+ if (errno == EINTR)
+ continue;
+
+ D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_ATTACH failed!\n" );
+ return DR_FUSION;
+ }
+
+
+ /* Generate filename. */
+ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs,
+ fusion_world_index( shm->world ), shared->pool_id );
+
+ /* Join the heap. */
+ ret = __shmalloc_join_heap( shm, buf, pool_attach.addr_base, shared->max_size, &fd );
+ if (ret) {
+ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DETACH, &shared->pool_id )) {
+ if (errno != EINTR) {
+ D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DETACH failed!\n" );
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+
+ /* Initialize local data. */
+ pool->attached = true;
+ pool->shm = shm;
+ pool->shared = shared;
+ pool->pool_id = shared->pool_id;
+ pool->fd = fd;
+ pool->filename = D_STRDUP( buf );
+
+
+ D_MAGIC_SET( pool, FusionSHMPool );
+
+ return DR_OK;
+}
+
+static void
+leave_pool( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared )
+{
+ FusionWorld *world;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( pool, FusionSHMPool );
+ D_MAGIC_ASSERT( shared, FusionSHMPoolShared );
+
+ world = shm->world;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DETACH, &shared->pool_id )) {
+ if (errno != EINTR) {
+ D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DETACH failed!\n" );
+ break;
+ }
+ }
+
+ if (munmap( shared->addr_base, shared->max_size ))
+ D_PERROR( "Fusion/SHM: Could not munmap shared memory file '%s'!\n", pool->filename );
+
+ if (pool->fd != -1 && close( pool->fd ))
+ D_PERROR( "Fusion/SHM: Could not close shared memory file '%s'!\n", pool->filename );
+
+ pool->attached = false;
+
+ D_FREE( pool->filename );
+
+ D_MAGIC_CLEAR( pool );
+}
+
+static void
+shutdown_pool( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared )
+{
+ FusionWorld *world;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( pool, FusionSHMPool );
+ D_MAGIC_ASSERT( shared, FusionSHMPoolShared );
+
+ world = shm->world;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ SHFREE( shared, shared->name );
+
+ fusion_dbg_print_memleaks( shared );
+
+ while (ioctl( world->fusion_fd, FUSION_SHMPOOL_DESTROY, &shared->pool_id )) {
+ if (errno != EINTR) {
+ D_PERROR( "Fusion/SHM: FUSION_SHMPOOL_DESTROY failed!\n" );
+ break;
+ }
+ }
+
+ if (munmap( shared->addr_base, shared->max_size ))
+ D_PERROR( "Fusion/SHM: Could not munmap shared memory file '%s'!\n", pool->filename );
+
+ if (pool->fd != -1 && close( pool->fd ))
+ D_PERROR( "Fusion/SHM: Could not close shared memory file '%s'!\n", pool->filename );
+
+ if (unlink( pool->filename ))
+ D_PERROR( "Fusion/SHM: Could not unlink shared memory file '%s'!\n", pool->filename );
+
+ shared->active = false;
+
+ pool->attached = false;
+
+ D_FREE( pool->filename );
+
+ D_MAGIC_CLEAR( pool );
+
+ fusion_skirmish_destroy( &shared->lock );
+
+ D_MAGIC_CLEAR( shared );
+}
+
+#else /* FUSION_BUILD_KERNEL */
+
+static DirectResult
+init_pool( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared,
+ const char *name,
+ unsigned int max_size,
+ bool debug )
+{
+ DirectResult ret;
+ int fd;
+ int size;
+ long page_size;
+ int pool_id;
+ unsigned int pool_max_size;
+ void *pool_addr_base = NULL;
+ FusionWorld *world;
+ char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32];
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p, '%s', %d, %sdebug )\n",
+ __FUNCTION__, shm, pool, shared, name, max_size, debug ? "" : "non-" );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( shm->shared, FusionSHMShared );
+ D_ASSERT( name != NULL );
+ D_ASSERT( max_size > sizeof(shmalloc_heap) );
+
+ world = shm->world;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ D_ASSERT( pool != NULL );
+ D_ASSERT( shared != NULL );
+
+ page_size = direct_pagesize();
+
+ pool_id = ++world->shared->pool_ids;
+
+ pool_max_size = max_size + BLOCKALIGN(sizeof(shmalloc_heap)) +
+ BLOCKALIGN( (max_size + BLOCKSIZE-1) / BLOCKSIZE * sizeof(shmalloc_info) );
+
+ pool_addr_base = world->shared->pool_base;
+ world->shared->pool_base += ((pool_max_size + page_size - 1) & ~(page_size - 1)) + page_size;
+ /* Exceeded limit? */
+ if (world->shared->pool_base > world->shared->pool_max)
+ return DR_NOSHAREDMEMORY;
+
+ /* Generate filename. */
+ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs,
+ fusion_world_index( world ), pool_id );
+
+ /* Initialize the heap. */
+ ret = __shmalloc_init_heap( shm, buf, pool_addr_base, max_size, &fd, &size );
+ if (ret)
+ return ret;
+
+ /* Initialize local data. */
+ pool->attached = true;
+ pool->shm = shm;
+ pool->shared = shared;
+ pool->pool_id = pool_id;
+ pool->fd = fd;
+ pool->filename = D_STRDUP( buf );
+
+ /* Initialize shared data. */
+ shared->active = true;
+ shared->debug = debug;
+ shared->shm = shm->shared;
+ shared->max_size = pool_max_size;
+ shared->pool_id = pool_id;
+ shared->addr_base = pool_addr_base;
+ shared->heap = pool_addr_base;
+ shared->heap->pool = shared;
+
+ fusion_skirmish_init( &shared->lock, name, world );
+
+
+ D_MAGIC_SET( pool, FusionSHMPool );
+ D_MAGIC_SET( shared, FusionSHMPoolShared );
+
+
+ shared->name = SHSTRDUP( shared, name );
+
+ return DR_OK;
+}
+
+static DirectResult
+join_pool( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared )
+{
+ DirectResult ret;
+ int fd;
+ FusionWorld *world;
+ char buf[FUSION_SHM_TMPFS_PATH_NAME_LEN + 32];
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( shm->shared, FusionSHMShared );
+ D_MAGIC_ASSERT( shared, FusionSHMPoolShared );
+
+#if !DIRECT_BUILD_DEBUGS
+ if (shared->debug) {
+ D_ERROR( "Fusion/SHM: Can't join debug enabled pool with pure-release library!\n" );
+ return DR_UNSUPPORTED;
+ }
+#endif
+
+ world = shm->world;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ /* Generate filename. */
+ snprintf( buf, sizeof(buf), "%s/fusion.%d.%d", shm->shared->tmpfs,
+ fusion_world_index( shm->world ), shared->pool_id );
+
+ /* Join the heap. */
+ ret = __shmalloc_join_heap( shm, buf, shared->addr_base, shared->max_size, &fd );
+ if (ret)
+ return ret;
+
+ /* Initialize local data. */
+ pool->attached = true;
+ pool->shm = shm;
+ pool->shared = shared;
+ pool->pool_id = shared->pool_id;
+ pool->fd = fd;
+ pool->filename = D_STRDUP( buf );
+
+
+ D_MAGIC_SET( pool, FusionSHMPool );
+
+ return DR_OK;
+}
+
+static void
+leave_pool( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared )
+{
+ FusionWorld *world;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( pool, FusionSHMPool );
+ D_MAGIC_ASSERT( shared, FusionSHMPoolShared );
+
+ world = shm->world;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ if (munmap( shared->addr_base, shared->max_size ))
+ D_PERROR( "Fusion/SHM: Could not munmap shared memory file '%s'!\n", pool->filename );
+
+ if (pool->fd != -1 && close( pool->fd ))
+ D_PERROR( "Fusion/SHM: Could not close shared memory file '%s'!\n", pool->filename );
+
+ pool->attached = false;
+
+ D_FREE( pool->filename );
+
+ D_MAGIC_CLEAR( pool );
+}
+
+static void
+shutdown_pool( FusionSHM *shm,
+ FusionSHMPool *pool,
+ FusionSHMPoolShared *shared )
+{
+ FusionWorld *world;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %p, %p )\n", __FUNCTION__, shm, pool, shared );
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( pool, FusionSHMPool );
+ D_MAGIC_ASSERT( shared, FusionSHMPoolShared );
+
+ world = shm->world;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ SHFREE( shared, shared->name );
+
+ fusion_dbg_print_memleaks( shared );
+
+ if (munmap( shared->addr_base, shared->max_size ))
+ D_PERROR( "Fusion/SHM: Could not munmap shared memory file '%s'!\n", pool->filename );
+
+ if (pool->fd != -1 && close( pool->fd ))
+ D_PERROR( "Fusion/SHM: Could not close shared memory file '%s'!\n", pool->filename );
+
+ if (unlink( pool->filename ))
+ D_PERROR( "Fusion/SHM: Could not unlink shared memory file '%s'!\n", pool->filename );
+
+ shared->active = false;
+
+ pool->attached = false;
+
+ D_FREE( pool->filename );
+
+ D_MAGIC_CLEAR( pool );
+
+ fusion_skirmish_destroy( &shared->lock );
+
+ D_MAGIC_CLEAR( shared );
+}
+
+#endif /* FUSION_BUILD_KERNEL */
+
+/**********************************************************************************************************************/
+
+#if FUSION_BUILD_KERNEL
+void
+_fusion_shmpool_process( FusionWorld *world,
+ int pool_id,
+ FusionSHMPoolMessage *msg )
+{
+ int i;
+ DirectResult ret;
+ FusionSHM *shm;
+ FusionSHMShared *shared;
+
+ D_DEBUG_AT( Fusion_SHMPool, "%s( %p, %d, %p )\n", __FUNCTION__, world, pool_id, msg );
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shm = &world->shm;
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+
+ shared = shm->shared;
+
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ ret = fusion_skirmish_prevail( &shared->lock );
+ if (ret)
+ return;
+
+ for (i=0; i<FUSION_SHM_MAX_POOLS; i++) {
+ if (shm->pools[i].attached) {
+ D_MAGIC_ASSERT( &shm->pools[i], FusionSHMPool );
+
+ if (shm->pools[i].pool_id == pool_id) {
+ switch (msg->type) {
+ case FSMT_REMAP:
+ break;
+
+ case FSMT_UNMAP:
+ D_UNIMPLEMENTED();
+ break;
+ }
+
+ break;
+ }
+ }
+ }
+
+ fusion_skirmish_dismiss( &shared->lock );
+}
+#endif /* FUSION_BUILD_KERNEL */
diff --git a/Source/DirectFB/lib/fusion/shm/pool.h b/Source/DirectFB/lib/fusion/shm/pool.h
new file mode 100755
index 0000000..b809a5a
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shm/pool.h
@@ -0,0 +1,69 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__SHM__POOL_H__
+#define __FUSION__SHM__POOL_H__
+
+#include <fusion/types.h>
+
+
+DirectResult fusion_shm_pool_create ( FusionWorld *world,
+ const char *name,
+ unsigned int max_size,
+ bool debug,
+ FusionSHMPoolShared **ret_pool );
+
+DirectResult fusion_shm_pool_destroy ( FusionWorld *world,
+ FusionSHMPoolShared *pool );
+
+
+DirectResult fusion_shm_pool_attach ( FusionSHM *shm,
+ FusionSHMPoolShared *pool );
+
+DirectResult fusion_shm_pool_detach ( FusionSHM *shm,
+ FusionSHMPoolShared *pool );
+
+
+DirectResult fusion_shm_pool_allocate ( FusionSHMPoolShared *pool,
+ int size,
+ bool clear,
+ bool lock,
+ void **ret_data );
+
+DirectResult fusion_shm_pool_reallocate( FusionSHMPoolShared *pool,
+ void *data,
+ int size,
+ bool lock,
+ void **ret_data );
+
+DirectResult fusion_shm_pool_deallocate( FusionSHMPoolShared *pool,
+ void *data,
+ bool lock );
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/shm/shm.c b/Source/DirectFB/lib/fusion/shm/shm.c
new file mode 100755
index 0000000..21c7f42
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shm/shm.c
@@ -0,0 +1,337 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+
+#include <direct/debug.h>
+#include <direct/list.h>
+#include <direct/signals.h>
+#include <direct/messages.h>
+#include <direct/util.h>
+
+#include <fusion/conf.h>
+#include <fusion/fusion_internal.h>
+
+#include <fusion/shm/pool.h>
+#include <fusion/shm/shm.h>
+#include <fusion/shm/shm_internal.h>
+
+
+/**********************************************************************************************************************/
+
+static int
+find_tmpfs( char *name, int len )
+{
+ int largest = 0;
+ char buffer[1024];
+ FILE *mounts_handle;
+
+ mounts_handle = fopen( "/proc/mounts", "r" );
+ if (!mounts_handle)
+ return 0;
+
+ while (fgets( buffer, sizeof(buffer), mounts_handle )) {
+ char *mount_point;
+ char *mount_fs;
+ char *pointer = buffer;
+
+ strsep( &pointer, " " );
+
+ mount_point = strsep( &pointer, " " );
+ mount_fs = strsep( &pointer, " " );
+
+ if (mount_fs && mount_point && !access( mount_point, W_OK ) &&
+ (!strcmp( mount_fs, "tmpfs" ) || !strcmp( mount_fs, "shmfs" ) || !strcmp( mount_fs, "ramfs" )))
+ {
+ struct statfs stat;
+ int bytes;
+
+ if (statfs( mount_point, &stat )) {
+ D_PERROR( "Fusion/SHM: statfs on '%s' failed!\n", mount_point );
+ continue;
+ }
+
+ bytes = stat.f_blocks * stat.f_bsize;
+
+ if (bytes > largest || (bytes == largest && !strcmp(mount_point,"/dev/shm"))) {
+ largest = bytes;
+
+ direct_snputs( name, mount_point, len );
+ }
+ }
+ }
+
+ fclose( mounts_handle );
+
+ return largest;
+}
+
+/**********************************************************************************************************************/
+
+DirectResult
+fusion_shm_init( FusionWorld *world )
+{
+ int i;
+ int num;
+ DirectResult ret;
+ FusionSHM *shm;
+ FusionSHMShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_MAGIC_ASSERT( world->shared, FusionWorldShared );
+
+ shm = &world->shm;
+ shared = &world->shared->shm;
+
+ /* Initialize local data. */
+ memset( shm, 0, sizeof(FusionSHM) );
+
+ shm->world = world;
+ shm->shared = shared;
+
+ /* Initialize shared data. */
+ if (fusion_master( world )) {
+ memset( shared, 0, sizeof(FusionSHMShared) );
+
+ if (fusion_config->tmpfs) {
+ snprintf( shared->tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN, fusion_config->tmpfs );
+ }
+ else if (!find_tmpfs( shared->tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN )) {
+ D_ERROR( "Fusion/SHM: Could not find tmpfs mount point, falling back to /dev/shm!\n" );
+ snprintf( shared->tmpfs, FUSION_SHM_TMPFS_PATH_NAME_LEN, "/dev/shm" );
+ }
+
+ shared->world = world->shared;
+
+ /* Initialize shared lock. */
+ ret = fusion_skirmish_init( &shared->lock, "Fusion SHM", world );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Failed to create skirmish!\n" );
+ return ret;
+ }
+
+ /* Initialize static pool array. */
+ for (i=0; i<FUSION_SHM_MAX_POOLS; i++)
+ shared->pools[i].index = i;
+
+ D_MAGIC_SET( shm, FusionSHM );
+ D_MAGIC_SET( shared, FusionSHMShared );
+ }
+ else {
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ ret = fusion_skirmish_prevail( &shared->lock );
+ if (ret)
+ return ret;
+
+ D_MAGIC_SET( shm, FusionSHM );
+
+ for (i=0, num=0; i<FUSION_SHM_MAX_POOLS; i++) {
+ if (shared->pools[i].active) {
+ D_MAGIC_ASSERT( &shared->pools[i], FusionSHMPoolShared );
+
+ ret = fusion_shm_pool_attach( shm, &shared->pools[i] );
+ if (ret) {
+ for (--i; i>=0; i--) {
+ if (shared->pools[i].active)
+ fusion_shm_pool_detach( shm, &shared->pools[i] );
+ }
+
+ fusion_skirmish_dismiss( &shared->lock );
+
+ D_MAGIC_CLEAR( shm );
+
+ return ret;
+ }
+
+ num++;
+ }
+ }
+
+ D_ASSERT( num == shared->num_pools );
+
+ fusion_skirmish_dismiss( &shared->lock );
+ }
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_deinit( FusionWorld *world )
+{
+ int i;
+ DirectResult ret;
+ FusionSHM *shm;
+ FusionSHMShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+
+ shm = &world->shm;
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+
+ shared = shm->shared;
+
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ ret = fusion_skirmish_prevail( &shared->lock );
+ if (ret)
+ return ret;
+
+ /* Deinitialize shared data. */
+ if (fusion_master( world )) {
+ D_ASSUME( shared->num_pools == 0 );
+
+ for (i=0; i<FUSION_SHM_MAX_POOLS; i++) {
+ if (shared->pools[i].active) {
+ D_MAGIC_ASSERT( &shared->pools[i], FusionSHMPoolShared );
+ D_MAGIC_ASSERT( &shm->pools[i], FusionSHMPool );
+
+ D_WARN( "destroying remaining '%s'", shared->pools[i].name );
+
+ fusion_shm_pool_destroy( world, &shared->pools[i] );
+ }
+ }
+
+ /* Destroy shared lock. */
+ fusion_skirmish_destroy( &shared->lock );
+
+ D_MAGIC_CLEAR( shared );
+ }
+ else {
+ for (i=0; i<FUSION_SHM_MAX_POOLS; i++) {
+ if (shared->pools[i].active) {
+ D_MAGIC_ASSERT( &shared->pools[i], FusionSHMPoolShared );
+ D_MAGIC_ASSERT( &shm->pools[i], FusionSHMPool );
+
+ fusion_shm_pool_detach( shm, &shared->pools[i] );
+ }
+ }
+
+ fusion_skirmish_dismiss( &shared->lock );
+ }
+
+ D_MAGIC_CLEAR( shm );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_attach_unattached( FusionWorld *world )
+{
+ int i;
+ DirectResult ret;
+ FusionSHM *shm;
+ FusionSHMShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_MAGIC_ASSERT( world->shared, FusionWorldShared );
+
+ shm = &world->shm;
+ shared = &world->shared->shm;
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ ret = fusion_skirmish_prevail( &shared->lock );
+ if (ret)
+ return ret;
+
+ for (i=0; i<FUSION_SHM_MAX_POOLS; i++) {
+ if (!shared->pools[i].active)
+ continue;
+
+ D_MAGIC_ASSERT( &shared->pools[i], FusionSHMPoolShared );
+
+ if (!shm->pools[i].attached) {
+ ret = fusion_shm_pool_attach( shm, &shared->pools[i] );
+ if (ret)
+ D_DERROR( ret, "fusion_shm_pool_attach( '%s' ) failed!\n", shared->pools[i].name );
+ }
+ else
+ D_MAGIC_ASSERT( &shm->pools[i], FusionSHMPool );
+ }
+
+ fusion_skirmish_dismiss( &shared->lock );
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_shm_enum_pools( FusionWorld *world,
+ FusionSHMPoolCallback callback,
+ void *ctx )
+{
+ int i;
+ DirectResult ret;
+ FusionSHM *shm;
+ FusionSHMShared *shared;
+
+ D_MAGIC_ASSERT( world, FusionWorld );
+ D_MAGIC_ASSERT( world->shared, FusionWorldShared );
+ D_ASSERT( callback != NULL );
+
+ shm = &world->shm;
+ shared = &world->shared->shm;
+
+ D_MAGIC_ASSERT( shm, FusionSHM );
+ D_MAGIC_ASSERT( shared, FusionSHMShared );
+
+ ret = fusion_skirmish_prevail( &shared->lock );
+ if (ret)
+ return ret;
+
+ for (i=0; i<FUSION_SHM_MAX_POOLS; i++) {
+ if (!shared->pools[i].active)
+ continue;
+
+ if (!shm->pools[i].attached) {
+ D_BUG( "not attached to pool" );
+ continue;
+ }
+
+ D_MAGIC_ASSERT( &shm->pools[i], FusionSHMPool );
+ D_MAGIC_ASSERT( &shared->pools[i], FusionSHMPoolShared );
+
+ if (callback( &shm->pools[i], ctx ) == DENUM_CANCEL)
+ break;
+ }
+
+ fusion_skirmish_dismiss( &shared->lock );
+
+ return DR_OK;
+}
+
diff --git a/Source/DirectFB/lib/fusion/shm/shm.h b/Source/DirectFB/lib/fusion/shm/shm.h
new file mode 100755
index 0000000..6764d17
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shm/shm.h
@@ -0,0 +1,48 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__SHM__SHM_H__
+#define __FUSION__SHM__SHM_H__
+
+#include <fusion/types.h>
+
+typedef DirectEnumerationResult (*FusionSHMPoolCallback)( FusionSHMPool *pool,
+ void *ctx );
+
+DirectResult fusion_shm_init ( FusionWorld *world );
+
+DirectResult fusion_shm_deinit( FusionWorld *world );
+
+DirectResult fusion_shm_attach_unattached( FusionWorld *world );
+
+DirectResult fusion_shm_enum_pools( FusionWorld *world,
+ FusionSHMPoolCallback callback,
+ void *ctx );
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/shm/shm_internal.h b/Source/DirectFB/lib/fusion/shm/shm_internal.h
new file mode 100755
index 0000000..3e282a5
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shm/shm_internal.h
@@ -0,0 +1,264 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__SHM__SHM_INTERNAL_H__
+#define __FUSION__SHM__SHM_INTERNAL_H__
+
+#include <limits.h>
+
+#include <direct/list.h>
+
+#include <fusion/build.h>
+#include <fusion/lock.h>
+
+
+#define FUSION_SHM_MAX_POOLS 24
+#define FUSION_SHM_TMPFS_PATH_NAME_LEN 64
+
+
+typedef struct __shmalloc_heap shmalloc_heap;
+
+
+/*
+ * Local pool data.
+ */
+struct __Fusion_FusionSHMPool {
+ int magic;
+
+ bool attached; /* Indicates usage of this entry in the static pool array. */
+
+ FusionSHM *shm; /* Back pointer to local SHM data. */
+
+ FusionSHMPoolShared *shared; /* Pointer to shared pool data. */
+
+ int pool_id; /* The pool's ID within the world. */
+
+ int fd; /* File descriptor of shared memory file. */
+ char *filename; /* Name of the shared memory file. */
+};
+
+/*
+ * Shared pool data.
+ */
+struct __Fusion_FusionSHMPoolShared {
+ int magic;
+
+ bool debug; /* Debug allocations in this pool? */
+
+ int index; /* Index within the static pool array. */
+ bool active; /* Indicates usage of this entry in the static pool array. */
+
+ FusionSHMShared *shm; /* Back pointer to shared SHM data. */
+
+ int max_size; /* Maximum possible size of the shared memory. */
+ int pool_id; /* The pool's ID within the world. */
+ void *addr_base; /* Virtual starting address of shared memory. */
+
+ FusionSkirmish lock; /* Lock for this pool. */
+
+ shmalloc_heap *heap; /* The actual heap information ported from libc5. */
+
+ char *name; /* Name of the pool (allocated in the pool). */
+
+ DirectLink *allocs; /* Used for debugging. */
+};
+
+
+/*
+ * Local SHM data.
+ */
+struct __Fusion_FusionSHM {
+ int magic;
+
+ FusionWorld *world; /* Back pointer to local world data. */
+
+ FusionSHMShared *shared; /* Pointer to shared SHM data. */
+
+ FusionSHMPool pools[FUSION_SHM_MAX_POOLS]; /* Local data of all pools. */
+
+ DirectSignalHandler *signal_handler;
+};
+
+/*
+ * Shared SHM data.
+ */
+struct __Fusion_FusionSHMShared {
+ int magic;
+
+ FusionWorldShared *world; /* Back pointer to shared world data. */
+
+ FusionSkirmish lock; /* Lock for list of pools. */
+
+ int num_pools; /* Number of active pools. */
+ FusionSHMPoolShared pools[FUSION_SHM_MAX_POOLS]; /* Shared data of all pools. */
+
+ char tmpfs[FUSION_SHM_TMPFS_PATH_NAME_LEN];
+};
+
+
+
+/* The allocator divides the heap into blocks of fixed size; large
+ requests receive one or more whole blocks, and small requests
+ receive a fragment of a block. Fragment sizes are powers of two,
+ and all fragments of a block are the same size. When all the
+ fragments in a block have been freed, the block itself is freed. */
+#define INT_BIT (CHAR_BIT * sizeof(int))
+#define BLOCKLOG (INT_BIT > 16 ? 12 : 9)
+#define BLOCKSIZE (1 << BLOCKLOG)
+#define BLOCKIFY(SIZE) (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
+#define BLOCKALIGN(SIZE) (((SIZE) + BLOCKSIZE - 1) & ~(BLOCKSIZE - 1))
+
+/* Number of contiguous free blocks allowed to build up at the end of
+ memory before they will be returned to the system. */
+#define FINAL_FREE_BLOCKS 8
+
+/* Address to block number and vice versa. */
+#define BLOCK(A) (((char *) (A) - heap->heapbase) / BLOCKSIZE + 1)
+#define ADDRESS(B) ((void *) (((B) - 1) * BLOCKSIZE + heap->heapbase))
+
+
+/* Data structure giving per-block information. */
+typedef union {
+
+ /* Heap information for a busy block. */
+ struct {
+
+ /* Zero for a large block, or positive giving the
+ logarithm to the base two of the fragment size. */
+ int type;
+
+ union {
+ struct {
+ size_t nfree; /* Free fragments in a fragmented block. */
+ size_t first; /* First free fragment of the block. */
+ } frag;
+
+ /* Size (in blocks) of a large cluster. */
+ size_t size;
+ } info;
+ } busy;
+
+ /* Heap information for a free block
+ (that may be the first of a free cluster). */
+ struct {
+ size_t size; /* Size (in blocks) of a free cluster. */
+ size_t next; /* Index of next free cluster. */
+ size_t prev; /* Index of previous free cluster. */
+ } free;
+} shmalloc_info;
+
+/* Doubly linked lists of free fragments. */
+struct list {
+ struct list *next;
+ struct list *prev;
+};
+
+
+#define SHMEMDESC_FUNC_NAME_LENGTH 48
+#define SHMEMDESC_FILE_NAME_LENGTH 24
+
+/* Used for debugging. */
+typedef struct {
+ DirectLink link;
+
+ const void *mem;
+ size_t bytes;
+ char func[SHMEMDESC_FUNC_NAME_LENGTH];
+ char file[SHMEMDESC_FILE_NAME_LENGTH];
+ unsigned int line;
+
+ FusionID fid;
+} SHMemDesc;
+
+
+struct __shmalloc_heap {
+ int magic;
+
+ /* Pointer to first block of the heap. */
+ char *heapbase;
+
+ /* Block information table indexed by block number giving per-block information. */
+ shmalloc_info *heapinfo;
+
+ /* Number of info entries. */
+ size_t heapsize;
+
+ /* Current search index for the heap table. */
+ size_t heapindex;
+
+ /* Limit of valid info table indices. */
+ size_t heaplimit;
+
+#if 1 /* Adapted from Mike */
+ /* Count of large blocks allocated for each fragment size. */
+ int fragblocks[BLOCKLOG];
+#endif
+
+ /* Free list headers for each fragment size. */
+ struct list fraghead[BLOCKLOG];
+
+ /* Instrumentation. */
+ size_t chunks_used;
+ size_t bytes_used;
+ size_t chunks_free;
+ size_t bytes_free;
+
+ /* Total size of heap in bytes. */
+ int size;
+
+ /* Back pointer to shared memory pool. */
+ FusionSHMPoolShared *pool;
+};
+
+
+void *_fusion_shmalloc (shmalloc_heap *heap, size_t __size);
+
+void *_fusion_shrealloc (shmalloc_heap *heap, void *__ptr, size_t __size);
+
+void _fusion_shfree (shmalloc_heap *heap, void *__ptr);
+
+
+DirectResult __shmalloc_init_heap( FusionSHM *shm,
+ const char *filename,
+ void *addr_base,
+ int space,
+ int *ret_fd,
+ int *ret_size );
+
+DirectResult __shmalloc_join_heap( FusionSHM *shm,
+ const char *filename,
+ void *addr_base,
+ int size,
+ int *ret_fd );
+
+void *__shmalloc_brk ( shmalloc_heap *heap,
+ int increment );
+
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/shmalloc.c b/Source/DirectFB/lib/fusion/shmalloc.c
new file mode 100755
index 0000000..5fd3408
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shmalloc.c
@@ -0,0 +1,679 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <direct/build.h>
+#include <direct/debug.h>
+#include <direct/memcpy.h>
+#include <direct/messages.h>
+
+#include <fusion/build.h>
+#include <fusion/shmalloc.h>
+
+#include <fusion/fusion_internal.h>
+#include <fusion/shm/shm_internal.h>
+
+
+#if FUSION_BUILD_MULTI
+
+/*************************** MULTI APPLICATION CORE ***************************/
+
+#if DIRECT_BUILD_DEBUGS /* Build with debug support? */
+
+D_DEBUG_DOMAIN( Fusion_SHM, "Fusion/SHM", "Fusion Shared Memory" );
+
+void
+fusion_dbg_print_memleaks( FusionSHMPoolShared *pool )
+{
+ DirectResult ret;
+ SHMemDesc *desc;
+ unsigned int total = 0;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" );
+ return;
+ }
+
+ if (pool->allocs) {
+ direct_log_printf( NULL, "\nShared memory allocations remaining (%d) in '%s': \n",
+ direct_list_count_elements_EXPENSIVE( pool->allocs ), pool->name );
+
+ direct_list_foreach (desc, pool->allocs) {
+ direct_log_printf( NULL, " %9zu bytes at %p [%8lu] in %-30s [%3lx] (%s: %u)\n",
+ desc->bytes, desc->mem, (ulong)desc->mem - (ulong)pool->heap,
+ desc->func, desc->fid, desc->file, desc->line );
+
+ total += desc->bytes;
+ }
+
+ direct_log_printf( NULL, " -------\n %7dk total\n", total >> 10 );
+ direct_log_printf( NULL, "\nShared memory file size: %dk\n", pool->heap->size >> 10 );
+ }
+
+ fusion_skirmish_dismiss( &pool->lock );
+}
+
+static SHMemDesc *
+fill_shmem_desc( SHMemDesc *desc, int bytes, const char *func, const char *file, int line, FusionID fusion_id )
+{
+ D_ASSERT( desc != NULL );
+
+ desc->mem = desc + 1;
+ desc->bytes = bytes;
+
+ snprintf( desc->func, SHMEMDESC_FUNC_NAME_LENGTH, func );
+ snprintf( desc->file, SHMEMDESC_FILE_NAME_LENGTH, file );
+
+ desc->line = line;
+ desc->fid = fusion_id;
+
+ return desc;
+}
+
+/* Allocate SIZE bytes of memory. */
+void *
+fusion_dbg_shmalloc( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, size_t __size )
+{
+ DirectResult ret;
+ SHMemDesc *desc;
+ void *data = NULL;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( file != NULL );
+ D_ASSERT( line > 0 );
+ D_ASSERT( func != NULL );
+ D_ASSERT( __size > 0 );
+
+ if (!pool->debug)
+ return fusion_shmalloc( pool, __size );
+
+ /* Lock the pool. */
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" );
+ return NULL;
+ }
+
+ /* Allocate memory from the pool. */
+ ret = fusion_shm_pool_allocate( pool, __size + sizeof(SHMemDesc), false, false, &data );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not allocate %zu bytes from pool!\n", __size + sizeof(SHMemDesc) );
+ fusion_skirmish_dismiss( &pool->lock );
+ return NULL;
+ }
+
+ /* Fill description. */
+ desc = fill_shmem_desc( data, __size, func, file, line, _fusion_id(pool->shm->world) );
+
+ D_DEBUG_AT( Fusion_SHM, "allocating %9zu bytes at %p [%8lu] in %-30s [%3lx] (%s: %u)\n",
+ desc->bytes, desc->mem, (ulong)desc->mem - (ulong)pool->heap,
+ desc->func, desc->fid, desc->file, desc->line );
+
+ /* Add description to list. */
+ direct_list_append( &pool->allocs, &desc->link );
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return data + sizeof(SHMemDesc);
+}
+
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
+void *
+fusion_dbg_shcalloc( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, size_t __nmemb, size_t __size)
+{
+ DirectResult ret;
+ SHMemDesc *desc;
+ void *data = NULL;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( file != NULL );
+ D_ASSERT( line > 0 );
+ D_ASSERT( func != NULL );
+ D_ASSERT( __nmemb > 0 );
+ D_ASSERT( __size > 0 );
+
+ if (!pool->debug)
+ return fusion_shcalloc( pool, __nmemb, __size );
+
+ /* Lock the pool. */
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" );
+ return NULL;
+ }
+
+ /* Allocate memory from the pool. */
+ ret = fusion_shm_pool_allocate( pool, __nmemb * __size + sizeof(SHMemDesc), true, false, &data );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not allocate %zu bytes from pool!\n", __nmemb * __size + sizeof(SHMemDesc) );
+ fusion_skirmish_dismiss( &pool->lock );
+ return NULL;
+ }
+
+ /* Fill description. */
+ desc = fill_shmem_desc( data, __nmemb * __size, func, file, line, _fusion_id(pool->shm->world) );
+
+ D_DEBUG_AT( Fusion_SHM, "allocating %9zu bytes at %p [%8lu] in %-30s [%3lx] (%s: %u)\n",
+ desc->bytes, desc->mem, (ulong)desc->mem - (ulong)pool->heap,
+ desc->func, desc->fid, desc->file, desc->line );
+
+ /* Add description to list. */
+ direct_list_append( &pool->allocs, &desc->link );
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return data + sizeof(SHMemDesc);
+}
+
+/* Re-allocate the previously allocated block
+ in __ptr, making the new block SIZE bytes long. */
+void *
+fusion_dbg_shrealloc( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, const char *what, void *__ptr,
+ size_t __size )
+{
+ DirectResult ret;
+ SHMemDesc *desc;
+ void *data = NULL;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( file != NULL );
+ D_ASSERT( line > 0 );
+ D_ASSERT( func != NULL );
+ D_ASSERT( what != NULL );
+
+ if (!pool->debug)
+ return fusion_shrealloc( pool, __ptr, __size );
+
+ if (!__ptr)
+ return fusion_dbg_shmalloc( pool, file, line, func, __size );
+
+ if (!__size) {
+ fusion_dbg_shfree( pool, file, line, func, what, __ptr );
+ return NULL;
+ }
+
+ /* Lock the pool. */
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" );
+ return NULL;
+ }
+
+ /* Lookup the corresponding description. */
+ direct_list_foreach (desc, pool->allocs) {
+ if (desc->mem == __ptr)
+ break;
+ }
+
+ if (!desc) {
+ D_ERROR( "Fusion/SHM: Cannot reallocate unknown chunk at %p (%s) from [%s:%d in %s()]!\n",
+ __ptr, what, file, line, func );
+ D_BREAK( "unknown chunk" );
+ return NULL; /* shouldn't happen due to the break */
+ }
+
+ /* Remove the description in case the block moves. */
+ direct_list_remove( &pool->allocs, &desc->link );
+
+ /* Reallocate the memory block. */
+ ret = fusion_shm_pool_reallocate( pool, __ptr - sizeof(SHMemDesc), __size + sizeof(SHMemDesc), false, &data );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not reallocate from %zu to %zu bytes!\n",
+ desc->bytes + sizeof(SHMemDesc), __size + sizeof(SHMemDesc) );
+ fusion_skirmish_dismiss( &pool->lock );
+ return NULL;
+ }
+
+ /* Fill description. */
+ desc = fill_shmem_desc( data, __size, func, file, line, _fusion_id(pool->shm->world) );
+
+ D_DEBUG_AT( Fusion_SHM, "reallocating %9zu bytes at %p [%8lu] in %-30s [%3lx] (%s: %u) '%s'\n",
+ desc->bytes, desc->mem, (ulong)desc->mem - (ulong)pool->heap,
+ desc->func, desc->fid, desc->file, desc->line, what );
+
+ /* Add description to list. */
+ direct_list_append( &pool->allocs, &desc->link );
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+
+ return data + sizeof(SHMemDesc);
+}
+
+/* Free a block allocated by `shmalloc', `shrealloc' or `shcalloc'. */
+void
+fusion_dbg_shfree( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, const char *what, void *__ptr )
+{
+ DirectResult ret;
+ SHMemDesc *desc;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( file != NULL );
+ D_ASSERT( line > 0 );
+ D_ASSERT( func != NULL );
+ D_ASSERT( what != NULL );
+ D_ASSERT( __ptr != NULL );
+
+ if (!pool->debug)
+ return fusion_shfree( pool, __ptr );
+
+ /* Lock the pool. */
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" );
+ return;
+ }
+
+ /* Lookup the corresponding description. */
+ direct_list_foreach (desc, pool->allocs) {
+ if (desc->mem == __ptr)
+ break;
+ }
+
+ if (!desc) {
+ D_ERROR( "Fusion/SHM: Cannot free unknown chunk at %p (%s) from [%s:%d in %s()]!\n",
+ __ptr, what, file, line, func );
+ D_BREAK( "unknown chunk" );
+ return; /* shouldn't happen due to the break */
+ }
+
+ D_DEBUG_AT( Fusion_SHM, "freeing %9zu bytes at %p [%8lu] in %-30s [%3lx] (%s: %u) '%s'\n",
+ desc->bytes, desc->mem, (ulong)desc->mem - (ulong)pool->heap,
+ desc->func, desc->fid, desc->file, desc->line, what );
+
+ /* Remove the description. */
+ direct_list_remove( &pool->allocs, &desc->link );
+
+ /* Free the memory block. */
+ fusion_shm_pool_deallocate( pool, __ptr - sizeof(SHMemDesc), false );
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+}
+
+/* Duplicate string in shared memory. */
+char *
+fusion_dbg_shstrdup( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, const char *string )
+{
+ DirectResult ret;
+ SHMemDesc *desc;
+ void *data = NULL;
+ int length;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( file != NULL );
+ D_ASSERT( line > 0 );
+ D_ASSERT( func != NULL );
+ D_ASSERT( string != NULL );
+
+ if (!pool->debug)
+ return fusion_shstrdup( pool, string );
+
+ length = strlen( string ) + 1;
+
+ /* Lock the pool. */
+ ret = fusion_skirmish_prevail( &pool->lock );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not lock shared memory pool!\n" );
+ return NULL;
+ }
+
+ /* Allocate memory from the pool. */
+ ret = fusion_shm_pool_allocate( pool, length + sizeof(SHMemDesc), false, false, &data );
+ if (ret) {
+ D_DERROR( ret, "Fusion/SHM: Could not allocate %zu bytes from pool!\n", length + sizeof(SHMemDesc) );
+ fusion_skirmish_dismiss( &pool->lock );
+ return NULL;
+ }
+
+ /* Fill description. */
+ desc = fill_shmem_desc( data, length, func, file, line, _fusion_id(pool->shm->world) );
+
+ D_DEBUG_AT( Fusion_SHM, "allocating %9zu bytes at %p [%8lu] in %-30s [%3lx] (%s: %u) <- \"%s\"\n",
+ desc->bytes, desc->mem, (ulong)desc->mem - (ulong)pool->heap,
+ desc->func, desc->fid, desc->file, desc->line, string );
+
+ D_DEBUG_AT( Fusion_SHM, " -> allocs: %p\n", pool->allocs );
+
+ /* Add description to list. */
+ direct_list_append( &pool->allocs, &desc->link );
+
+ /* Unlock the pool. */
+ fusion_skirmish_dismiss( &pool->lock );
+
+ /* Copy string content. */
+ direct_memcpy( data + sizeof(SHMemDesc), string, length );
+
+ return data + sizeof(SHMemDesc);
+}
+
+#else
+
+void
+fusion_dbg_print_memleaks( FusionSHMPoolShared *pool )
+{
+}
+
+#endif
+
+/**********************************************************************************************************************/
+
+/* Allocate SIZE bytes of memory. */
+void *
+fusion_shmalloc( FusionSHMPoolShared *pool, size_t __size )
+{
+ void *data = NULL;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( __size > 0 );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ if (fusion_shm_pool_allocate( pool, __size, false, true, &data ))
+ return NULL;
+
+ D_ASSERT( data != NULL );
+
+ return data;
+}
+
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
+void *
+fusion_shcalloc( FusionSHMPoolShared *pool, size_t __nmemb, size_t __size )
+{
+ void *data = NULL;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( __nmemb > 0 );
+ D_ASSERT( __size > 0 );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ if (fusion_shm_pool_allocate( pool, __nmemb * __size, true, true, &data ))
+ return NULL;
+
+ D_ASSERT( data != NULL );
+
+ return data;
+}
+
+/* Re-allocate the previously allocated block
+ in __ptr, making the new block SIZE bytes long. */
+void *
+fusion_shrealloc( FusionSHMPoolShared *pool, void *__ptr, size_t __size )
+{
+ void *data = NULL;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ if (!__ptr)
+ return fusion_shmalloc( pool, __size );
+
+ if (!__size) {
+ fusion_shfree( pool, __ptr );
+ return NULL;
+ }
+
+ if (fusion_shm_pool_reallocate( pool, __ptr, __size, true, &data ))
+ return NULL;
+
+ D_ASSERT( data != NULL || __size == 0 );
+
+ return data;
+}
+
+/* Free a block allocated by `shmalloc', `shrealloc' or `shcalloc'. */
+void
+fusion_shfree( FusionSHMPoolShared *pool, void *__ptr )
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( __ptr != NULL );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ fusion_shm_pool_deallocate( pool, __ptr, true );
+}
+
+/* Duplicate string in shared memory. */
+char *
+fusion_shstrdup( FusionSHMPoolShared *pool, const char* string )
+{
+ int len;
+ void *data = NULL;
+
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( string != NULL );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ len = strlen( string ) + 1;
+
+ if (fusion_shm_pool_allocate( pool, len, false, true, &data ))
+ return NULL;
+
+ D_ASSERT( data != NULL );
+
+ direct_memcpy( data, string, len );
+
+ return data;
+}
+
+#else
+
+/************************** SINGLE APPLICATION CORE ***************************/
+
+#include <direct/mem.h>
+
+void
+fusion_dbg_print_memleaks( FusionSHMPoolShared *pool )
+{
+}
+
+#if DIRECT_BUILD_DEBUGS /* Build with debug support? */
+
+/* Allocate SIZE bytes of memory. */
+void *
+fusion_dbg_shmalloc( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, size_t __size )
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( __size > 0 );
+
+ if (pool->debug)
+ return direct_malloc( file, line, func, __size );
+
+ return malloc( __size );
+}
+
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
+void *
+fusion_dbg_shcalloc( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, size_t __nmemb, size_t __size)
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( __nmemb > 0 );
+ D_ASSERT( __size > 0 );
+
+ if (pool->debug)
+ return direct_calloc( file, line, func, __nmemb, __size );
+
+ return calloc( __nmemb, __size );
+}
+
+/* Re-allocate the previously allocated block
+ in __ptr, making the new block SIZE bytes long. */
+void *
+fusion_dbg_shrealloc( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, const char *what, void *__ptr,
+ size_t __size )
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ if (pool->debug)
+ return direct_realloc( file, line, func, what, __ptr, __size );
+
+ return realloc( __ptr, __size );
+}
+
+/* Free a block allocated by `shmalloc', `shrealloc' or `shcalloc'. */
+void
+fusion_dbg_shfree( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, const char *what, void *__ptr )
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( __ptr != NULL );
+
+ if (pool->debug)
+ direct_free( file, line, func, what, __ptr );
+ else
+ free( __ptr );
+}
+
+/* Duplicate string in shared memory. */
+char *
+fusion_dbg_shstrdup( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, const char *string )
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( string != NULL );
+
+ if (pool->debug)
+ return direct_strdup( file, line, func, string );
+
+ return strdup( string );
+}
+
+#endif
+
+/**********************************************************************************************************************/
+
+/* Allocate SIZE bytes of memory. */
+void *
+fusion_shmalloc (FusionSHMPoolShared *pool,
+ size_t __size)
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( __size > 0 );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ return malloc( __size );
+}
+
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
+void *
+fusion_shcalloc (FusionSHMPoolShared *pool,
+ size_t __nmemb, size_t __size)
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( __nmemb > 0 );
+ D_ASSERT( __size > 0 );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ return calloc( __nmemb, __size );
+}
+
+/* Re-allocate the previously allocated block
+ in __ptr, making the new block SIZE bytes long. */
+void *
+fusion_shrealloc (FusionSHMPoolShared *pool,
+ void *__ptr, size_t __size)
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ return realloc( __ptr, __size );
+}
+
+/* Free a block allocated by `shmalloc', `shrealloc' or `shcalloc'. */
+void
+fusion_shfree (FusionSHMPoolShared *pool,
+ void *__ptr)
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( __ptr != NULL );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ free( __ptr );
+}
+
+/* Duplicate string in shared memory. */
+char *
+fusion_shstrdup (FusionSHMPoolShared *pool,
+ const char *string)
+{
+ D_MAGIC_ASSERT( pool, FusionSHMPoolShared );
+ D_ASSERT( string != NULL );
+
+ if (pool->debug)
+ D_WARN( "Fusion/SHMMalloc: Pool runs in debug mode, but access from pure-release is attempted!\n" );
+
+ return strdup( string );
+}
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/shmalloc.h b/Source/DirectFB/lib/fusion/shmalloc.h
new file mode 100755
index 0000000..4b8c8d3
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/shmalloc.h
@@ -0,0 +1,124 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ Fusion shmalloc is based on GNU malloc. Please see below.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__SHMALLOC_H__
+#define __FUSION__SHMALLOC_H__
+
+#include <stddef.h>
+
+#include <direct/build.h>
+#include <fusion/build.h>
+
+#include <fusion/types.h>
+#include <fusion/shm/pool.h>
+
+
+#if FUSION_BUILD_MULTI && DIRECT_BUILD_TEXT
+#define D_OOSHM() (direct_messages_warn( __FUNCTION__, __FILE__, __LINE__, \
+ "out of shared memory" ), DR_NOSHAREDMEMORY)
+#else
+#define D_OOSHM() D_OOM()
+#endif
+
+
+
+void fusion_dbg_print_memleaks( FusionSHMPoolShared *pool );
+
+
+void *fusion_dbg_shmalloc ( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, size_t __size );
+
+void *fusion_dbg_shcalloc ( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, size_t __nmemb, size_t __size);
+
+void *fusion_dbg_shrealloc( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, const char *what, void *__ptr,
+ size_t __size );
+
+void fusion_dbg_shfree ( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, const char *what, void *__ptr );
+
+char *fusion_dbg_shstrdup ( FusionSHMPoolShared *pool,
+ const char *file, int line,
+ const char *func, const char *string );
+
+
+/* Allocate SIZE bytes of memory. */
+void *fusion_shmalloc (FusionSHMPoolShared *pool, size_t __size);
+
+/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0. */
+void *fusion_shcalloc (FusionSHMPoolShared *pool, size_t __nmemb, size_t __size);
+
+/* Re-allocate the previously allocated block
+ in __ptr, making the new block SIZE bytes long. */
+void *fusion_shrealloc (FusionSHMPoolShared *pool, void *__ptr, size_t __size);
+
+/* Free a block allocated by `shmalloc', `shrealloc' or `shcalloc'. */
+void fusion_shfree (FusionSHMPoolShared *pool, void *__ptr);
+
+/* Duplicate string in shared memory. */
+char *fusion_shstrdup (FusionSHMPoolShared *pool, const char *string);
+
+
+
+#if DIRECT_BUILD_DEBUGS || DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) || defined(DIRECT_FORCE_DEBUG)
+
+#if !DIRECT_BUILD_DEBUGS
+#warning Building with debug, but library headers suggest that debug is not supported.
+#endif
+
+
+#define SHMALLOC(pool,bytes) fusion_dbg_shmalloc( pool, __FILE__, __LINE__, __FUNCTION__, bytes )
+#define SHCALLOC(pool,count,bytes) fusion_dbg_shcalloc( pool, __FILE__, __LINE__, __FUNCTION__, count, bytes )
+#define SHREALLOC(pool,mem,bytes) fusion_dbg_shrealloc( pool, __FILE__, __LINE__, __FUNCTION__, #mem, mem, bytes )
+#define SHFREE(pool,mem) fusion_dbg_shfree( pool, __FILE__, __LINE__, __FUNCTION__, #mem,mem )
+#define SHSTRDUP(pool,string) fusion_dbg_shstrdup( pool, __FILE__, __LINE__, __FUNCTION__, string )
+
+
+#else
+
+
+#define SHMALLOC fusion_shmalloc
+#define SHCALLOC fusion_shcalloc
+#define SHREALLOC fusion_shrealloc
+#define SHFREE fusion_shfree
+#define SHSTRDUP fusion_shstrdup
+
+
+#endif
+
+
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/types.h b/Source/DirectFB/lib/fusion/types.h
new file mode 100755
index 0000000..bb5967f
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/types.h
@@ -0,0 +1,87 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__TYPES_H__
+#define __FUSION__TYPES_H__
+
+#include <fusion/build.h>
+
+#if FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL
+
+#include <linux/fusion.h>
+
+#define FUSION_API_MAJOR_REQUIRED 8
+#define FUSION_API_MINOR_REQUIRED 0
+
+#if FUSION_API_MAJOR_REQUIRED > FUSION_API_MAJOR_PROVIDED
+#error Major version of Fusion Kernel Module too low! Upgrade your kernel.
+#else
+#if FUSION_API_MAJOR_REQUIRED == FUSION_API_MAJOR_PROVIDED
+#if FUSION_API_MINOR_REQUIRED > FUSION_API_MINOR_PROVIDED
+#error Minor version of Fusion Kernel Module too low! Upgrade your kernel.
+#endif
+#endif
+#endif
+
+#else
+typedef unsigned long FusionID;
+
+#define FUSION_ID_MASTER 1L
+
+typedef enum {
+ FCEF_NONE = 0x00000000,
+ FCEF_ONEWAY = 0x00000001,
+ FCEF_ALL = 0x00000001
+} FusionCallExecFlags;
+
+#endif
+
+#define FCEF_NODIRECT 0x80000000
+
+#include <direct/types.h>
+
+
+typedef struct __Fusion_FusionConfig FusionConfig;
+
+typedef struct __Fusion_FusionArena FusionArena;
+typedef struct __Fusion_FusionReactor FusionReactor;
+typedef struct __Fusion_FusionWorld FusionWorld;
+typedef struct __Fusion_FusionWorldShared FusionWorldShared;
+
+typedef struct __Fusion_FusionObject FusionObject;
+typedef struct __Fusion_FusionObjectPool FusionObjectPool;
+
+typedef struct __Fusion_FusionSHM FusionSHM;
+typedef struct __Fusion_FusionSHMShared FusionSHMShared;
+
+typedef struct __Fusion_FusionSHMPool FusionSHMPool;
+typedef struct __Fusion_FusionSHMPoolShared FusionSHMPoolShared;
+typedef struct __Fusion_FusionHash FusionHash;
+
+#endif
+
diff --git a/Source/DirectFB/lib/fusion/vector.c b/Source/DirectFB/lib/fusion/vector.c
new file mode 100755
index 0000000..aa8a4a0
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/vector.c
@@ -0,0 +1,230 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <config.h>
+
+#include <direct/debug.h>
+#include <direct/mem.h>
+#include <direct/memcpy.h>
+
+#include <fusion/object.h>
+#include <fusion/shmalloc.h>
+#include <fusion/vector.h>
+
+
+static inline bool ensure_capacity( FusionVector *vector )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( vector->capacity > 0 );
+
+ if (!vector->elements) {
+ if (vector->pool)
+ vector->elements = SHMALLOC( vector->pool, vector->capacity * sizeof(void*) );
+ else
+ vector->elements = D_MALLOC( vector->capacity * sizeof(void*) );
+
+ if (!vector->elements)
+ return false;
+ }
+ else if (vector->count == vector->capacity) {
+ void *elements;
+ void *oldelements = vector->elements;
+ int capacity = vector->capacity << 1;
+
+ if (vector->pool)
+ elements = SHMALLOC( vector->pool, capacity * sizeof(void*) );
+ else
+ elements = D_MALLOC( capacity * sizeof(void*) );
+
+ if (!elements)
+ return false;
+
+ direct_memcpy( elements, vector->elements,
+ vector->count * sizeof(void*) );
+
+ vector->elements = elements;
+ vector->capacity = capacity;
+
+ if (vector->pool)
+ SHFREE( vector->pool, oldelements );
+ else
+ D_FREE( oldelements );
+ }
+
+ return true;
+}
+
+void
+fusion_vector_init( FusionVector *vector,
+ int capacity,
+ FusionSHMPoolShared *pool )
+{
+ D_ASSERT( vector != NULL );
+ D_ASSERT( capacity > 0 );
+
+ vector->elements = NULL;
+ vector->count = 0;
+ vector->capacity = capacity;
+ vector->pool = pool;
+
+ D_MAGIC_SET( vector, FusionVector );
+}
+
+void
+fusion_vector_destroy( FusionVector *vector )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( vector->count == 0 || vector->elements != NULL );
+
+ if (vector->elements) {
+ if (vector->pool)
+ SHFREE( vector->pool, vector->elements );
+ else
+ D_FREE( vector->elements );
+
+ vector->elements = NULL;
+ }
+
+ D_MAGIC_CLEAR( vector );
+}
+
+DirectResult
+fusion_vector_add( FusionVector *vector,
+ void *element )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( element != NULL );
+
+ /* Make sure there's a free entry left. */
+ if (!ensure_capacity( vector ))
+ return D_OOSHM();
+
+ /* Add the element to the vector. */
+ vector->elements[vector->count++] = element;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_vector_insert( FusionVector *vector,
+ void *element,
+ int index )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( element != NULL );
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index <= vector->count );
+
+ /* Make sure there's a free entry left. */
+ if (!ensure_capacity( vector ))
+ return D_OOSHM();
+
+ /* Move elements from insertion point one up. */
+ memmove( &vector->elements[ index + 1 ],
+ &vector->elements[ index ],
+ (vector->count - index) * sizeof(void*) );
+
+ /* Insert the element into the vector. */
+ vector->elements[index] = element;
+
+ /* Increase the element counter. */
+ vector->count++;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_vector_move( FusionVector *vector,
+ int from,
+ int to )
+{
+ void *element;
+
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( from >= 0 );
+ D_ASSERT( from < vector->count );
+ D_ASSERT( to >= 0 );
+ D_ASSERT( to < vector->count );
+
+ if (to == from)
+ return DR_OK;
+
+ /* Save the element. */
+ element = vector->elements[from];
+
+ /* Move elements that lie on the way to the new position. */
+ if (to > from) {
+ /* Element is moving up -> move other elements down. */
+ memmove( &vector->elements[ from ],
+ &vector->elements[ from + 1 ],
+ (to - from) * sizeof(void*) );
+ }
+ else {
+ /* Element is moving down -> move other elements up. */
+ memmove( &vector->elements[ to + 1 ],
+ &vector->elements[ to ],
+ (from - to) * sizeof(void*) );
+ }
+
+ /* Restore the element at the new position. */
+ vector->elements[to] = element;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_vector_remove( FusionVector *vector,
+ int index )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < vector->count );
+
+ /* Move elements after this element one down. */
+ memmove( &vector->elements[ index ],
+ &vector->elements[ index + 1 ],
+ (vector->count - index - 1) * sizeof(void*) );
+
+ /* Decrease the element counter. */
+ vector->count--;
+
+ return DR_OK;
+}
+
+DirectResult
+fusion_vector_remove_last( FusionVector *vector )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( vector->count > 0 );
+
+ /* Decrease the element counter. */
+ vector->count--;
+
+ return DR_OK;
+}
+
diff --git a/Source/DirectFB/lib/fusion/vector.h b/Source/DirectFB/lib/fusion/vector.h
new file mode 100755
index 0000000..e978ce9
--- /dev/null
+++ b/Source/DirectFB/lib/fusion/vector.h
@@ -0,0 +1,164 @@
+/*
+ (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org)
+ (c) Copyright 2000-2004 Convergence (integrated media) GmbH
+
+ All rights reserved.
+
+ Written by Denis Oliver Kropp <dok@directfb.org>,
+ Andreas Hundt <andi@fischlustig.de>,
+ Sven Neumann <neo@directfb.org>,
+ Ville Syrjälä <syrjala@sci.fi> and
+ Claudio Ciccani <klan@users.sf.net>.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FUSION__VECTOR_H__
+#define __FUSION__VECTOR_H__
+
+#include <limits.h>
+
+#include <fusion/types.h>
+
+#include <direct/debug.h>
+
+typedef struct {
+ int magic;
+
+ void **elements;
+ int count;
+
+ int capacity;
+
+ FusionSHMPoolShared *pool;
+} FusionVector;
+
+void fusion_vector_init ( FusionVector *vector,
+ int capacity,
+ FusionSHMPoolShared *pool );
+
+void fusion_vector_destroy ( FusionVector *vector );
+
+DirectResult fusion_vector_add ( FusionVector *vector,
+ void *element );
+
+DirectResult fusion_vector_insert ( FusionVector *vector,
+ void *element,
+ int index );
+
+DirectResult fusion_vector_move ( FusionVector *vector,
+ int from,
+ int to );
+
+DirectResult fusion_vector_remove ( FusionVector *vector,
+ int index );
+
+DirectResult fusion_vector_remove_last( FusionVector *vector );
+
+
+static inline bool
+fusion_vector_has_elements( const FusionVector *vector )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+
+ return vector->count > 0;
+}
+
+static inline bool
+fusion_vector_is_empty( const FusionVector *vector )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+
+ return vector->count == 0;
+}
+
+static inline int
+fusion_vector_size( const FusionVector *vector )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+
+ return vector->count;
+}
+
+static inline void *
+fusion_vector_at( const FusionVector *vector, int index )
+{
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( index >= 0 );
+ D_ASSERT( index < vector->count );
+
+ return vector->elements[index];
+}
+
+static inline bool
+fusion_vector_contains( const FusionVector *vector, const void *element )
+{
+ int i;
+ int count;
+ void * const *elements;
+
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( element != NULL );
+
+ count = vector->count;
+ elements = vector->elements;
+
+ /* Start with more recently added elements. */
+ for (i=count-1; i>=0; i--)
+ if (elements[i] == element)
+ return true;
+
+ return false;
+}
+
+static inline int
+fusion_vector_index_of( const FusionVector *vector, const void *element )
+{
+ int i;
+ int count;
+ void * const *elements;
+
+ D_MAGIC_ASSERT( vector, FusionVector );
+ D_ASSERT( element != NULL );
+
+ count = vector->count;
+ elements = vector->elements;
+
+ /* Start with more recently added elements. */
+ for (i=count-1; i>=0; i--)
+ if (elements[i] == element)
+ return i;
+
+ /*
+ * In case the return value isn't checked
+ * this will most likely generate a bad address.
+ */
+ return INT_MIN >> 2;
+}
+
+
+#define fusion_vector_foreach(element, index, vector) \
+ for ((index) = 0; \
+ (index) < (vector).count && (element = (vector).elements[index]); \
+ (index)++)
+
+#define fusion_vector_foreach_reverse(element, index, vector) \
+ for ((index) = (vector).count - 1; \
+ (index) >= 0 && (element = (vector).elements[index]); \
+ (index)--)
+
+#endif
+