From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/lib/fusion/Makefile.am | 100 + Source/DirectFB/lib/fusion/Makefile.in | 804 ++++++++ Source/DirectFB/lib/fusion/arena.c | 566 ++++++ Source/DirectFB/lib/fusion/arena.h | 62 + Source/DirectFB/lib/fusion/build.h.in | 36 + Source/DirectFB/lib/fusion/call.c | 581 ++++++ Source/DirectFB/lib/fusion/call.h | 74 + Source/DirectFB/lib/fusion/conf.c | 113 ++ Source/DirectFB/lib/fusion/conf.h | 55 + Source/DirectFB/lib/fusion/fusion.c | 2658 +++++++++++++++++++++++++ Source/DirectFB/lib/fusion/fusion.h | 142 ++ Source/DirectFB/lib/fusion/fusion.pc.in | 11 + Source/DirectFB/lib/fusion/fusion_internal.h | 185 ++ Source/DirectFB/lib/fusion/hash.c | 560 ++++++ Source/DirectFB/lib/fusion/hash.h | 179 ++ Source/DirectFB/lib/fusion/lock.c | 687 +++++++ Source/DirectFB/lib/fusion/lock.h | 122 ++ Source/DirectFB/lib/fusion/object.c | 640 ++++++ Source/DirectFB/lib/fusion/object.h | 279 +++ Source/DirectFB/lib/fusion/property.c | 530 +++++ Source/DirectFB/lib/fusion/property.h | 114 ++ Source/DirectFB/lib/fusion/protocol.h | 119 ++ Source/DirectFB/lib/fusion/reactor.c | 1868 +++++++++++++++++ Source/DirectFB/lib/fusion/reactor.h | 197 ++ Source/DirectFB/lib/fusion/ref.c | 849 ++++++++ Source/DirectFB/lib/fusion/ref.h | 134 ++ Source/DirectFB/lib/fusion/shm/Makefile.am | 31 + Source/DirectFB/lib/fusion/shm/Makefile.in | 565 ++++++ Source/DirectFB/lib/fusion/shm/fake.c | 163 ++ Source/DirectFB/lib/fusion/shm/heap.c | 802 ++++++++ Source/DirectFB/lib/fusion/shm/pool.c | 954 +++++++++ Source/DirectFB/lib/fusion/shm/pool.h | 69 + Source/DirectFB/lib/fusion/shm/shm.c | 337 ++++ Source/DirectFB/lib/fusion/shm/shm.h | 48 + Source/DirectFB/lib/fusion/shm/shm_internal.h | 264 +++ Source/DirectFB/lib/fusion/shmalloc.c | 679 +++++++ Source/DirectFB/lib/fusion/shmalloc.h | 124 ++ Source/DirectFB/lib/fusion/types.h | 87 + Source/DirectFB/lib/fusion/vector.c | 230 +++ Source/DirectFB/lib/fusion/vector.h | 164 ++ 40 files changed, 16182 insertions(+) create mode 100755 Source/DirectFB/lib/fusion/Makefile.am create mode 100755 Source/DirectFB/lib/fusion/Makefile.in create mode 100755 Source/DirectFB/lib/fusion/arena.c create mode 100755 Source/DirectFB/lib/fusion/arena.h create mode 100755 Source/DirectFB/lib/fusion/build.h.in create mode 100755 Source/DirectFB/lib/fusion/call.c create mode 100755 Source/DirectFB/lib/fusion/call.h create mode 100755 Source/DirectFB/lib/fusion/conf.c create mode 100755 Source/DirectFB/lib/fusion/conf.h create mode 100755 Source/DirectFB/lib/fusion/fusion.c create mode 100755 Source/DirectFB/lib/fusion/fusion.h create mode 100755 Source/DirectFB/lib/fusion/fusion.pc.in create mode 100755 Source/DirectFB/lib/fusion/fusion_internal.h create mode 100755 Source/DirectFB/lib/fusion/hash.c create mode 100755 Source/DirectFB/lib/fusion/hash.h create mode 100755 Source/DirectFB/lib/fusion/lock.c create mode 100755 Source/DirectFB/lib/fusion/lock.h create mode 100755 Source/DirectFB/lib/fusion/object.c create mode 100755 Source/DirectFB/lib/fusion/object.h create mode 100755 Source/DirectFB/lib/fusion/property.c create mode 100755 Source/DirectFB/lib/fusion/property.h create mode 100755 Source/DirectFB/lib/fusion/protocol.h create mode 100755 Source/DirectFB/lib/fusion/reactor.c create mode 100755 Source/DirectFB/lib/fusion/reactor.h create mode 100755 Source/DirectFB/lib/fusion/ref.c create mode 100755 Source/DirectFB/lib/fusion/ref.h create mode 100755 Source/DirectFB/lib/fusion/shm/Makefile.am create mode 100755 Source/DirectFB/lib/fusion/shm/Makefile.in create mode 100755 Source/DirectFB/lib/fusion/shm/fake.c create mode 100755 Source/DirectFB/lib/fusion/shm/heap.c create mode 100755 Source/DirectFB/lib/fusion/shm/pool.c create mode 100755 Source/DirectFB/lib/fusion/shm/pool.h create mode 100755 Source/DirectFB/lib/fusion/shm/shm.c create mode 100755 Source/DirectFB/lib/fusion/shm/shm.h create mode 100755 Source/DirectFB/lib/fusion/shm/shm_internal.h create mode 100755 Source/DirectFB/lib/fusion/shmalloc.c create mode 100755 Source/DirectFB/lib/fusion/shmalloc.h create mode 100755 Source/DirectFB/lib/fusion/types.h create mode 100755 Source/DirectFB/lib/fusion/vector.c create mode 100755 Source/DirectFB/lib/fusion/vector.h (limited to 'Source/DirectFB/lib/fusion') 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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +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 , + Andreas Hundt , + Sven Neumann and + Ville Syrjälä . + + 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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#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 +#include + + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include +#include +#include + +#include +#include +#include + +#include + + +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= Location of shared memory file\n" + " shmfile-group= 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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "fusion_internal.h" + +#include + +#include + + +#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; ifork_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; ishared; + + 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; ifork_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 world 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_indexrefs > 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, ¶m )) { + 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 + +#include + +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; ifork_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; ishared; + + 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; ishared; + + 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 world 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_indexshmfile_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; ipools[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 world_index 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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include + +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 world_index 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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include + +#include + +#include + +#include +#include +#include +#include +#include + +#if FUSION_BUILD_MULTI +# if FUSION_BUILD_KERNEL +# include +# include +# else +# include +# 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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä , + Claudio Ciccani and + Michael Emmel . + + 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 + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä , + Claudio Ciccani and + Michael Emmel . + + 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 +#include +#include + +#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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#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 +#include +#include + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include + +#include +#include + + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include +#include +#include +#include +#include + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#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 + +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 + +/* + * 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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include +#include + +#include + + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include +#include +#include + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include "fusion_internal.h" + +#include + + +#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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include +#include +#include + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include +#include +#include + +#include +#include + +#include + + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +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; ipools[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; ipools[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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + + +/**********************************************************************************************************************/ + +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; ipools[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; ipools[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; ipools[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; ipools[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; ipools[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; ipools[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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include + +#include +#include + + +#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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + + +#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 + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include +#include + +#include +#include + + +#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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#if FUSION_BUILD_MULTI && FUSION_BUILD_KERNEL + +#include + +#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 + + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include +#include +#include + +#include +#include +#include + + +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 , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + 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 + +#include + +#include + +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 + -- cgit