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/Makefile.am | 7 + Source/DirectFB/lib/Makefile.in | 557 ++++ Source/DirectFB/lib/direct/Makefile.am | 138 + Source/DirectFB/lib/direct/Makefile.in | 769 ++++++ Source/DirectFB/lib/direct/armasm_memcpy.S | 421 ++++ Source/DirectFB/lib/direct/armasm_memcpy.h | 32 + Source/DirectFB/lib/direct/build.h.in | 51 + Source/DirectFB/lib/direct/clock.c | 135 + Source/DirectFB/lib/direct/clock.h | 45 + Source/DirectFB/lib/direct/conf.c | 348 +++ Source/DirectFB/lib/direct/conf.h | 92 + Source/DirectFB/lib/direct/debug.c | 430 ++++ Source/DirectFB/lib/direct/debug.h | 287 +++ Source/DirectFB/lib/direct/direct.c | 197 ++ Source/DirectFB/lib/direct/direct.h | 49 + Source/DirectFB/lib/direct/direct.pc.in | 13 + Source/DirectFB/lib/direct/fastlz.c | 97 + Source/DirectFB/lib/direct/fastlz.h | 52 + Source/DirectFB/lib/direct/flz.c | 555 ++++ Source/DirectFB/lib/direct/flz.h | 100 + Source/DirectFB/lib/direct/hash.c | 268 ++ Source/DirectFB/lib/direct/hash.h | 61 + Source/DirectFB/lib/direct/interface.c | 474 ++++ Source/DirectFB/lib/direct/interface.h | 215 ++ .../DirectFB/lib/direct/interface_implementation.h | 91 + Source/DirectFB/lib/direct/list.c | 35 + Source/DirectFB/lib/direct/list.h | 224 ++ Source/DirectFB/lib/direct/log.c | 414 +++ Source/DirectFB/lib/direct/log.h | 89 + Source/DirectFB/lib/direct/mem.c | 350 +++ Source/DirectFB/lib/direct/mem.h | 84 + Source/DirectFB/lib/direct/memcpy.c | 265 ++ Source/DirectFB/lib/direct/memcpy.h | 51 + Source/DirectFB/lib/direct/messages.c | 215 ++ Source/DirectFB/lib/direct/messages.h | 173 ++ Source/DirectFB/lib/direct/modules.c | 463 ++++ Source/DirectFB/lib/direct/modules.h | 95 + Source/DirectFB/lib/direct/ppc_asm.h | 115 + Source/DirectFB/lib/direct/ppcasm_memcpy.S | 77 + Source/DirectFB/lib/direct/ppcasm_memcpy.h | 7 + .../DirectFB/lib/direct/ppcasm_memcpy_cachable.S | 180 ++ Source/DirectFB/lib/direct/serial.h | 118 + Source/DirectFB/lib/direct/signals.c | 480 ++++ Source/DirectFB/lib/direct/signals.h | 70 + Source/DirectFB/lib/direct/stream.c | 2286 +++++++++++++++++ Source/DirectFB/lib/direct/stream.h | 129 + Source/DirectFB/lib/direct/system.c | 68 + Source/DirectFB/lib/direct/system.h | 40 + Source/DirectFB/lib/direct/thread.c | 795 ++++++ Source/DirectFB/lib/direct/thread.h | 168 ++ Source/DirectFB/lib/direct/trace.c | 676 +++++ Source/DirectFB/lib/direct/trace.h | 98 + Source/DirectFB/lib/direct/tree.c | 307 +++ Source/DirectFB/lib/direct/tree.h | 67 + Source/DirectFB/lib/direct/types.h | 169 ++ Source/DirectFB/lib/direct/utf8.c | 36 + Source/DirectFB/lib/direct/utf8.h | 80 + Source/DirectFB/lib/direct/util.c | 519 ++++ Source/DirectFB/lib/direct/util.h | 330 +++ 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 ++ Source/DirectFB/lib/voodoo/Makefile.am | 82 + Source/DirectFB/lib/voodoo/Makefile.in | 666 +++++ Source/DirectFB/lib/voodoo/app.h | 66 + Source/DirectFB/lib/voodoo/build.h.in | 34 + Source/DirectFB/lib/voodoo/client.c | 208 ++ Source/DirectFB/lib/voodoo/client.h | 44 + Source/DirectFB/lib/voodoo/compat.h | 8 + Source/DirectFB/lib/voodoo/conf.c | 253 ++ Source/DirectFB/lib/voodoo/conf.h | 58 + Source/DirectFB/lib/voodoo/connection.cpp | 70 + Source/DirectFB/lib/voodoo/connection.h | 60 + Source/DirectFB/lib/voodoo/connection_link.cpp | 331 +++ Source/DirectFB/lib/voodoo/connection_link.h | 106 + Source/DirectFB/lib/voodoo/connection_packet.cpp | 368 +++ Source/DirectFB/lib/voodoo/connection_packet.h | 61 + .../DirectFB/lib/voodoo/connection_packet_old.cpp | 433 ++++ Source/DirectFB/lib/voodoo/connection_packet_old.h | 87 + Source/DirectFB/lib/voodoo/connection_raw.cpp | 341 +++ Source/DirectFB/lib/voodoo/connection_raw.h | 60 + Source/DirectFB/lib/voodoo/dispatcher.cpp | 231 ++ Source/DirectFB/lib/voodoo/dispatcher.h | 71 + Source/DirectFB/lib/voodoo/instance.cpp | 107 + Source/DirectFB/lib/voodoo/instance.h | 61 + Source/DirectFB/lib/voodoo/interface.c | 114 + Source/DirectFB/lib/voodoo/interface.h | 52 + Source/DirectFB/lib/voodoo/internal.h | 40 + Source/DirectFB/lib/voodoo/ivoodooplayer.c | 247 ++ Source/DirectFB/lib/voodoo/ivoodooplayer.h | 74 + .../DirectFB/lib/voodoo/ivoodooplayer_dispatcher.c | 359 +++ .../DirectFB/lib/voodoo/ivoodooplayer_dispatcher.h | 41 + .../DirectFB/lib/voodoo/ivoodooplayer_requestor.c | 330 +++ Source/DirectFB/lib/voodoo/link.h | 78 + Source/DirectFB/lib/voodoo/manager.cpp | 937 +++++++ Source/DirectFB/lib/voodoo/manager.h | 279 ++ Source/DirectFB/lib/voodoo/manager_c.cpp | 553 ++++ Source/DirectFB/lib/voodoo/message.h | 258 ++ Source/DirectFB/lib/voodoo/mutex.c | 105 + Source/DirectFB/lib/voodoo/mutex.h | 142 ++ Source/DirectFB/lib/voodoo/packet.h | 285 +++ Source/DirectFB/lib/voodoo/play.c | 935 +++++++ Source/DirectFB/lib/voodoo/play.h | 146 ++ Source/DirectFB/lib/voodoo/play_internal.h | 89 + Source/DirectFB/lib/voodoo/play_server.c | 430 ++++ Source/DirectFB/lib/voodoo/play_server.h | 79 + Source/DirectFB/lib/voodoo/server.c | 459 ++++ Source/DirectFB/lib/voodoo/server.h | 52 + Source/DirectFB/lib/voodoo/types.h | 97 + Source/DirectFB/lib/voodoo/unix/interfaces_unix.c | 237 ++ Source/DirectFB/lib/voodoo/unix/link_unix.c | 567 +++++ .../DirectFB/lib/voodoo/unix/link_unix_1408limit.c | 422 ++++ Source/DirectFB/lib/voodoo/voodoo.pc.in | 11 + Source/DirectFB/lib/voodoo/waitqueue.h | 117 + 151 files changed, 42280 insertions(+) create mode 100755 Source/DirectFB/lib/Makefile.am create mode 100755 Source/DirectFB/lib/Makefile.in create mode 100755 Source/DirectFB/lib/direct/Makefile.am create mode 100755 Source/DirectFB/lib/direct/Makefile.in create mode 100755 Source/DirectFB/lib/direct/armasm_memcpy.S create mode 100755 Source/DirectFB/lib/direct/armasm_memcpy.h create mode 100755 Source/DirectFB/lib/direct/build.h.in create mode 100755 Source/DirectFB/lib/direct/clock.c create mode 100755 Source/DirectFB/lib/direct/clock.h create mode 100755 Source/DirectFB/lib/direct/conf.c create mode 100755 Source/DirectFB/lib/direct/conf.h create mode 100755 Source/DirectFB/lib/direct/debug.c create mode 100755 Source/DirectFB/lib/direct/debug.h create mode 100755 Source/DirectFB/lib/direct/direct.c create mode 100755 Source/DirectFB/lib/direct/direct.h create mode 100755 Source/DirectFB/lib/direct/direct.pc.in create mode 100755 Source/DirectFB/lib/direct/fastlz.c create mode 100755 Source/DirectFB/lib/direct/fastlz.h create mode 100755 Source/DirectFB/lib/direct/flz.c create mode 100755 Source/DirectFB/lib/direct/flz.h create mode 100755 Source/DirectFB/lib/direct/hash.c create mode 100755 Source/DirectFB/lib/direct/hash.h create mode 100755 Source/DirectFB/lib/direct/interface.c create mode 100755 Source/DirectFB/lib/direct/interface.h create mode 100755 Source/DirectFB/lib/direct/interface_implementation.h create mode 100755 Source/DirectFB/lib/direct/list.c create mode 100755 Source/DirectFB/lib/direct/list.h create mode 100755 Source/DirectFB/lib/direct/log.c create mode 100755 Source/DirectFB/lib/direct/log.h create mode 100755 Source/DirectFB/lib/direct/mem.c create mode 100755 Source/DirectFB/lib/direct/mem.h create mode 100755 Source/DirectFB/lib/direct/memcpy.c create mode 100755 Source/DirectFB/lib/direct/memcpy.h create mode 100755 Source/DirectFB/lib/direct/messages.c create mode 100755 Source/DirectFB/lib/direct/messages.h create mode 100755 Source/DirectFB/lib/direct/modules.c create mode 100755 Source/DirectFB/lib/direct/modules.h create mode 100755 Source/DirectFB/lib/direct/ppc_asm.h create mode 100755 Source/DirectFB/lib/direct/ppcasm_memcpy.S create mode 100755 Source/DirectFB/lib/direct/ppcasm_memcpy.h create mode 100755 Source/DirectFB/lib/direct/ppcasm_memcpy_cachable.S create mode 100755 Source/DirectFB/lib/direct/serial.h create mode 100755 Source/DirectFB/lib/direct/signals.c create mode 100755 Source/DirectFB/lib/direct/signals.h create mode 100755 Source/DirectFB/lib/direct/stream.c create mode 100755 Source/DirectFB/lib/direct/stream.h create mode 100755 Source/DirectFB/lib/direct/system.c create mode 100755 Source/DirectFB/lib/direct/system.h create mode 100755 Source/DirectFB/lib/direct/thread.c create mode 100755 Source/DirectFB/lib/direct/thread.h create mode 100755 Source/DirectFB/lib/direct/trace.c create mode 100755 Source/DirectFB/lib/direct/trace.h create mode 100755 Source/DirectFB/lib/direct/tree.c create mode 100755 Source/DirectFB/lib/direct/tree.h create mode 100755 Source/DirectFB/lib/direct/types.h create mode 100755 Source/DirectFB/lib/direct/utf8.c create mode 100755 Source/DirectFB/lib/direct/utf8.h create mode 100755 Source/DirectFB/lib/direct/util.c create mode 100755 Source/DirectFB/lib/direct/util.h 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 create mode 100755 Source/DirectFB/lib/voodoo/Makefile.am create mode 100755 Source/DirectFB/lib/voodoo/Makefile.in create mode 100755 Source/DirectFB/lib/voodoo/app.h create mode 100755 Source/DirectFB/lib/voodoo/build.h.in create mode 100755 Source/DirectFB/lib/voodoo/client.c create mode 100755 Source/DirectFB/lib/voodoo/client.h create mode 100755 Source/DirectFB/lib/voodoo/compat.h create mode 100755 Source/DirectFB/lib/voodoo/conf.c create mode 100755 Source/DirectFB/lib/voodoo/conf.h create mode 100755 Source/DirectFB/lib/voodoo/connection.cpp create mode 100755 Source/DirectFB/lib/voodoo/connection.h create mode 100755 Source/DirectFB/lib/voodoo/connection_link.cpp create mode 100755 Source/DirectFB/lib/voodoo/connection_link.h create mode 100755 Source/DirectFB/lib/voodoo/connection_packet.cpp create mode 100755 Source/DirectFB/lib/voodoo/connection_packet.h create mode 100755 Source/DirectFB/lib/voodoo/connection_packet_old.cpp create mode 100755 Source/DirectFB/lib/voodoo/connection_packet_old.h create mode 100755 Source/DirectFB/lib/voodoo/connection_raw.cpp create mode 100755 Source/DirectFB/lib/voodoo/connection_raw.h create mode 100755 Source/DirectFB/lib/voodoo/dispatcher.cpp create mode 100755 Source/DirectFB/lib/voodoo/dispatcher.h create mode 100755 Source/DirectFB/lib/voodoo/instance.cpp create mode 100755 Source/DirectFB/lib/voodoo/instance.h create mode 100755 Source/DirectFB/lib/voodoo/interface.c create mode 100755 Source/DirectFB/lib/voodoo/interface.h create mode 100755 Source/DirectFB/lib/voodoo/internal.h create mode 100755 Source/DirectFB/lib/voodoo/ivoodooplayer.c create mode 100755 Source/DirectFB/lib/voodoo/ivoodooplayer.h create mode 100755 Source/DirectFB/lib/voodoo/ivoodooplayer_dispatcher.c create mode 100755 Source/DirectFB/lib/voodoo/ivoodooplayer_dispatcher.h create mode 100755 Source/DirectFB/lib/voodoo/ivoodooplayer_requestor.c create mode 100755 Source/DirectFB/lib/voodoo/link.h create mode 100755 Source/DirectFB/lib/voodoo/manager.cpp create mode 100755 Source/DirectFB/lib/voodoo/manager.h create mode 100755 Source/DirectFB/lib/voodoo/manager_c.cpp create mode 100755 Source/DirectFB/lib/voodoo/message.h create mode 100755 Source/DirectFB/lib/voodoo/mutex.c create mode 100755 Source/DirectFB/lib/voodoo/mutex.h create mode 100755 Source/DirectFB/lib/voodoo/packet.h create mode 100755 Source/DirectFB/lib/voodoo/play.c create mode 100755 Source/DirectFB/lib/voodoo/play.h create mode 100755 Source/DirectFB/lib/voodoo/play_internal.h create mode 100755 Source/DirectFB/lib/voodoo/play_server.c create mode 100755 Source/DirectFB/lib/voodoo/play_server.h create mode 100755 Source/DirectFB/lib/voodoo/server.c create mode 100755 Source/DirectFB/lib/voodoo/server.h create mode 100755 Source/DirectFB/lib/voodoo/types.h create mode 100755 Source/DirectFB/lib/voodoo/unix/interfaces_unix.c create mode 100755 Source/DirectFB/lib/voodoo/unix/link_unix.c create mode 100755 Source/DirectFB/lib/voodoo/unix/link_unix_1408limit.c create mode 100755 Source/DirectFB/lib/voodoo/voodoo.pc.in create mode 100755 Source/DirectFB/lib/voodoo/waitqueue.h (limited to 'Source/DirectFB/lib') diff --git a/Source/DirectFB/lib/Makefile.am b/Source/DirectFB/lib/Makefile.am new file mode 100755 index 0000000..89ac43d --- /dev/null +++ b/Source/DirectFB/lib/Makefile.am @@ -0,0 +1,7 @@ +## Makefile.am for DirectFB/lib + +if ENABLE_VOODOO +VOODOO_DIR = voodoo +endif + +SUBDIRS = direct fusion $(VOODOO_DIR) diff --git a/Source/DirectFB/lib/Makefile.in b/Source/DirectFB/lib/Makefile.in new file mode 100755 index 0000000..5c1ee83 --- /dev/null +++ b/Source/DirectFB/lib/Makefile.in @@ -0,0 +1,557 @@ +# 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 +DIST_COMMON = $(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 = +SOURCES = +DIST_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 +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = direct fusion voodoo +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@ +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@ +@ENABLE_VOODOO_TRUE@VOODOO_DIR = voodoo +SUBDIRS = direct fusion $(VOODOO_DIR) +all: all-recursive + +.SUFFIXES: +$(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/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu lib/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 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# 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 +installdirs: installdirs-recursive +installdirs-am: +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." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-exec-am: + +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 -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean 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-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/Source/DirectFB/lib/direct/Makefile.am b/Source/DirectFB/lib/direct/Makefile.am new file mode 100755 index 0000000..c7604cd --- /dev/null +++ b/Source/DirectFB/lib/direct/Makefile.am @@ -0,0 +1,138 @@ +## Makefile.am for DirectFB/lib/direct + +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 = direct.pc + +EXTRA_DIST = \ + armasm_memcpy.S \ + armasm_memcpy.h \ + ppcasm_memcpy.S \ + ppcasm_memcpy_cachable.S \ + ppcasm_memcpy.h \ + ppc_asm.h + +if BUILDPPCASM +if HAVE_LINUX +ppcasm_sources = ppcasm_memcpy.S ppcasm_memcpy_cachable.S +else +ppcasm_sources = ppcasm_memcpy.S +endif + +ppcasm_headers = ppcasm_memcpy.h ppc_asm.h +endif + +if BUILDARMASM +armasm_sources = armasm_memcpy.S +armasm_header = armasm_memcpy.h +endif + +# If the old location isn't cleared, builds of external modules fail +install-exec-local: + rm -rf $(DESTDIR)$(INTERNALINCLUDEDIR)/direct + + +includedir = @INCLUDEDIR@/direct + +include_HEADERS = \ + $(ppcasm_headers) \ + $(armasm_headers) \ + build.h \ + clock.h \ + conf.h \ + debug.h \ + direct.h \ + hash.h \ + interface.h \ + interface_implementation.h \ + list.h \ + log.h \ + mem.h \ + memcpy.h \ + messages.h \ + modules.h \ + serial.h \ + signals.h \ + stream.h \ + system.h \ + thread.h \ + trace.h \ + tree.h \ + types.h \ + utf8.h \ + fastlz.h \ + flz.h \ + util.h + + +lib_LTLIBRARIES = libdirect.la + +libdirect_la_SOURCES = \ + $(ppcasm_sources) \ + $(armasm_sources) \ + clock.c \ + conf.c \ + debug.c \ + direct.c \ + hash.c \ + interface.c \ + list.c \ + log.c \ + mem.c \ + memcpy.c \ + messages.c \ + modules.c \ + signals.c \ + stream.c \ + system.c \ + trace.c \ + tree.c \ + thread.c \ + utf8.c \ + fastlz.c \ + flz.c \ + util.c + +libdirect_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 libdirect_fixed.a + +all-local: libdirect_fixed.a + +libdirect_fixed.a: .libs/libdirect.a + rm -f libdirect_fixed.a + ${AR} cru libdirect_fixed.a `find . -name "*.o" | grep -v '.libs' | grep -v dtest` + ${RANLIB} libdirect_fixed.a + cp -pf libdirect_fixed.a .libs/libdirect.a + +.libs/libdirect.a: libdirect.la + +else + +clean-local: + +all-local: + +endif + + +include $(top_srcdir)/rules/nmfile.make diff --git a/Source/DirectFB/lib/direct/Makefile.in b/Source/DirectFB/lib/direct/Makefile.in new file mode 100755 index 0000000..efb1a74 --- /dev/null +++ b/Source/DirectFB/lib/direct/Makefile.in @@ -0,0 +1,769 @@ +# 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 = $(am__include_HEADERS_DIST) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/build.h.in \ + $(srcdir)/direct.pc.in $(top_srcdir)/rules/nmfile.make +subdir = lib/direct +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 direct.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) +libdirect_la_LIBADD = +am__libdirect_la_SOURCES_DIST = ppcasm_memcpy.S \ + ppcasm_memcpy_cachable.S armasm_memcpy.S clock.c conf.c \ + debug.c direct.c hash.c interface.c list.c log.c mem.c \ + memcpy.c messages.c modules.c signals.c stream.c system.c \ + trace.c tree.c thread.c utf8.c util.c +@BUILDPPCASM_TRUE@@HAVE_LINUX_FALSE@am__objects_1 = ppcasm_memcpy.lo +@BUILDPPCASM_TRUE@@HAVE_LINUX_TRUE@am__objects_1 = ppcasm_memcpy.lo \ +@BUILDPPCASM_TRUE@@HAVE_LINUX_TRUE@ ppcasm_memcpy_cachable.lo +@BUILDARMASM_TRUE@am__objects_2 = armasm_memcpy.lo +am_libdirect_la_OBJECTS = $(am__objects_1) $(am__objects_2) clock.lo \ + conf.lo debug.lo direct.lo hash.lo interface.lo list.lo log.lo \ + mem.lo memcpy.lo messages.lo modules.lo signals.lo stream.lo \ + system.lo trace.lo tree.lo thread.lo utf8.lo util.lo +libdirect_la_OBJECTS = $(am_libdirect_la_OBJECTS) +libdirect_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libdirect_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +CPPASCOMPILE = $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) +LTCPPASCOMPILE = $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CCAS) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CCASFLAGS) $(CCASFLAGS) +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 = $(libdirect_la_SOURCES) +DIST_SOURCES = $(am__libdirect_la_SOURCES_DIST) +pkgconfigDATA_INSTALL = $(INSTALL_DATA) +DATA = $(pkgconfig_DATA) +am__include_HEADERS_DIST = ppcasm_memcpy.h ppc_asm.h build.h clock.h \ + conf.h debug.h direct.h hash.h interface.h \ + interface_implementation.h list.h log.h mem.h memcpy.h \ + messages.h modules.h serial.h signals.h stream.h system.h \ + thread.h trace.h tree.h types.h utf8.h util.h +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@/direct +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=\"${RUNTIME_SYSROOT}@DATADIR@\" \ + -DMODULEDIR=\"${RUNTIME_SYSROOT}@MODULEDIR@\" + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = direct.pc +EXTRA_DIST = \ + armasm_memcpy.S \ + armasm_memcpy.h \ + ppcasm_memcpy.S \ + ppcasm_memcpy_cachable.S \ + ppcasm_memcpy.h \ + ppc_asm.h + +@BUILDPPCASM_TRUE@@HAVE_LINUX_FALSE@ppcasm_sources = ppcasm_memcpy.S +@BUILDPPCASM_TRUE@@HAVE_LINUX_TRUE@ppcasm_sources = ppcasm_memcpy.S ppcasm_memcpy_cachable.S +@BUILDPPCASM_TRUE@ppcasm_headers = ppcasm_memcpy.h ppc_asm.h +@BUILDARMASM_TRUE@armasm_sources = armasm_memcpy.S +@BUILDARMASM_TRUE@armasm_header = armasm_memcpy.h +include_HEADERS = \ + $(ppcasm_headers) \ + $(armasm_headers) \ + build.h \ + clock.h \ + conf.h \ + debug.h \ + direct.h \ + hash.h \ + interface.h \ + interface_implementation.h \ + list.h \ + log.h \ + mem.h \ + memcpy.h \ + messages.h \ + modules.h \ + serial.h \ + signals.h \ + stream.h \ + system.h \ + thread.h \ + trace.h \ + tree.h \ + types.h \ + utf8.h \ + util.h + +lib_LTLIBRARIES = libdirect.la +libdirect_la_SOURCES = \ + $(ppcasm_sources) \ + $(armasm_sources) \ + clock.c \ + conf.c \ + debug.c \ + direct.c \ + hash.c \ + interface.c \ + list.c \ + log.c \ + mem.c \ + memcpy.c \ + messages.c \ + modules.c \ + signals.c \ + stream.c \ + system.c \ + trace.c \ + tree.c \ + thread.c \ + utf8.c \ + util.c + +libdirect_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-am + +.SUFFIXES: +.SUFFIXES: .S .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/direct/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu lib/direct/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)/$@ +direct.pc: $(top_builddir)/config.status $(srcdir)/direct.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 +libdirect.la: $(libdirect_la_OBJECTS) $(libdirect_la_DEPENDENCIES) + $(libdirect_la_LINK) -rpath $(libdir) $(libdirect_la_OBJECTS) $(libdirect_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/armasm_memcpy.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/clock.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/direct.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mem.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memcpy.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/messages.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/modules.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppcasm_memcpy.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ppcasm_memcpy_cachable.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signals.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stream.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/system.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trace.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tree.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utf8.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Plo@am__quote@ + +.S.o: +@am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCCAS_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(CPPASCOMPILE) -c -o $@ $< + +.S.obj: +@am__fastdepCCAS_TRUE@ $(CPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCCAS_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(CPPASCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.S.lo: +@am__fastdepCCAS_TRUE@ $(LTCPPASCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCCAS_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCCAS_FALSE@ DEPDIR=$(DEPDIR) $(CCASDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCCAS_FALSE@ $(LTCPPASCOMPILE) -c -o $@ $< + +.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 + +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) $(DATA) $(HEADERS) all-local +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(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." +@BUILD_SHARED_FALSE@install-data-local: +@ENABLE_TRACE_FALSE@install-data-local: +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ + 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-data-local install-includeHEADERS \ + install-pkgconfigDATA + +install-dvi: install-dvi-am + +install-exec-am: install-exec-local install-libLTLIBRARIES + +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 uninstall-libLTLIBRARIES \ + uninstall-pkgconfigDATA + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ + 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-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 \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags 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)/direct + +# +# + +@BUILD_STATIC_TRUE@clean-local: +@BUILD_STATIC_TRUE@ rm -f libdirect_fixed.a + +@BUILD_STATIC_TRUE@all-local: libdirect_fixed.a + +@BUILD_STATIC_TRUE@libdirect_fixed.a: .libs/libdirect.a +@BUILD_STATIC_TRUE@ rm -f libdirect_fixed.a +@BUILD_STATIC_TRUE@ ${AR} cru libdirect_fixed.a `find . -name "*.o" | grep -v '.libs' | grep -v dtest` +@BUILD_STATIC_TRUE@ ${RANLIB} libdirect_fixed.a +@BUILD_STATIC_TRUE@ cp -pf libdirect_fixed.a .libs/libdirect.a + +@BUILD_STATIC_TRUE@.libs/libdirect.a: libdirect.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/direct/armasm_memcpy.S b/Source/DirectFB/lib/direct/armasm_memcpy.S new file mode 100755 index 0000000..e422168 --- /dev/null +++ b/Source/DirectFB/lib/direct/armasm_memcpy.S @@ -0,0 +1,421 @@ +/* + * ARM memcpy asm replacement. + * + * Copyright (C) 2009 Bluush Dev Team. + * + * 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 + +#if USE_ARMASM && !WORDS_BIGENDIAN + +#define _LABEL(f) f : + +.global direct_armasm_memcpy + + .code 32 + +_LABEL(direct_armasm_memcpy) + cmp r1, r0 + bcc Lmemcpy_backwards + + moveq r0, #0 + moveq pc, lr + + stmdb sp!, {r0, lr} + subs r2, r2, #4 + blt Lmemcpy_fl4 + ands r12, r0, #3 + bne Lmemcpy_fdestul + ands r12, r1, #3 + bne Lmemcpy_fsrcul + +_LABEL(Lmemcpy_ft8) + subs r2, r2, #8 + blt Lmemcpy_fl12 + subs r2, r2, #0x14 + blt Lmemcpy_fl32 + stmdb sp!, {r4} + +_LABEL(Lmemcpy_floop32) + ldmia r1!, {r3, r4, r12, lr} + stmia r0!, {r3, r4, r12, lr} + ldmia r1!, {r3, r4, r12, lr} + stmia r0!, {r3, r4, r12, lr} + subs r2, r2, #0x20 + bge Lmemcpy_floop32 + + cmn r2, #0x10 + ldmgeia r1!, {r3, r4, r12, lr} + stmgeia r0!, {r3, r4, r12, lr} + subge r2, r2, #0x10 + ldmia sp!, {r4} + +_LABEL(Lmemcpy_fl32) + adds r2, r2, #0x14 + + +_LABEL(Lmemcpy_floop12) + ldmgeia r1!, {r3, r12, lr} + stmgeia r0!, {r3, r12, lr} + subges r2, r2, #0x0c + bge Lmemcpy_floop12 + +_LABEL(Lmemcpy_fl12) + adds r2, r2, #8 + blt Lmemcpy_fl4 + + subs r2, r2, #4 + ldrlt r3, [r1], #4 + strlt r3, [r0], #4 + ldmgeia r1!, {r3, r12} + stmgeia r0!, {r3, r12} + subge r2, r2, #4 + +_LABEL(Lmemcpy_fl4) + adds r2, r2, #4 + ldmeqia sp!, {r0, pc} + + cmp r2, #2 + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrgeb r3, [r1], #1 + strgeb r3, [r0], #1 + ldrgtb r3, [r1], #1 + strgtb r3, [r0], #1 + ldmia sp!, {r0, pc} + + +_LABEL(Lmemcpy_fdestul) + rsb r12, r12, #4 + cmp r12, #2 + + ldrb r3, [r1], #1 + strb r3, [r0], #1 + ldrgeb r3, [r1], #1 + strgeb r3, [r0], #1 + ldrgtb r3, [r1], #1 + strgtb r3, [r0], #1 + subs r2, r2, r12 + blt Lmemcpy_fl4 + + ands r12, r1, #3 + beq Lmemcpy_ft8 + + +_LABEL(Lmemcpy_fsrcul) + bic r1, r1, #3 + ldr lr, [r1], #4 + cmp r12, #2 + bgt Lmemcpy_fsrcul3 + beq Lmemcpy_fsrcul2 + cmp r2, #0x0c + blt Lmemcpy_fsrcul1loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5} + +_LABEL(Lmemcpy_fsrcul1loop16) + mov r3, lr, lsr #8 + ldmia r1!, {r4, r5, r12, lr} + orr r3, r3, r4, lsl #24 + mov r4, r4, lsr #8 + orr r4, r4, r5, lsl #24 + mov r5, r5, lsr #8 + orr r5, r5, r12, lsl #24 + mov r12, r12, lsr #8 + orr r12, r12, lr, lsl #24 + stmia r0!, {r3-r5, r12} + subs r2, r2, #0x10 + bge Lmemcpy_fsrcul1loop16 + ldmia sp!, {r4, r5} + adds r2, r2, #0x0c + blt Lmemcpy_fsrcul1l4 + +_LABEL(Lmemcpy_fsrcul1loop4) + mov r12, lr, lsr #8 + ldr lr, [r1], #4 + orr r12, r12, lr, lsl #24 + str r12, [r0], #4 + subs r2, r2, #4 + bge Lmemcpy_fsrcul1loop4 + +_LABEL(Lmemcpy_fsrcul1l4) + sub r1, r1, #3 + b Lmemcpy_fl4 + +_LABEL(Lmemcpy_fsrcul2) + cmp r2, #0x0c + blt Lmemcpy_fsrcul2loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5} + +_LABEL(Lmemcpy_fsrcul2loop16) + mov r3, lr, lsr #16 + ldmia r1!, {r4, r5, r12, lr} + orr r3, r3, r4, lsl #16 + mov r4, r4, lsr #16 + orr r4, r4, r5, lsl #16 + mov r5, r5, lsr #16 + orr r5, r5, r12, lsl #16 + mov r12, r12, lsr #16 + orr r12, r12, lr, lsl #16 + stmia r0!, {r3-r5, r12} + subs r2, r2, #0x10 + bge Lmemcpy_fsrcul2loop16 + ldmia sp!, {r4, r5} + adds r2, r2, #0x0c + blt Lmemcpy_fsrcul2l4 + +_LABEL(Lmemcpy_fsrcul2loop4) + mov r12, lr, lsr #16 + ldr lr, [r1], #4 + orr r12, r12, lr, lsl #16 + str r12, [r0], #4 + subs r2, r2, #4 + bge Lmemcpy_fsrcul2loop4 + +_LABEL(Lmemcpy_fsrcul2l4) + sub r1, r1, #2 + b Lmemcpy_fl4 + +_LABEL(Lmemcpy_fsrcul3) + cmp r2, #0x0c + blt Lmemcpy_fsrcul3loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5} + +_LABEL(Lmemcpy_fsrcul3loop16) + mov r3, lr, lsr #24 + ldmia r1!, {r4, r5, r12, lr} + orr r3, r3, r4, lsl #8 + mov r4, r4, lsr #24 + orr r4, r4, r5, lsl #8 + mov r5, r5, lsr #24 + orr r5, r5, r12, lsl #8 + mov r12, r12, lsr #24 + orr r12, r12, lr, lsl #8 + stmia r0!, {r3-r5, r12} + subs r2, r2, #0x10 + bge Lmemcpy_fsrcul3loop16 + ldmia sp!, {r4, r5} + adds r2, r2, #0x0c + blt Lmemcpy_fsrcul3l4 + +_LABEL(Lmemcpy_fsrcul3loop4) + mov r12, lr, lsr #24 + ldr lr, [r1], #4 + orr r12, r12, lr, lsl #8 + str r12, [r0], #4 + subs r2, r2, #4 + bge Lmemcpy_fsrcul3loop4 + +_LABEL(Lmemcpy_fsrcul3l4) + sub r1, r1, #1 + b Lmemcpy_fl4 + +_LABEL(Lmemcpy_backwards) + add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt Lmemcpy_bl4 + ands r12, r0, #3 + bne Lmemcpy_bdestul + ands r12, r1, #3 + bne Lmemcpy_bsrcul + +_LABEL(Lmemcpy_bt8) + subs r2, r2, #8 + blt Lmemcpy_bl12 + stmdb sp!, {r4, lr} + subs r2, r2, #0x14 + blt Lmemcpy_bl32 + + +_LABEL(Lmemcpy_bloop32) + ldmdb r1!, {r3, r4, r12, lr} + stmdb r0!, {r3, r4, r12, lr} + ldmdb r1!, {r3, r4, r12, lr} + stmdb r0!, {r3, r4, r12, lr} + subs r2, r2, #0x20 + bge Lmemcpy_bloop32 + +_LABEL(Lmemcpy_bl32) + cmn r2, #0x10 + ldmgedb r1!, {r3, r4, r12, lr} + stmgedb r0!, {r3, r4, r12, lr} + subge r2, r2, #0x10 + adds r2, r2, #0x14 + ldmgedb r1!, {r3, r12, lr} + stmgedb r0!, {r3, r12, lr} + subge r2, r2, #0x0c + ldmia sp!, {r4, lr} + +_LABEL(Lmemcpy_bl12) + adds r2, r2, #8 + blt Lmemcpy_bl4 + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + strlt r3, [r0, #-4]! + ldmgedb r1!, {r3, r12} + stmgedb r0!, {r3, r12} + subge r2, r2, #4 + +_LABEL(Lmemcpy_bl4) + adds r2, r2, #4 + moveq pc, lr + + cmp r2, #2 + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrgeb r3, [r1, #-1]! + strgeb r3, [r0, #-1]! + ldrgtb r3, [r1, #-1]! + strgtb r3, [r0, #-1]! + mov pc, lr + + +_LABEL(Lmemcpy_bdestul) + cmp r12, #2 + + ldrb r3, [r1, #-1]! + strb r3, [r0, #-1]! + ldrgeb r3, [r1, #-1]! + strgeb r3, [r0, #-1]! + ldrgtb r3, [r1, #-1]! + strgtb r3, [r0, #-1]! + subs r2, r2, r12 + blt Lmemcpy_bl4 + ands r12, r1, #3 + beq Lmemcpy_bt8 + + +_LABEL(Lmemcpy_bsrcul) + bic r1, r1, #3 + ldr r3, [r1, #0] + cmp r12, #2 + blt Lmemcpy_bsrcul1 + beq Lmemcpy_bsrcul2 + cmp r2, #0x0c + blt Lmemcpy_bsrcul3loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5, lr} + +_LABEL(Lmemcpy_bsrcul3loop16) + mov lr, r3, lsl #8 + ldmdb r1!, {r3-r5, r12} + orr lr, lr, r12, lsr #24 + mov r12, r12, lsl #8 + orr r12, r12, r5, lsr #24 + mov r5, r5, lsl #8 + orr r5, r5, r4, lsr #24 + mov r4, r4, lsl #8 + orr r4, r4, r3, lsr #24 + stmdb r0!, {r4, r5, r12, lr} + subs r2, r2, #0x10 + bge Lmemcpy_bsrcul3loop16 + ldmia sp!, {r4, r5, lr} + adds r2, r2, #0x0c + blt Lmemcpy_bsrcul3l4 + +_LABEL(Lmemcpy_bsrcul3loop4) + mov r12, r3, lsl #8 + ldr r3, [r1, #-4]! + orr r12, r12, r3, lsr #24 + str r12, [r0, #-4]! + subs r2, r2, #4 + bge Lmemcpy_bsrcul3loop4 + +_LABEL(Lmemcpy_bsrcul3l4) + add r1, r1, #3 + b Lmemcpy_bl4 + +_LABEL(Lmemcpy_bsrcul2) + cmp r2, #0x0c + blt Lmemcpy_bsrcul2loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5, lr} + +_LABEL(Lmemcpy_bsrcul2loop16) + mov lr, r3, lsl #16 + ldmdb r1!, {r3-r5, r12} + orr lr, lr, r12, lsr #16 + mov r12, r12, lsl #16 + orr r12, r12, r5, lsr #16 + mov r5, r5, lsl #16 + orr r5, r5, r4, lsr #16 + mov r4, r4, lsl #16 + orr r4, r4, r3, lsr #16 + stmdb r0!, {r4, r5, r12, lr} + subs r2, r2, #0x10 + bge Lmemcpy_bsrcul2loop16 + ldmia sp!, {r4, r5, lr} + adds r2, r2, #0x0c + blt Lmemcpy_bsrcul2l4 + +_LABEL(Lmemcpy_bsrcul2loop4) + mov r12, r3, lsl #16 + ldr r3, [r1, #-4]! + orr r12, r12, r3, lsr #16 + str r12, [r0, #-4]! + subs r2, r2, #4 + bge Lmemcpy_bsrcul2loop4 + +_LABEL(Lmemcpy_bsrcul2l4) + add r1, r1, #2 + b Lmemcpy_bl4 + +_LABEL(Lmemcpy_bsrcul1) + cmp r2, #0x0c + blt Lmemcpy_bsrcul1loop4 + sub r2, r2, #0x0c + stmdb sp!, {r4, r5, lr} + +_LABEL(Lmemcpy_bsrcul1loop32) + mov lr, r3, lsl #24 + ldmdb r1!, {r3-r5, r12} + orr lr, lr, r12, lsr #8 + mov r12, r12, lsl #24 + orr r12, r12, r5, lsr #8 + mov r5, r5, lsl #24 + orr r5, r5, r4, lsr #8 + mov r4, r4, lsl #24 + orr r4, r4, r3, lsr #8 + stmdb r0!, {r4, r5, r12, lr} + subs r2, r2, #0x10 + bge Lmemcpy_bsrcul1loop32 + ldmia sp!, {r4, r5, lr} + adds r2, r2, #0x0c + blt Lmemcpy_bsrcul1l4 + +_LABEL(Lmemcpy_bsrcul1loop4) + mov r12, r3, lsl #24 + ldr r3, [r1, #-4]! + orr r12, r12, r3, lsr #8 + str r12, [r0, #-4]! + subs r2, r2, #4 + bge Lmemcpy_bsrcul1loop4 + +_LABEL(Lmemcpy_bsrcul1l4) + add r1, r1, #1 + b Lmemcpy_bl4 + + + .ltorg + +#endif /* USE_ARMASM && !WORDS_BIGENDIAN */ + + diff --git a/Source/DirectFB/lib/direct/armasm_memcpy.h b/Source/DirectFB/lib/direct/armasm_memcpy.h new file mode 100755 index 0000000..27138ab --- /dev/null +++ b/Source/DirectFB/lib/direct/armasm_memcpy.h @@ -0,0 +1,32 @@ +/* + * ARM memcpy asm replacement. + * + * Copyright (C) 2009 Bluush Dev Team. + * + * 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 __ARMASM_MEMCPY_H__ +#define __ARMASM_MEMCPY_H__ + +#if USE_ARMASM && !WORDS_BIGENDIAN + +void *direct_armasm_memcpy ( void *dest, const void *src, size_t n); + +#endif /* USE_ARMASM && !WORDS_BIGENDIAN */ + +#endif /* __ARMASM_MEMCPY_H__ */ + diff --git a/Source/DirectFB/lib/direct/build.h.in b/Source/DirectFB/lib/direct/build.h.in new file mode 100755 index 0000000..926cea5 --- /dev/null +++ b/Source/DirectFB/lib/direct/build.h.in @@ -0,0 +1,51 @@ +/* + (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 __DIRECT__BUILD_H__ +#define __DIRECT__BUILD_H__ + +#define DIRECT_BUILD_DEBUG (@DIRECT_BUILD_DEBUG@) +#define DIRECT_BUILD_DEBUGS (@DIRECT_BUILD_DEBUGS@) +#define DIRECT_BUILD_TRACE (@DIRECT_BUILD_TRACE@) +#define DIRECT_BUILD_TEXT (@DIRECT_BUILD_TEXT@) +#define DIRECT_BUILD_GETTID (@DIRECT_BUILD_GETTID@) +#define DIRECT_BUILD_NETWORK (@DIRECT_BUILD_NETWORK@) +#define DIRECT_BUILD_STDBOOL (@DIRECT_BUILD_STDBOOL@) + + +#if !DIRECT_BUILD_DEBUGS +#if defined(DIRECT_ENABLE_DEBUG) || defined(DIRECT_FORCE_DEBUG) +#define DIRECT_MINI_DEBUG +#endif +#undef DIRECT_ENABLE_DEBUG +#ifdef DIRECT_FORCE_DEBUG +#warning DIRECT_FORCE_DEBUG used with 'pure release' library headers. +#undef DIRECT_FORCE_DEBUG +#endif +#endif + +#endif diff --git a/Source/DirectFB/lib/direct/clock.c b/Source/DirectFB/lib/direct/clock.c new file mode 100755 index 0000000..e77bfe2 --- /dev/null +++ b/Source/DirectFB/lib/direct/clock.c @@ -0,0 +1,135 @@ +/* + (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 + +#ifdef CLOCK_MONOTONIC +#include +#endif +#include +#include + +D_DEBUG_DOMAIN( Direct_Clock, "Direct/Clock", "Time measurement etc." ); + +static struct timeval start_time = { 0, 0 }; + +/* libc has incredibly messy way of doing this, + * typically requiring -lrt. We just skip all this mess */ +struct timeval* +direct_monotonic_gettimeofday( struct timeval *tv ) +{ + struct timespec ts; + +#ifdef CLOCK_MONOTONIC + /* No locking or atomic ops for no_monotonic here */ + static int no_monotonic = 0; + + if (!no_monotonic) + if(syscall( __NR_clock_gettime, CLOCK_MONOTONIC, &ts )) + no_monotonic = 1; + + if (no_monotonic) + if(syscall(__NR_clock_gettime, CLOCK_REALTIME, &ts)) +#endif + { + gettimeofday( tv, NULL ); + return tv; + } + + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; + + return tv; +} + +long long +direct_clock_get_micros( void ) +{ + struct timeval tv; + long long ret; + + if (start_time.tv_sec == 0) { + direct_monotonic_gettimeofday( &start_time ); + return 0; + } + + direct_monotonic_gettimeofday( &tv ); + + ret = (long long)(tv.tv_sec - start_time.tv_sec) * 1000000LL + + (long long)(tv.tv_usec - start_time.tv_usec); + if (ret < 0) { + D_DEBUG_AT( Direct_Clock, "Clock skew detected (%lld in the past)!\n", -ret ); + start_time = tv; + ret = 0; + } + + return ret; +} + +long long +direct_clock_get_millis( void ) +{ + return direct_clock_get_micros() / 1000LL; +} + +void +direct_clock_set_start( const struct timeval *start ) +{ + long long diff; + + D_ASSERT( start != NULL ); + + diff = (long long)(start->tv_sec - start_time.tv_sec) * 1000LL + + (long long)(start->tv_usec - start_time.tv_usec) / 1000LL; + + D_DEBUG_AT( Direct_Clock, "Adjusting start time " + "(%lld.%lld seconds diff)\n", diff / 1000LL, ABS(diff) % 1000LL ); + + start_time = *start; +} + +long long +direct_clock_get_abs_micros( void ) +{ + struct timeval tv; + + direct_monotonic_gettimeofday( &tv ); + + return (long long)(tv.tv_sec) * 1000000LL + (long long)(tv.tv_usec); +} + +long long +direct_clock_get_abs_millis( void ) +{ + return direct_clock_get_abs_micros() / 1000LL; +} + diff --git a/Source/DirectFB/lib/direct/clock.h b/Source/DirectFB/lib/direct/clock.h new file mode 100755 index 0000000..dca6ea9 --- /dev/null +++ b/Source/DirectFB/lib/direct/clock.h @@ -0,0 +1,45 @@ +/* + (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 __DIRECT__CLOCK_H__ +#define __DIRECT__CLOCK_H__ + +#include + +struct timeval* direct_monotonic_gettimeofday( struct timeval *tv ); + +long long direct_clock_get_micros( void ); +long long direct_clock_get_millis( void ); + +void direct_clock_set_start( const struct timeval *start ); + +long long direct_clock_get_abs_micros( void ); +long long direct_clock_get_abs_millis( void ); + +#endif + diff --git a/Source/DirectFB/lib/direct/conf.c b/Source/DirectFB/lib/direct/conf.c new file mode 100755 index 0000000..8be92af --- /dev/null +++ b/Source/DirectFB/lib/direct/conf.c @@ -0,0 +1,348 @@ +/* + (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 + + +static DirectConfig config = { + .debug = false, + .trace = true, + .sighandler = true, + + .fatal = DCFL_ASSERT, + .fatal_break = true, + .thread_block_signals = true, + .thread_priority_scale = 100, +}; + +DirectConfig *direct_config = &config; +const char *direct_config_usage = + "libdirect options:\n" + " memcpy= Skip memcpy() probing (help = show list)\n" + " [no-]quiet Disable text output except debug messages or direct logs\n" + " [no-]quiet= Only quiet certain types (cumulative with 'quiet')\n" + " [ info | warning | error | once | unimplemented ]\n" + " [no-]debug Enable debug output\n" + " [no-]debugmem Enable memory allocation tracking\n" + " [no-]trace Enable stack trace support\n" + " log-file= Write all messages to a file\n" + " log-udp=: Send all messages via UDP to host:port\n" + " fatal-level= Abort on NONE, ASSERT (default) or ASSUME (incl. assert)\n" + " [no-]fatal-break Abort on BREAK (default)\n" + " dont-catch=[[,]...] Don't catch these signals\n" + " [no-]sighandler Enable signal handler\n" + " [no-]thread-block-signals Block all signals in new threads?\n" + " disable-module= suppress loading this module\n" + " module-dir= Override default module search directory (default = $libdir/directfb-x.y-z)\n" + " thread-priority-scale=<100th> Apply scaling factor on thread type based priorities\n" + "\n"; + +/**********************************************************************************************************************/ + +DirectResult +direct_config_set( const char *name, const char *value ) +{ + if (strcmp (name, "disable-module" ) == 0) { + if (value) { + int n = 0; + + while (direct_config->disable_module && + direct_config->disable_module[n]) + n++; + + direct_config->disable_module = D_REALLOC( direct_config->disable_module, + sizeof(char*) * (n + 2) ); + + direct_config->disable_module[n] = D_STRDUP( value ); + direct_config->disable_module[n+1] = NULL; + } + else { + D_ERROR("Direct/Config '%s': No module name specified!\n", name); + return DR_INVARG; + } + } else + if (strcmp (name, "module-dir" ) == 0) { + if (value) { + if (direct_config->module_dir) + D_FREE( direct_config->module_dir ); + direct_config->module_dir = D_STRDUP( value ); + } + else { + D_ERROR("Direct/Config 'module-dir': No directory name specified!\n"); + return DR_INVARG; + } + } else + if (strcmp (name, "memcpy" ) == 0) { + if (value) { + if (direct_config->memcpy) + D_FREE( direct_config->memcpy ); + direct_config->memcpy = D_STRDUP( value ); + } + else { + D_ERROR("Direct/Config '%s': No method specified!\n", name); + return DR_INVARG; + } + } + else + if (strcmp (name, "quiet" ) == 0 || strcmp (name, "no-quiet" ) == 0) { + /* Enable/disable all at once by default. */ + DirectMessageType type = DMT_ALL; + + /* Find out the specific message type being configured. */ + if (value) { + if (!strcmp( value, "info" )) type = DMT_INFO; else + if (!strcmp( value, "warning" )) type = DMT_WARNING; else + if (!strcmp( value, "error" )) type = DMT_ERROR; else + if (!strcmp( value, "once" )) type = DMT_ONCE; else + if (!strcmp( value, "unimplemented" )) type = DMT_UNIMPLEMENTED; + else { + D_ERROR( "DirectFB/Config '%s': Unknown message type '%s'!\n", name, value ); + return DR_INVARG; + } + } + + /* Set/clear the corresponding flag in the configuration. */ + if (name[0] == 'q') + direct_config->quiet |= type; + else + direct_config->quiet &= ~type; + } + else + if (strcmp (name, "no-quiet" ) == 0) { + direct_config->quiet = false; + } + else + if (strcmp (name, "debug" ) == 0) { + if (value) + direct_debug_config_domain( value, true ); + else + direct_config->debug = true; + } + else + if (strcmp (name, "no-debug" ) == 0) { + if (value) + direct_debug_config_domain( value, false ); + else + direct_config->debug = false; + } + else + if (strcmp (name, "debugmem" ) == 0) { + direct_config->debugmem = true; + } + else + if (strcmp (name, "no-debugmem" ) == 0) { + direct_config->debugmem = false; + } + else + if (strcmp (name, "trace" ) == 0) { + direct_config->trace = true; + } + else + if (strcmp (name, "no-trace" ) == 0) { + direct_config->trace = false; + } + else + if (strcmp (name, "log-file" ) == 0 || strcmp (name, "log-udp" ) == 0) { + if (value) { + DirectResult ret; + DirectLog *log; + + ret = direct_log_create( strcmp(name,"log-udp") ? DLT_FILE : DLT_UDP, value, &log ); + if (ret) + return ret; + + if (direct_config->log) + direct_log_destroy( direct_config->log ); + + direct_config->log = log; + + direct_log_set_default( log ); + } + else { + if (strcmp(name,"log-udp")) + D_ERROR("Direct/Config '%s': No file name specified!\n", name); + else + D_ERROR("Direct/Config '%s': No host and port specified!\n", name); + return DR_INVARG; + } + } + else + if (strcmp (name, "fatal-level" ) == 0) { + if (strcasecmp (value, "none" ) == 0) { + direct_config->fatal = DCFL_NONE; + } + else + if (strcasecmp (value, "assert" ) == 0) { + direct_config->fatal = DCFL_ASSERT; + } + else + if (strcasecmp (value, "assume" ) == 0) { + direct_config->fatal = DCFL_ASSUME; + } + else { + D_ERROR("Direct/Config '%s': Unknown level specified (use 'none', 'assert', 'assume')!\n", name); + return DR_INVARG; + } + } + else + if (strcmp (name, "fatal-break" ) == 0) { + direct_config->fatal_break = true; + } + else + if (strcmp (name, "no-fatal-break" ) == 0) { + direct_config->fatal_break = false; + } + else + if (strcmp (name, "sighandler" ) == 0) { + direct_config->sighandler = true; + } + else + if (strcmp (name, "no-sighandler" ) == 0) { + direct_config->sighandler = false; + } + else + if (strcmp (name, "dont-catch" ) == 0) { + if (value) { + char *signals = D_STRDUP( value ); + char *p = NULL, *r, *s = signals; + + while ((r = strtok_r( s, ",", &p ))) { + char *error; + unsigned long signum; + + direct_trim( &r ); + + signum = strtoul( r, &error, 10 ); + + if (*error) { + D_ERROR( "Direct/Config '%s': Error in number at '%s'!\n", name, error ); + D_FREE( signals ); + return DR_INVARG; + } + + sigaddset( &direct_config->dont_catch, signum ); + + s = NULL; + } + + D_FREE( signals ); + } + else { + D_ERROR("Direct/Config '%s': No signals specified!\n", name); + return DR_INVARG; + } + } + else + if (strcmp (name, "thread_block_signals") == 0) { + direct_config->thread_block_signals = true; + } + else + if (strcmp (name, "no-thread_block_signals") == 0) { + direct_config->thread_block_signals = false; + } else + if (strcmp (name, "thread-priority-scale" ) == 0) { + if (value) { + int scale; + + if (sscanf( value, "%d", &scale ) < 1) { + D_ERROR("Direct/Config '%s': Could not parse value!\n", name); + return DR_INVARG; + } + + direct_config->thread_priority_scale = scale; + } + else { + D_ERROR("Direct/Config '%s': No value specified!\n", name); + return DR_INVARG; + } + } else + if (strcmp (name, "thread-priority" ) == 0) { /* Must be moved to lib/direct/conf.c in trunk! */ + if (value) { + int priority; + + if (sscanf( value, "%d", &priority ) < 1) { + D_ERROR("Direct/Config '%s': Could not parse value!\n", name); + return DR_INVARG; + } + + direct_config->thread_priority = priority; + } + else { + D_ERROR("Direct/Config '%s': No value specified!\n", name); + return DR_INVARG; + } + } else + if (strcmp (name, "thread-scheduler" ) == 0) { /* Must be moved to lib/direct/conf.c in trunk! */ + if (value) { + if (strcmp( value, "other" ) == 0) { + direct_config->thread_scheduler = DCTS_OTHER; + } else + if (strcmp( value, "fifo" ) == 0) { + direct_config->thread_scheduler = DCTS_FIFO; + } else + if (strcmp( value, "rr" ) == 0) { + direct_config->thread_scheduler = DCTS_RR; + } else { + D_ERROR( "Direct/Config '%s': Unknown scheduler '%s'!\n", name, value ); + return DR_INVARG; + } + } + else { + D_ERROR( "Direct/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "thread-stacksize" ) == 0) { /* Must be moved to lib/direct/conf.c in trunk! */ + if (value) { + int size; + + if (sscanf( value, "%d", &size ) < 1) { + D_ERROR( "Direct/Config '%s': Could not parse value!\n", name ); + return DR_INVARG; + } + + direct_config->thread_stack_size = size; + } + else { + D_ERROR( "Direct/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } + else + return DR_UNSUPPORTED; + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/direct/conf.h b/Source/DirectFB/lib/direct/conf.h new file mode 100755 index 0000000..ef1230e --- /dev/null +++ b/Source/DirectFB/lib/direct/conf.h @@ -0,0 +1,92 @@ +/* + (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 __DIRECT__CONF_H__ +#define __DIRECT__CONF_H__ + + +#include + +#if HAVE_SIGNAL_H +#include +#else +#include +#endif + +typedef enum { + DCFL_NONE, /* None is fatal. */ + DCFL_ASSERT, /* ASSERT is fatal. */ + DCFL_ASSUME /* ASSERT and ASSUME are fatal. */ +} DirectConfigFatalLevel; + +typedef enum { + DCTS_OTHER, + DCTS_FIFO, + DCTS_RR +} DirectConfigThreadScheduler; + +struct __D_DirectConfig { + DirectMessageType quiet; + bool debug; + bool trace; + + char *memcpy; /* Don't probe for memcpy routines to save a lot of + startup time. Use this one instead if it's set. */ + + char **disable_module; /* Never load these modules. */ + char *module_dir; /* module dir override */ + + bool sighandler; + sigset_t dont_catch; /* don't catch these signals */ + + DirectLog *log; + + DirectConfigFatalLevel fatal; + + bool debugmem; + + bool thread_block_signals; + + bool fatal_break; /* Should D_BREAK() cause a trap? */ + + int thread_priority; + DirectConfigThreadScheduler thread_scheduler; + int thread_stack_size; + int thread_priority_scale; +}; + +extern DirectConfig *direct_config; + +extern const char *direct_config_usage; + + +DirectResult direct_config_set( const char *name, const char *value ); + + +#endif + diff --git a/Source/DirectFB/lib/direct/debug.c b/Source/DirectFB/lib/direct/debug.c new file mode 100755 index 0000000..6aad0a1 --- /dev/null +++ b/Source/DirectFB/lib/direct/debug.c @@ -0,0 +1,430 @@ +/* + (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 + + +#if DIRECT_BUILD_TEXT + +#if DIRECT_BUILD_DEBUGS /* Build with debug support? */ + +typedef struct { + DirectLink link; + char *name; + bool enabled; +} DebugDomainEntry; + +/**************************************************************************************************/ + +static pthread_mutex_t domains_lock = PTHREAD_MUTEX_INITIALIZER; +static unsigned int domains_age = 1; +static DirectLink *domains = NULL; + +/**************************************************************************************************/ + +__attribute__((no_instrument_function)) +static inline DebugDomainEntry * +lookup_domain( const char *name, bool sub ) +{ + DebugDomainEntry *entry; + + direct_list_foreach (entry, domains) { + if (! strcasecmp( entry->name, name )) + return entry; + } + + /* + * If the domain being registered contains a slash, but didn't exactly match an entry + * in directfbrc, check to see if the domain is descended from an entry in directfbrc + * (e.g. 'ui/field/messages' matches 'ui' or 'ui/field') + */ + if (sub && strchr(name, '/')) { + int passed_name_len = strlen( name ); + + direct_list_foreach (entry, domains) { + int entry_len = strlen( entry->name ); + if ((passed_name_len > entry_len) && + (name[entry_len] == '/') && + (! strncasecmp( entry->name, name, entry_len))) { + return entry; + } + } + } + + return NULL; +} + +__attribute__((no_instrument_function)) +static inline bool +check_domain( DirectDebugDomain *domain ) +{ + if (domain->age != domains_age) { + DebugDomainEntry *entry = lookup_domain( domain->name, true ); + + domain->age = domains_age; + + if (entry) { + domain->registered = true; + domain->enabled = entry->enabled; + } + } + + return domain->registered ? domain->enabled : direct_config->debug; +} + +#endif /* DIRECT_BUILD_DEBUGS */ + +/**************************************************************************************************/ + +void +direct_debug_config_domain( const char *name, bool enable ) +{ +#if DIRECT_BUILD_DEBUGS /* Build with debug support? */ + DebugDomainEntry *entry; + + pthread_mutex_lock( &domains_lock ); + + entry = lookup_domain( name, false ); + if (!entry) { + entry = calloc( 1, sizeof(DebugDomainEntry) ); + if (!entry) { + D_WARN( "out of memory" ); + pthread_mutex_unlock( &domains_lock ); + return; + } + + entry->name = strdup( name ); + + direct_list_prepend( &domains, &entry->link ); + } + + entry->enabled = enable; + + if (! ++domains_age) + domains_age++; + + pthread_mutex_unlock( &domains_lock ); +#endif /* DIRECT_BUILD_DEBUGS */ +} + +/**************************************************************************************************/ + +__attribute__((no_instrument_function)) +static inline void +debug_domain_vprintf( const char *name, + int name_len, + const char *format, + va_list ap ) +{ + char buf[512]; + long long millis = direct_clock_get_millis(); + const char *thread = direct_thread_self_name(); + int indent = direct_trace_debug_indent() * 4; + + /* Prepare user message. */ + vsnprintf( buf, sizeof(buf), format, ap ); + + /* Fill up domain name column after the colon, prepending remaining space (excl. ': ') to indent. */ + indent += (name_len < 20 ? 20 : 36) - name_len - 2; + + /* Print full message. */ + direct_log_printf( NULL, "(-) [%-15s %3lld.%03lld] (%5d) %s: %*s%s", thread ? thread : " NO NAME", + millis / 1000LL, millis % 1000LL, direct_gettid(), name, indent, "", buf ); +} + +#if DIRECT_BUILD_DEBUGS /* Build with debug support? */ + +__attribute__((no_instrument_function)) +void +direct_debug( const char *format, ... ) +{ + va_list ap; + + va_start( ap, format ); + + debug_domain_vprintf( "- - ", 4, format, ap ); + + va_end( ap ); +} + +__attribute__((no_instrument_function)) +void +direct_debug_at( DirectDebugDomain *domain, + const char *format, ... ) +{ + bool enabled; + + pthread_mutex_lock( &domains_lock ); + + enabled = check_domain( domain ); + + pthread_mutex_unlock( &domains_lock ); + + if (enabled) { + va_list ap; + + va_start( ap, format ); + + debug_domain_vprintf( domain->name, domain->name_len, format, ap ); + + va_end( ap ); + } +} + +#endif /* DIRECT_BUILD_DEBUGS */ + +__attribute__((no_instrument_function)) +void +direct_debug_at_always( DirectDebugDomain *domain, + const char *format, ... ) +{ + va_list ap; + + va_start( ap, format ); + + debug_domain_vprintf( domain->name, domain->name_len, format, ap ); + + va_end( ap ); +} + +#if DIRECT_BUILD_DEBUGS /* Build with debug support? */ + +__attribute__((no_instrument_function)) +void +direct_debug_enter( DirectDebugDomain *domain, + const char *func, + const char *file, + int line, + const char *format, ... ) +{ + bool enabled; + + pthread_mutex_lock( &domains_lock ); + + enabled = check_domain( domain ); + + pthread_mutex_unlock( &domains_lock ); + + if (enabled) { + int len; + char dom[48]; + char fmt[128]; + char buf[512]; + long long millis = direct_clock_get_millis(); + const char *name = direct_thread_self_name(); + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + + len = snprintf( dom, sizeof(dom), "%s:", domain->name ); + + if (len < 18) + len = 18; + else + len = 28; + + len += direct_trace_debug_indent() * 4; + + snprintf( fmt, sizeof(fmt), "(>) [%%-15s %%3lld.%%03lld] (%%5d) %%-%ds Entering %%s%%s [%%s:%%d]\n", len ); + + direct_log_printf( NULL, fmt, name ? name : " NO NAME ", + millis / 1000LL, millis % 1000LL, direct_gettid(), dom, + func, buf, file, line ); + } +} + +__attribute__((no_instrument_function)) +void +direct_debug_exit( DirectDebugDomain *domain, + const char *func, + const char *file, + int line, + const char *format, ... ) +{ + bool enabled; + + pthread_mutex_lock( &domains_lock ); + + enabled = check_domain( domain ); + + pthread_mutex_unlock( &domains_lock ); + + if (enabled) { + int len; + char dom[48]; + char fmt[128]; + char buf[512]; + long long millis = direct_clock_get_millis(); + const char *name = direct_thread_self_name(); + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + + len = snprintf( dom, sizeof(dom), "%s:", domain->name ); + + if (len < 18) + len = 18; + else + len = 28; + + len += direct_trace_debug_indent() * 4; + + snprintf( fmt, sizeof(fmt), "(<) [%%-15s %%3lld.%%03lld] (%%5d) %%-%ds Returning from %%s%%s [%%s:%%d]\n", len ); + + direct_log_printf( NULL, fmt, name ? name : " NO NAME ", + millis / 1000LL, millis % 1000LL, direct_gettid(), dom, + func, buf, file, line ); + } +} + +__attribute__((no_instrument_function)) +static void +trap( const char *domain ) +{ + D_DEBUG( "Direct/%s: Raising SIGTRAP...\n", domain ); + + raise( SIGTRAP ); + + D_DEBUG( "Direct/%s: ...didn't catch signal on my own, calling killpg().\n", domain ); + + kill( direct_gettid(), SIGTRAP ); + + D_DEBUG( "Direct/%s: ...still running, calling pthread_exit().\n", domain ); + + pthread_exit( NULL ); +} + +__attribute__((no_instrument_function)) +void +direct_break( const char *func, + const char *file, + int line, + const char *format, ... ) +{ + char buf[512]; + long long millis = direct_clock_get_millis(); + const char *name = direct_thread_self_name(); + + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + direct_log_printf( NULL, + "(!) [%-15s %3lld.%03lld] (%5d) *** Break [%s] *** [%s:%d in %s()]\n", + name ? name : " NO NAME ", millis / 1000LL, millis % 1000LL, + direct_gettid(), buf, file, line, func ); + + direct_trace_print_stack( NULL ); + + if (direct_config->fatal_break) + trap( "Break" ); +} + +__attribute__((no_instrument_function)) +void +direct_assertion( const char *exp, + const char *func, + const char *file, + int line ) +{ + long long millis = direct_clock_get_millis(); + const char *name = direct_thread_self_name(); + + direct_log_printf( NULL, + "(!) [%-15s %3lld.%03lld] (%5d) *** Assertion [%s] failed *** [%s:%d in %s()]\n", + name ? name : " NO NAME ", millis / 1000LL, millis % 1000LL, + direct_gettid(), exp, file, line, func ); + + direct_trace_print_stack( NULL ); + + if (direct_config->fatal >= DCFL_ASSERT) + trap( "Assertion" ); +} + +__attribute__((no_instrument_function)) +void +direct_assumption( const char *exp, + const char *func, + const char *file, + int line ) +{ + long long millis = direct_clock_get_millis(); + const char *name = direct_thread_self_name(); + + direct_log_printf( NULL, + "(!) [%-15s %3lld.%03lld] (%5d) *** Assumption [%s] failed *** [%s:%d in %s()]\n", + name ? name : " NO NAME ", millis / 1000LL, millis % 1000LL, + direct_gettid(), exp, file, line, func ); + + direct_trace_print_stack( NULL ); + + if (direct_config->fatal >= DCFL_ASSUME) + trap( "Assumption" ); +} + +#endif /* DIRECT_BUILD_DEBUGS */ + +#else + +void +direct_debug_config_domain( const char *name, bool enable ) +{ +} + +#endif /* DIRECT_BUILD_TEXT */ + diff --git a/Source/DirectFB/lib/direct/debug.h b/Source/DirectFB/lib/direct/debug.h new file mode 100755 index 0000000..1232716 --- /dev/null +++ b/Source/DirectFB/lib/direct/debug.h @@ -0,0 +1,287 @@ +/* + (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 __DIRECT__DEBUG_H__ +#define __DIRECT__DEBUG_H__ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + + +typedef struct { + unsigned int age; + bool enabled; + bool registered; + + const char *name; + const char *description; + + int name_len; +} DirectDebugDomain; + +void direct_debug_config_domain( const char *name, bool enable ); + + +#if DIRECT_BUILD_TEXT + +#define D_DEBUG_DOMAIN(identifier,name,description) \ + static DirectDebugDomain identifier __attribute__((unused)) \ + = { 0, false, false, name, description, sizeof(name) - 1 } + +void direct_debug_at_always( DirectDebugDomain *domain, + const char *format, ... ) D_FORMAT_PRINTF(2); + +#define d_debug_at( domain, x... ) direct_debug_at_always( &domain, x ) + + +#if DIRECT_BUILD_DEBUGS + +void direct_debug( const char *format, ... ) D_FORMAT_PRINTF(1); + +void direct_debug_at( DirectDebugDomain *domain, + const char *format, ... ) D_FORMAT_PRINTF(2); + +void direct_debug_enter( DirectDebugDomain *domain, + const char *func, + const char *file, + int line, + const char *format, ... ) D_FORMAT_PRINTF(5); + +void direct_debug_exit( DirectDebugDomain *domain, + const char *func, + const char *file, + int line, + const char *format, ... ) D_FORMAT_PRINTF(5); + +void direct_break( const char *func, + const char *file, + int line, + const char *format, ... ) D_FORMAT_PRINTF(4); + +void direct_assertion( const char *exp, + const char *func, + const char *file, + int line ); + +void direct_assumption( const char *exp, + const char *func, + const char *file, + int line ); +#endif + +#if DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) || defined(DIRECT_FORCE_DEBUG) + +#define D_DEBUG_ENABLED (1) + +#define D_DEBUG(x...) \ + do { \ + if (!direct_config || direct_config->debug) \ + direct_debug( x ); \ + } while (0) + + +#define D_DEBUG_AT(d,x...) \ + do { \ + direct_debug_at( &d, x ); \ + } while (0) + +#define D_DEBUG_ENTER(d,x...) \ + do { \ + direct_debug_enter( &d, __FUNCTION__, __FILE__, __LINE__, x ); \ + } while (0) + +#define D_DEBUG_EXIT(d,x...) \ + do { \ + direct_debug_exit( &d, __FUNCTION__, __FILE__, __LINE__, x ); \ + } while (0) + +#define D_ASSERT(exp) \ + do { \ + if (!(exp)) \ + direct_assertion( #exp, __FUNCTION__, __FILE__, __LINE__ ); \ + } while (0) + + +#define D_ASSUME(exp) \ + do { \ + if (!(exp)) \ + direct_assumption( #exp, __FUNCTION__, __FILE__, __LINE__ ); \ + } while (0) + + +#define D_BREAK(x...) \ + do { \ + direct_break( __FUNCTION__, __FILE__, __LINE__, x ); \ + } while (0) + +#elif defined(DIRECT_MINI_DEBUG) + +/* + * Mini debug mode, only D_DEBUG_AT, no domain filters, simple assertion + */ + +#define D_DEBUG_ENABLED (2) + +#define D_DEBUG_AT(d,x...) \ + do { \ + if (direct_config->debug) direct_debug_at_always( &d, x ); \ + } while (0) + +#define D_CHECK(exp, aa) \ + do { \ + if (!(exp)) { \ + long long millis = direct_clock_get_millis(); \ + const char *name = direct_thread_self_name(); \ + \ + direct_log_printf( NULL, \ + "(!) [%-15s %3lld.%03lld] (%5d) *** " #aa " [%s] failed *** [%s:%d in %s()]\n", \ + name ? name : " NO NAME ", millis / 1000LL, millis % 1000LL, \ + direct_gettid(), #exp, __FILE__, __LINE__, __FUNCTION__ ); \ + \ + direct_trace_print_stack( NULL ); \ + } \ + } while (0) + +#define D_ASSERT(exp) D_CHECK(exp, Assertion) +#define D_ASSUME(exp) D_CHECK(exp, Assumption) + +#endif /* MINI_DEBUG / DIRECT_BUILD_DEBUG || DIRECT_ENABLE_DEBUG || DIRECT_FORCE_DEBUG */ + +#endif /* DIRECT_BUILD_TEXT */ + + +/* + * Fallback definitions, e.g. without DIRECT_BUILD_TEXT or DIRECT_ENABLE_DEBUG + */ + +#ifndef D_DEBUG_ENABLED +#define D_DEBUG_ENABLED (0) +#endif + +#ifndef D_DEBUG +#define D_DEBUG(x...) do {} while (0) +#endif + +#ifndef D_DEBUG_AT +#define D_DEBUG_AT(d,x...) do {} while (0) +#endif + +#ifndef D_DEBUG_ENTER +#define D_DEBUG_ENTER(d,x...) do {} while (0) +#endif + +#ifndef D_DEBUG_EXIT +#define D_DEBUG_EXIT(d,x...) do {} while (0) +#endif + +#ifndef D_ASSERT +#define D_ASSERT(exp) do {} while (0) +#endif + +#ifndef D_ASSUME +#define D_ASSUME(exp) do {} while (0) +#endif + +#ifndef D_BREAK +#define D_BREAK(x...) do {} while (0) +#endif + +#ifndef d_debug_at +#define d_debug_at( domain, x... ) do {} while (0) +#endif + +#ifndef D_DEBUG_DOMAIN +#define D_DEBUG_DOMAIN(i,n,d) +#endif + + + +/* + * Magic Assertions & Utilities + */ + +#define D_MAGIC(spell) ( (((spell)[sizeof(spell)*8/9] << 24) | \ + ((spell)[sizeof(spell)*7/9] << 16) | \ + ((spell)[sizeof(spell)*6/9] << 8) | \ + ((spell)[sizeof(spell)*5/9] )) ^ \ + (((spell)[sizeof(spell)*4/9] << 24) | \ + ((spell)[sizeof(spell)*3/9] << 16) | \ + ((spell)[sizeof(spell)*2/9] << 8) | \ + ((spell)[sizeof(spell)*1/9] )) ) + + +#define D_MAGIC_SET(o,m) do { \ + D_ASSERT( (o) != NULL ); \ + D_ASSUME( (o)->magic != D_MAGIC(#m) ); \ + \ + (o)->magic = D_MAGIC(#m); \ + } while (0) + +#define D_MAGIC_SET_ONLY(o,m) do { \ + D_ASSERT( (o) != NULL ); \ + \ + (o)->magic = D_MAGIC(#m); \ + } while (0) + +#define D_MAGIC_ASSERT(o,m) do { \ + D_ASSERT( (o) != NULL ); \ + D_ASSERT( (o)->magic == D_MAGIC(#m) ); \ + } while (0) + +#define D_MAGIC_ASSUME(o,m) do { \ + D_ASSUME( (o) != NULL ); \ + if (o) \ + D_ASSUME( (o)->magic == D_MAGIC(#m) ); \ + } while (0) + +#define D_MAGIC_ASSERT_IF(o,m) do { \ + if (o) \ + D_ASSERT( (o)->magic == D_MAGIC(#m) ); \ + } while (0) + +#define D_MAGIC_CLEAR(o) do { \ + D_ASSERT( (o) != NULL ); \ + D_ASSUME( (o)->magic != 0 ); \ + \ + (o)->magic = 0; \ + } while (0) + + +#endif + diff --git a/Source/DirectFB/lib/direct/direct.c b/Source/DirectFB/lib/direct/direct.c new file mode 100755 index 0000000..38b930f --- /dev/null +++ b/Source/DirectFB/lib/direct/direct.c @@ -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. +*/ + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +D_DEBUG_DOMAIN( Direct_Main, "Direct/Main", "Initialization and shutdown of libdirect" ); + +/**************************************************************************************************/ + +struct __D_DirectCleanupHandler { + DirectLink link; + + int magic; + + DirectCleanupHandlerFunc func; + void *ctx; +}; + +/**************************************************************************************************/ + +static int refs = 0; +static DirectLink *handlers = NULL; +static pthread_mutex_t main_lock = PTHREAD_MUTEX_INITIALIZER; + +/**************************************************************************************************/ + +static void +direct_cleanup( void ) +{ + DirectCleanupHandler *handler, *temp; + + if (!refs) + return; + + direct_list_foreach_safe (handler, temp, handlers) { + D_DEBUG_AT( Direct_Main, "Calling cleanup func %p...\n", handler->func ); + + handler->func( handler->ctx ); + + /*direct_list_remove( &handlers, &handler->link ); + + D_MAGIC_CLEAR( handler ); + + D_FREE( handler );*/ + } + + direct_print_memleaks(); + + direct_print_interface_leaks(); +} + +/**************************************************************************************************/ + +DirectResult +direct_cleanup_handler_add( DirectCleanupHandlerFunc func, + void *ctx, + DirectCleanupHandler **ret_handler ) +{ + DirectCleanupHandler *handler; + + D_ASSERT( func != NULL ); + D_ASSERT( ret_handler != NULL ); + + D_DEBUG_AT( Direct_Main, + "Adding cleanup handler %p with context %p...\n", func, ctx ); + + handler = D_CALLOC( 1, sizeof(DirectCleanupHandler) ); + if (!handler) { + D_WARN( "out of memory" ); + return DR_NOLOCALMEMORY; + } + + handler->func = func; + handler->ctx = ctx; + + D_MAGIC_SET( handler, DirectCleanupHandler ); + + pthread_mutex_lock( &main_lock ); + + if (handlers == NULL) + atexit( direct_cleanup ); + + direct_list_append( &handlers, &handler->link ); + + pthread_mutex_unlock( &main_lock ); + + *ret_handler = handler; + + return DR_OK; +} + +DirectResult +direct_cleanup_handler_remove( DirectCleanupHandler *handler ) +{ + D_ASSERT( handler != NULL ); + + D_MAGIC_ASSERT( handler, DirectCleanupHandler ); + + D_DEBUG_AT( Direct_Main, "Removing cleanup handler %p with context %p...\n", + handler->func, handler->ctx ); + + pthread_mutex_lock( &main_lock ); + direct_list_remove( &handlers, &handler->link ); + pthread_mutex_unlock( &main_lock ); + + D_MAGIC_CLEAR( handler ); + + D_FREE( handler ); + + return DR_OK; +} + +DirectResult +direct_initialize( void ) +{ + pthread_mutex_lock( &main_lock ); + + D_DEBUG_AT( Direct_Main, "direct_initialize() called...\n" ); + + if (refs++) { + D_DEBUG_AT( Direct_Main, "...%d references now.\n", refs ); + pthread_mutex_unlock( &main_lock ); + return DR_OK; + } + else if (!direct_thread_self_name()) + direct_thread_set_name( "Main Thread" ); + + D_DEBUG_AT( Direct_Main, "...initializing now.\n" ); + + direct_signals_initialize(); + + pthread_mutex_unlock( &main_lock ); + + return DR_OK; +} + +DirectResult +direct_shutdown( void ) +{ + pthread_mutex_lock( &main_lock ); + + D_DEBUG_AT( Direct_Main, "direct_shutdown() called...\n" ); + + if (--refs) { + D_DEBUG_AT( Direct_Main, "...%d references left.\n", refs ); + pthread_mutex_unlock( &main_lock ); + return DR_OK; + } + + D_DEBUG_AT( Direct_Main, "...shutting down now.\n" ); + + direct_signals_shutdown(); + + pthread_mutex_unlock( &main_lock ); + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/direct/direct.h b/Source/DirectFB/lib/direct/direct.h new file mode 100755 index 0000000..b94e999 --- /dev/null +++ b/Source/DirectFB/lib/direct/direct.h @@ -0,0 +1,49 @@ +/* + (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 __DIRECT__DIRECT_H__ +#define __DIRECT__DIRECT_H__ + +#include + +DirectResult direct_initialize( void ); +DirectResult direct_shutdown( void ); + + +typedef void (*DirectCleanupHandlerFunc)( void *ctx ); + + +DirectResult direct_cleanup_handler_add( DirectCleanupHandlerFunc func, + void *ctx, + DirectCleanupHandler **ret_handler ); + +DirectResult direct_cleanup_handler_remove( DirectCleanupHandler *handler ); + + +#endif + diff --git a/Source/DirectFB/lib/direct/direct.pc.in b/Source/DirectFB/lib/direct/direct.pc.in new file mode 100755 index 0000000..fa6e663 --- /dev/null +++ b/Source/DirectFB/lib/direct/direct.pc.in @@ -0,0 +1,13 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +moduledir=@MODULEDIR@ +moduledirname=@MODULEDIRNAME@ +includedir=@includedir@ + +Name: Direct +Description: DirectFB base development library +Version: @VERSION@ +Libs: -L${libdir} -ldirect @THREADLIB@ +Libs.private: -L${libdir} @DYNLIB@ +Cflags: @THREADFLAGS@ -I@INCLUDEDIR@ diff --git a/Source/DirectFB/lib/direct/fastlz.c b/Source/DirectFB/lib/direct/fastlz.c new file mode 100755 index 0000000..60bf3ca --- /dev/null +++ b/Source/DirectFB/lib/direct/fastlz.c @@ -0,0 +1,97 @@ +/* + (c) Copyright 2001-2011 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 "flz.h" + + +int +direct_fastlz_compress( const void *input, + int length, + void *output ) +{ + return fastlz_compress_level( 2, input, length, output ); +} + +int +direct_fastlz_decompress( const void *input, + int length, + void *output, + int maxout ) +{ + return fastlz_decompress( input, length, output, maxout ); +} + +int +direct_fastlz_compress_multi( const void **inputs, + int *lengths, + unsigned int num, + void *output ) +{ + // FIXME: Optimize by modifying fastlz compressor to take an array of buffers directly + + unsigned int i; + int total = 0; + int offset = 0; + void *buffer; + int result; + + if (num == 0) + return 0; + + if (num == 1) + return direct_fastlz_compress( inputs[0], lengths[0], output ); + + for (i=0; i, + 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 __DIRECT__FASTLZ_H__ +#define __DIRECT__FASTLZ_H__ + +#include + +/**********************************************************************************************************************/ + +int direct_fastlz_compress ( const void *input, + int length, + void *output ); + +int direct_fastlz_decompress ( const void *input, + int length, + void *output, + int maxout ); + + +int direct_fastlz_compress_multi( const void **inputs, + int *lengths, + unsigned int num, + void *output ); + +#endif + diff --git a/Source/DirectFB/lib/direct/flz.c b/Source/DirectFB/lib/direct/flz.c new file mode 100755 index 0000000..070bbe2 --- /dev/null +++ b/Source/DirectFB/lib/direct/flz.c @@ -0,0 +1,555 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#if !defined(FASTLZ__COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) + +/* + * Always check for bound when decompressing. + * Generally it is best to leave it defined. + */ +#define FASTLZ_SAFE + +/* + * Give hints to the compiler for branch prediction optimization. + */ +#if defined(__GNUC__) && (__GNUC__ > 2) +#define FASTLZ_EXPECT_CONDITIONAL(c) (__builtin_expect((c), 1)) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (__builtin_expect((c), 0)) +#else +#define FASTLZ_EXPECT_CONDITIONAL(c) (c) +#define FASTLZ_UNEXPECT_CONDITIONAL(c) (c) +#endif + +/* + * Use inlined functions for supported systems. + */ +#if defined(__GNUC__) || defined(__DMC__) || defined(__POCC__) || defined(__WATCOMC__) || defined(__SUNPRO_C) +#define FASTLZ_INLINE inline +#elif defined(__BORLANDC__) || defined(_MSC_VER) || defined(__LCC__) +#define FASTLZ_INLINE __inline +#else +#define FASTLZ_INLINE +#endif + +/* + * Prevent accessing more than 8-bit at once, except on x86 architectures. + */ +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_STRICT_ALIGN + +#if 0 +#if defined(__i386__) || defined(__386) /* GNU C, Sun Studio */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__i486__) || defined(__i586__) || defined(__i686__) /* GNU C */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(_M_IX86) /* Intel, MSVC */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__386) +#undef FASTLZ_STRICT_ALIGN +#elif defined(_X86_) /* MinGW */ +#undef FASTLZ_STRICT_ALIGN +#elif defined(__I86__) /* Digital Mars */ +#undef FASTLZ_STRICT_ALIGN +#endif +#endif + +#endif + +/* + * FIXME: use preprocessor magic to set this on different platforms! + */ +typedef unsigned char flzuint8; +typedef unsigned short flzuint16; +typedef unsigned int flzuint32; + +/* prototypes */ +int fastlz_compress(const void* input, int length, void* output); +int fastlz_compress_level(int level, const void* input, int length, void* output); +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +#define MAX_COPY 32 +#define MAX_LEN 264 /* 256 + 8 */ +#define MAX_DISTANCE 8192 + +#if !defined(FASTLZ_STRICT_ALIGN) +#define FASTLZ_READU16(p) *((const flzuint16*)(p)) +#else +#define FASTLZ_READU16(p) ((p)[0] | (p)[1]<<8) +#endif + +#define HASH_LOG 13 +#define HASH_SIZE (1<< HASH_LOG) +#define HASH_MASK (HASH_SIZE-1) +#define HASH_FUNCTION(v,p) { v = FASTLZ_READU16(p); v ^= FASTLZ_READU16(p+1)^(v>>(16-HASH_LOG));v &= HASH_MASK; } + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 1 + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz1_compress +#define FASTLZ_DECOMPRESSOR fastlz1_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "flz.c" + +#undef FASTLZ_LEVEL +#define FASTLZ_LEVEL 2 + +#undef MAX_DISTANCE +#define MAX_DISTANCE 8191 +#define MAX_FARDISTANCE (65535+MAX_DISTANCE-1) + +#undef FASTLZ_COMPRESSOR +#undef FASTLZ_DECOMPRESSOR +#define FASTLZ_COMPRESSOR fastlz2_compress +#define FASTLZ_DECOMPRESSOR fastlz2_decompress +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output); +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout); +#include "flz.c" + +int fastlz_compress(const void* input, int length, void* output) +{ + /* for short block, choose fastlz1 */ + if(length < 65536) + return fastlz1_compress(input, length, output); + + /* else... */ + return fastlz2_compress(input, length, output); +} + +int fastlz_decompress(const void* input, int length, void* output, int maxout) +{ + /* magic identifier for compression level */ + int level = ((*(const flzuint8*)input) >> 5) + 1; + + if(level == 1) + return fastlz1_decompress(input, length, output, maxout); + if(level == 2) + return fastlz2_decompress(input, length, output, maxout); + + /* unknown level, trigger error */ + return 0; +} + +int fastlz_compress_level(int level, const void* input, int length, void* output) +{ + if(level == 1) + return fastlz1_compress(input, length, output); + if(level == 2) + return fastlz2_compress(input, length, output); + + return 0; +} + +#else /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ + +static FASTLZ_INLINE int FASTLZ_COMPRESSOR(const void* input, int length, void* output) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_bound = ip + length - 2; + const flzuint8* ip_limit = ip + length - 12; + flzuint8* op = (flzuint8*) output; + + const flzuint8* htab[HASH_SIZE]; + const flzuint8** hslot; + flzuint32 hval; + + flzuint32 copy; + + /* sanity check */ + if(FASTLZ_UNEXPECT_CONDITIONAL(length < 4)) + { + if(length) + { + /* create literal copy only */ + *op++ = length-1; + ip_bound++; + while(ip <= ip_bound) + *op++ = *ip++; + return length+1; + } + else + return 0; + } + + /* initializes hash table */ + for (hslot = htab; hslot < htab + HASH_SIZE; hslot++) + *hslot = ip; + + /* we start with literal copy */ + copy = 2; + *op++ = MAX_COPY-1; + *op++ = *ip++; + *op++ = *ip++; + + /* main loop */ + while(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + { + const flzuint8* ref; + flzuint32 distance; + + /* minimum match length */ + flzuint32 len = 3; + + /* comparison starting-point */ + const flzuint8* anchor = ip; + + /* check for a run */ +#if FASTLZ_LEVEL==2 + if(ip[0] == ip[-1] && FASTLZ_READU16(ip-1)==FASTLZ_READU16(ip+1)) + { + distance = 1; + ip += 3; + ref = anchor - 1 + 3; + goto match; + } +#endif + + /* find potential match */ + HASH_FUNCTION(hval,ip); + hslot = htab + hval; + ref = htab[hval]; + + /* calculate distance to the match */ + distance = anchor - ref; + + /* update hash table */ + *hslot = anchor; + + /* is this a match? check the first 3 bytes */ + if(distance==0 || +#if FASTLZ_LEVEL==1 + (distance >= MAX_DISTANCE) || +#else + (distance >= MAX_FARDISTANCE) || +#endif + *ref++ != *ip++ || *ref++!=*ip++ || *ref++!=*ip++) + goto literal; + +#if FASTLZ_LEVEL==2 + /* far, needs at least 5-byte match */ + if(distance >= MAX_DISTANCE) + { + if(*ip++ != *ref++ || *ip++!= *ref++) + goto literal; + len += 2; + } + + match: +#endif + + /* last matched byte */ + ip = anchor + len; + + /* distance is biased */ + distance--; + + if(!distance) + { + /* zero distance means a run */ + flzuint8 x = ip[-1]; + while(ip < ip_bound) + if(*ref++ != x) break; else ip++; + } + else + for(;;) + { + /* safe because the outer check against ip limit */ + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + if(*ref++ != *ip++) break; + while(ip < ip_bound) + if(*ref++ != *ip++) break; + break; + } + + /* if we have copied something, adjust the copy count */ + if(copy) + /* copy is biased, '0' means 1 byte copy */ + *(op-copy-1) = copy-1; + else + /* back, to overwrite the copy count */ + op--; + + /* reset literal counter */ + copy = 0; + + /* length is biased, '1' means a match of 3 bytes */ + ip -= 3; + len = ip - anchor; + + /* encode the match */ +#if FASTLZ_LEVEL==2 + if(distance < MAX_DISTANCE) + { + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = (distance & 255); + } + } + else + { + /* far away, but not yet in the another galaxy... */ + if(len < 7) + { + distance -= MAX_DISTANCE; + *op++ = (len << 5) + 31; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + else + { + distance -= MAX_DISTANCE; + *op++ = (7 << 5) + 31; + for(len-=7; len >= 255; len-= 255) + *op++ = 255; + *op++ = len; + *op++ = 255; + *op++ = distance >> 8; + *op++ = distance & 255; + } + } +#else + + if(FASTLZ_UNEXPECT_CONDITIONAL(len > MAX_LEN-2)) + while(len > MAX_LEN-2) + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = MAX_LEN - 2 - 7 -2; + *op++ = (distance & 255); + len -= MAX_LEN-2; + } + + if(len < 7) + { + *op++ = (len << 5) + (distance >> 8); + *op++ = (distance & 255); + } + else + { + *op++ = (7 << 5) + (distance >> 8); + *op++ = len - 7; + *op++ = (distance & 255); + } +#endif + + /* update the hash at match boundary */ + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + HASH_FUNCTION(hval,ip); + htab[hval] = ip++; + + /* assuming literal copy */ + *op++ = MAX_COPY-1; + + continue; + + literal: + *op++ = *anchor++; + ip = anchor; + copy++; + if(FASTLZ_UNEXPECT_CONDITIONAL(copy == MAX_COPY)) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* left-over as literal copy */ + ip_bound++; + while(ip <= ip_bound) + { + *op++ = *ip++; + copy++; + if(copy == MAX_COPY) + { + copy = 0; + *op++ = MAX_COPY-1; + } + } + + /* if we have copied something, adjust the copy length */ + if(copy) + *(op-copy-1) = copy-1; + else + op--; + +#if FASTLZ_LEVEL==2 + /* marker for fastlz2 */ + *(flzuint8*)output |= (1 << 5); +#endif + + return op - (flzuint8*)output; +} + +static FASTLZ_INLINE int FASTLZ_DECOMPRESSOR(const void* input, int length, void* output, int maxout) +{ + const flzuint8* ip = (const flzuint8*) input; + const flzuint8* ip_limit = ip + length; + flzuint8* op = (flzuint8*) output; + flzuint8* op_limit = op + maxout; + flzuint32 ctrl = (*ip++) & 31; + int loop = 1; + + do + { + const flzuint8* ref = op; + flzuint32 len = ctrl >> 5; + flzuint32 ofs = (ctrl & 31) << 8; + + if(ctrl >= 32) + { +#if FASTLZ_LEVEL==2 + flzuint8 code; +#endif + len--; + ref -= ofs; + if (len == 7-1) +#if FASTLZ_LEVEL==1 + len += *ip++; + ref -= *ip++; +#else + do + { + code = *ip++; + len += code; + } while (code==255); + code = *ip++; + ref -= code; + + /* match from 16-bit distance */ + if(FASTLZ_UNEXPECT_CONDITIONAL(code==255)) + if(FASTLZ_EXPECT_CONDITIONAL(ofs==(31 << 8))) + { + ofs = (*ip++) << 8; + ofs += *ip++; + ref = op - ofs - MAX_DISTANCE; + } +#endif + +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + len + 3 > op_limit)) + return 0; + + if (FASTLZ_UNEXPECT_CONDITIONAL(ref-1 < (flzuint8 *)output)) + return 0; +#endif + + if(FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit)) + ctrl = *ip++; + else + loop = 0; + + if(ref == op) + { + /* optimize copy for a run */ + flzuint8 b = ref[-1]; + *op++ = b; + *op++ = b; + *op++ = b; + for(; len; --len) + *op++ = b; + } + else + { +#if !defined(FASTLZ_STRICT_ALIGN) + const flzuint16* p; + flzuint16* q; +#endif + /* copy from reference */ + ref--; + *op++ = *ref++; + *op++ = *ref++; + *op++ = *ref++; + +#if !defined(FASTLZ_STRICT_ALIGN) + /* copy a byte, so that now it's word aligned */ + if(len & 1) + { + *op++ = *ref++; + len--; + } + + /* copy 16-bit at once */ + q = (flzuint16*) op; + op += len; + p = (const flzuint16*) ref; + for(len>>=1; len > 4; len-=4) + { + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + *q++ = *p++; + } + for(; len; --len) + *q++ = *p++; +#else + for(; len; --len) + *op++ = *ref++; +#endif + } + } + else + { + ctrl++; +#ifdef FASTLZ_SAFE + if (FASTLZ_UNEXPECT_CONDITIONAL(op + ctrl > op_limit)) + return 0; + if (FASTLZ_UNEXPECT_CONDITIONAL(ip + ctrl > ip_limit)) + return 0; +#endif + + *op++ = *ip++; + for(--ctrl; ctrl; ctrl--) + *op++ = *ip++; + + loop = FASTLZ_EXPECT_CONDITIONAL(ip < ip_limit); + if(loop) + ctrl = *ip++; + } + } + while(FASTLZ_EXPECT_CONDITIONAL(loop)); + + return op - (flzuint8*)output; +} + +#endif /* !defined(FASTLZ_COMPRESSOR) && !defined(FASTLZ_DECOMPRESSOR) */ diff --git a/Source/DirectFB/lib/direct/flz.h b/Source/DirectFB/lib/direct/flz.h new file mode 100755 index 0000000..f87bc7b --- /dev/null +++ b/Source/DirectFB/lib/direct/flz.h @@ -0,0 +1,100 @@ +/* + FastLZ - lightning-fast lossless compression library + + Copyright (C) 2007 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2006 Ariya Hidayat (ariya@kde.org) + Copyright (C) 2005 Ariya Hidayat (ariya@kde.org) + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#ifndef FASTLZ_H +#define FASTLZ_H + +#define FASTLZ_VERSION 0x000100 + +#define FASTLZ_VERSION_MAJOR 0 +#define FASTLZ_VERSION_MINOR 0 +#define FASTLZ_VERSION_REVISION 0 + +#define FASTLZ_VERSION_STRING "0.1.0" + +#if defined (__cplusplus) +extern "C" { +#endif + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. +*/ + +int fastlz_compress(const void* input, int length, void* output); + +/** + Decompress a block of compressed data and returns the size of the + decompressed block. If error occurs, e.g. the compressed data is + corrupted or the output buffer is not large enough, then 0 (zero) + will be returned instead. + + The input buffer and the output buffer can not overlap. + + Decompression is memory safe and guaranteed not to write the output buffer + more than what is specified in maxout. + */ + +int fastlz_decompress(const void* input, int length, void* output, int maxout); + +/** + Compress a block of data in the input buffer and returns the size of + compressed block. The size of input buffer is specified by length. The + minimum input buffer size is 16. + + The output buffer must be at least 5% larger than the input buffer + and can not be smaller than 66 bytes. + + If the input is not compressible, the return value might be larger than + length (input buffer size). + + The input buffer and the output buffer can not overlap. + + Compression level can be specified in parameter level. At the moment, + only level 1 and level 2 are supported. + Level 1 is the fastest compression and generally useful for short data. + Level 2 is slightly slower but it gives better compression ratio. + + Note that the compressed data, regardless of the level, can always be + decompressed using the function fastlz_decompress above. +*/ + +int fastlz_compress_level(int level, const void* input, int length, void* output); + +#if defined (__cplusplus) +} +#endif + +#endif /* FASTLZ_H */ diff --git a/Source/DirectFB/lib/direct/hash.c b/Source/DirectFB/lib/direct/hash.c new file mode 100755 index 0000000..729e866 --- /dev/null +++ b/Source/DirectFB/lib/direct/hash.c @@ -0,0 +1,268 @@ +/* + (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 + + +D_DEBUG_DOMAIN( Direct_Hash, "Direct/Hash", "Hash table implementation" ); + + +#define REMOVED ((void *) -1) + +typedef struct { + unsigned long key; + void *value; +} Element; + +struct __D_DirectHash { + int magic; + + int size; + + int count; + int removed; + + Element *elements; +}; + +/**************************************************************************************************/ + +static inline int +locate_key( const DirectHash *hash, unsigned long key ) +{ + int pos; + const Element *element; + + pos = key % hash->size; + + element = &hash->elements[pos]; + + while (element->value) { + if (element->value != REMOVED && element->key == key) + return pos; + + if (++pos == hash->size) + pos = 0; + + element = &hash->elements[pos]; + } + + return -1; +} + +/**************************************************************************************************/ + +DirectResult +direct_hash_create( int size, + DirectHash **ret_hash ) +{ + DirectHash *hash; + + if (size < 17) + size = 17; + + D_DEBUG_AT( Direct_Hash, "Creating hash table with initial capacity of %d...\n", size ); + + hash = D_CALLOC( 1, sizeof (DirectHash) ); + if (!hash) { + D_WARN( "out of memory" ); + return DR_NOLOCALMEMORY; + } + + hash->size = size; + hash->elements = D_CALLOC( size, sizeof(Element) ); + + if (!hash->elements) { + D_WARN( "out of memory" ); + D_FREE( hash ); + return DR_NOLOCALMEMORY; + } + + D_MAGIC_SET( hash, DirectHash ); + + *ret_hash = hash; + + return DR_OK; +} + +void +direct_hash_destroy( DirectHash *hash ) +{ + D_MAGIC_ASSERT( hash, DirectHash ); + + D_MAGIC_CLEAR( hash ); + + D_FREE( hash->elements ); + D_FREE( hash ); +} + +DirectResult +direct_hash_insert( DirectHash *hash, + unsigned long key, + void *value ) +{ + int pos; + Element *element; + + D_MAGIC_ASSERT( hash, DirectHash ); + D_ASSERT( value != NULL ); + + /* Need to resize the hash table? */ + if ((hash->count + hash->removed) > hash->size / 4) { + int i, size = hash->size * 3; + Element *elements; + + D_DEBUG_AT( Direct_Hash, "Resizing from %d to %d... (count %d, removed %d)\n", + hash->size, size, hash->count, hash->removed ); + + elements = D_CALLOC( size, sizeof(Element) ); + if (!elements) { + D_WARN( "out of memory" ); + return DR_NOLOCALMEMORY; + } + + for (i=0; isize; i++) { + Element *element = &hash->elements[i]; + Element *insertElement; + + if (element->value && element->value != REMOVED) { + pos = element->key % size; + + insertElement = &elements[pos]; + while (insertElement->value && insertElement->value != REMOVED) { + if (++pos == size) + pos = 0; + insertElement = &elements[pos]; + } + + elements[pos] = *element; + } + } + + D_FREE( hash->elements ); + + hash->size = size; + hash->elements = elements; + hash->removed = 0; + } + + pos = key % hash->size; + + D_DEBUG_AT( Direct_Hash, "Attempting to insert key 0x%08lx at position %d...\n", key, pos ); + + element = &hash->elements[pos]; + + while (element->value && element->value != REMOVED) { + if (element->key == key) { + D_BUG( "key already exists" ); + return DR_BUG; + } + + if (++pos == hash->size) + pos = 0; + + element = &hash->elements[pos]; + } + + if (element->value == REMOVED) + hash->removed--; + + element->key = key; + element->value = value; + + hash->count++; + + D_DEBUG_AT( Direct_Hash, "...inserted at %d, new count = %d, removed = %d, size = %d, key = 0x%08lx.\n", + pos, hash->count, hash->removed, hash->size, key ); + + return DR_OK; +} + +void +direct_hash_remove( DirectHash *hash, + unsigned long key ) +{ + int pos; + + D_MAGIC_ASSERT( hash, DirectHash ); + + pos = locate_key( hash, key ); + if (pos == -1) { + D_WARN( "key not found" ); + return; + } + + hash->elements[pos].value = REMOVED; + + hash->count--; + hash->removed++; + + D_DEBUG_AT( Direct_Hash, "Removed key 0x%08lx at %d, new count = %d, removed = %d, size = %d.\n", + key, pos, hash->count, hash->removed, hash->size ); +} + +void * +direct_hash_lookup( DirectHash *hash, + unsigned long key ) +{ + int pos; + + D_MAGIC_ASSERT( hash, DirectHash ); + + pos = locate_key( hash, key ); + + return (pos != -1) ? hash->elements[pos].value : NULL; +} + +void +direct_hash_iterate( DirectHash *hash, + DirectHashIteratorFunc func, + void *ctx ) +{ + int i; + + D_MAGIC_ASSERT( hash, DirectHash ); + + for (i=0; isize; i++) { + Element *element = &hash->elements[i]; + + if (!element->value || element->value == REMOVED) + continue; + + if (!func( hash, element->key, element->value, ctx ) ) + return; + } +} + diff --git a/Source/DirectFB/lib/direct/hash.h b/Source/DirectFB/lib/direct/hash.h new file mode 100755 index 0000000..6b487d9 --- /dev/null +++ b/Source/DirectFB/lib/direct/hash.h @@ -0,0 +1,61 @@ +/* + (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 __DIRECT__HASH_H__ +#define __DIRECT__HASH_H__ + +#include + + +typedef bool (*DirectHashIteratorFunc)( DirectHash *hash, + unsigned long key, + void *value, + void *ctx ); + + +DirectResult direct_hash_create ( int size, + DirectHash **ret_hash ); + +void direct_hash_destroy( DirectHash *hash ); + +DirectResult direct_hash_insert ( DirectHash *hash, + unsigned long key, + void *value ); + +void direct_hash_remove ( DirectHash *hash, + unsigned long key ); + +void *direct_hash_lookup ( DirectHash *hash, + unsigned long key ); + +void direct_hash_iterate( DirectHash *hash, + DirectHashIteratorFunc func, + void *ctx ); + +#endif + diff --git a/Source/DirectFB/lib/direct/interface.c b/Source/DirectFB/lib/direct/interface.c new file mode 100755 index 0000000..1247412 --- /dev/null +++ b/Source/DirectFB/lib/direct/interface.c @@ -0,0 +1,474 @@ +/* + (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 +#ifndef USE_KOS +#include +#endif +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef PIC +#define DYNAMIC_LINKING +#endif + + +D_DEBUG_DOMAIN( Direct_Interface, "Direct/Interface", "Direct Interface" ); + + +typedef struct { + DirectLink link; + + int magic; + + char *filename; + void *module_handle; + + DirectInterfaceFuncs *funcs; + + const char *type; + const char *implementation; + + int references; +} DirectInterfaceImplementation; + + +#ifdef PTHREADMINIT +static pthread_mutex_t implementations_mutex = PTHREAD_MUTEX_INITIALIZER; +#else +static pthread_mutex_t implementations_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +#endif +static DirectLink *implementations = NULL; + +/**************************************************************************************************/ + +void +DirectRegisterInterface( DirectInterfaceFuncs *funcs ) +{ + DirectInterfaceImplementation *impl; + + D_DEBUG_AT( Direct_Interface, "%s( %p )\n", __FUNCTION__, funcs ); + + impl = D_CALLOC( 1, sizeof(DirectInterfaceImplementation) ); + + impl->funcs = funcs; + impl->type = funcs->GetType(); + impl->implementation = funcs->GetImplementation(); + + D_MAGIC_SET( impl, DirectInterfaceImplementation ); + + D_DEBUG_AT( Direct_Interface, " -> %s | %s\n", impl->type, impl->implementation ); + + pthread_mutex_lock( &implementations_mutex ); + direct_list_prepend( &implementations, &impl->link ); + pthread_mutex_unlock( &implementations_mutex ); +} + +void +DirectUnregisterInterface( DirectInterfaceFuncs *funcs ) +{ + DirectInterfaceImplementation *impl; + + pthread_mutex_lock( &implementations_mutex ); + + direct_list_foreach (impl, implementations) { + D_MAGIC_ASSERT( impl, DirectInterfaceImplementation ); + + if (impl->funcs == funcs) { + direct_list_remove( &implementations, &impl->link ); + + break; + } + } + + pthread_mutex_unlock( &implementations_mutex ); + + if (!impl) { + D_BUG( "implementation not found" ); + return; + } + + D_MAGIC_CLEAR( impl ); + + D_FREE( impl ); +} + +DirectResult +DirectProbeInterface( DirectInterfaceFuncs *funcs, void *ctx ) +{ + return (funcs->Probe( ctx ) == DR_OK); +} + +DirectResult +DirectGetInterface( DirectInterfaceFuncs **funcs, + const char *type, + const char *implementation, + DirectInterfaceProbeFunc probe, + void *probe_ctx ) +{ +#ifdef DYNAMIC_LINKING + int len; + DIR *dir; + char *interface_dir; + struct dirent *entry = NULL; + struct dirent tmp; + const char *path; +#endif + + DirectLink *link; + + D_DEBUG_AT( Direct_Interface, "%s( %p, '%s', '%s', %p, %p )\n", __FUNCTION__, + funcs, type, implementation, probe, probe_ctx ); + + pthread_mutex_lock( &implementations_mutex ); + + /* + * Check existing implementations first. + */ + direct_list_foreach( link, implementations ) { + DirectInterfaceImplementation *impl = (DirectInterfaceImplementation*) link; + + if (type && strcmp( type, impl->type )) + continue; + + if (implementation && strcmp( implementation, impl->implementation )) + continue; + + D_DEBUG_AT( Direct_Interface, " -> Probing '%s'...\n", impl->implementation ); + + if (probe && !probe( impl->funcs, probe_ctx )) + continue; + else { + if (!impl->references) { + D_INFO( "Direct/Interface: Using '%s' implementation of '%s'.\n", + impl->implementation, impl->type ); + } + + *funcs = impl->funcs; + impl->references++; + + pthread_mutex_unlock( &implementations_mutex ); + + return DR_OK; + } + } + +#ifdef DYNAMIC_LINKING + /* + * Try to load it dynamically. + */ + + /* NULL type means we can't find plugin, so stop immediately */ + if (type == NULL) { + pthread_mutex_unlock( &implementations_mutex ); + return DR_NOIMPL; + } + + path = direct_config->module_dir; + if(!path) + path = MODULEDIR; + + len = strlen(path) + strlen("/interfaces/") + strlen(type) + 1; + interface_dir = alloca( len ); + snprintf( interface_dir, len, "%s%sinterfaces/%s", path, (path[strlen(path)-1]=='/') ? "" : "/", type ); + + dir = opendir( interface_dir ); + if (!dir) { + D_DEBUG( "Could not open interface directory `%s'!\n", interface_dir ); + pthread_mutex_unlock( &implementations_mutex ); + return errno2result( errno ); + } + + /* + * Iterate directory. + */ + while (readdir_r( dir, &tmp, &entry ) == 0 && entry) { + void *handle = NULL; + char buf[4096]; + + DirectInterfaceImplementation *old_impl = (DirectInterfaceImplementation*) implementations; + + if (strlen(entry->d_name) < 4 || + entry->d_name[strlen(entry->d_name)-1] != 'o' || + entry->d_name[strlen(entry->d_name)-2] != 's') + continue; + + snprintf( buf, 4096, "%s/%s", interface_dir, entry->d_name ); + + /* + * Check if it got already loaded. + */ + direct_list_foreach( link, implementations ) { + DirectInterfaceImplementation *impl = (DirectInterfaceImplementation*) link; + + if (impl->filename && !strcmp( impl->filename, buf )) { + handle = impl->module_handle; + break; + } + } + + /* + * If already loaded take the next one. + */ + if (handle) + continue; + + /* + * Open it and check. + */ + handle = dlopen( buf, RTLD_NOW ); + if (handle) { + DirectInterfaceImplementation *impl = (DirectInterfaceImplementation*) implementations; + + /* + * Check if it registered itself. + */ + if (impl == old_impl) { + dlclose( handle ); + continue; + } + + /* + * Keep filename and module handle. + */ + impl->filename = D_STRDUP( buf ); + impl->module_handle = handle; + + /* + * Almost the same stuff like above, TODO: make function. + */ + if (strcmp( type, impl->type )) + continue; + + if (implementation && strcmp( implementation, + impl->implementation )) + continue; + + if (probe && !probe( impl->funcs, probe_ctx )) { + continue; + } + else { + D_INFO( "Direct/Interface: Loaded '%s' implementation of '%s'.\n", + impl->implementation, impl->type ); + + *funcs = impl->funcs; + impl->references++; + + closedir( dir ); + + pthread_mutex_unlock( &implementations_mutex ); + + return DR_OK; + } + } + else + D_DLERROR( "Direct/Interface: Unable to dlopen `%s'!\n", buf ); + } + + closedir( dir ); + + pthread_mutex_unlock( &implementations_mutex ); +#endif + + return DR_NOIMPL; +} + +/**************************************************************************************************/ + +#if DIRECT_BUILD_DEBUGS /* Build with debug support? */ + +typedef struct { + const void *interface; + char *name; + char *what; + + const char *func; + const char *file; + int line; + + DirectTraceBuffer *trace; +} InterfaceDesc; + +static int alloc_count = 0; +static int alloc_capacity = 0; +static InterfaceDesc *alloc_list = NULL; +static pthread_mutex_t alloc_lock = PTHREAD_MUTEX_INITIALIZER; + +/**************************************************************************************************/ + +void +direct_print_interface_leaks( void ) +{ + unsigned int i; + + pthread_mutex_lock( &alloc_lock ); + + if (alloc_count /*&& (!direct_config || direct_config->debug)*/) { + direct_log_printf( NULL, "Interface instances remaining (%d): \n", alloc_count ); + + for (i=0; iname, + desc->interface, desc->what, desc->func, desc->file, desc->line ); + + if (desc->trace) + direct_trace_print_stack( desc->trace ); + } + } + + pthread_mutex_unlock( &alloc_lock ); +} + +/**************************************************************************************************/ + +static InterfaceDesc * +allocate_interface_desc( void ) +{ + int cap = alloc_capacity; + + if (!cap) + cap = 64; + else if (cap == alloc_count) + cap <<= 1; + + if (cap != alloc_capacity) { + alloc_capacity = cap; + alloc_list = realloc( alloc_list, sizeof(InterfaceDesc) * cap ); + + D_ASSERT( alloc_list != NULL ); + } + + return &alloc_list[alloc_count++]; +} + +static inline void +fill_interface_desc( InterfaceDesc *desc, + const void *interface, + const char *name, + const char *func, + const char *file, + int line, + const char *what, + DirectTraceBuffer *trace ) +{ + desc->interface = interface; + desc->name = strdup( name ); + desc->what = strdup( what ); + desc->func = func; + desc->file = file; + desc->line = line; + desc->trace = trace; +} + +/**************************************************************************************************/ + +__attribute__((no_instrument_function)) +void +direct_dbg_interface_add( const char *func, + const char *file, + int line, + const char *what, + const void *interface, + const char *name ) +{ + InterfaceDesc *desc; + + pthread_mutex_lock( &alloc_lock ); + + desc = allocate_interface_desc(); + + fill_interface_desc( desc, interface, name, + func, file, line, what, direct_trace_copy_buffer(NULL) ); + + pthread_mutex_unlock( &alloc_lock ); +} + +__attribute__((no_instrument_function)) +void +direct_dbg_interface_remove( const char *func, + const char *file, + int line, + const char *what, + const void *interface ) +{ + unsigned int i; + + pthread_mutex_lock( &alloc_lock ); + + for (i=0; iinterface == interface) { + if (desc->trace) + direct_trace_free_buffer( desc->trace ); + + free( desc->what ); + free( desc->name ); + + if (i < --alloc_count) + direct_memmove( desc, desc + 1, (alloc_count - i) * sizeof(InterfaceDesc) ); + + pthread_mutex_unlock( &alloc_lock ); + + return; + } + } + + pthread_mutex_unlock( &alloc_lock ); + + D_ERROR( "Direct/Interface: unknown instance %p (%s) from [%s:%d in %s()]\n", + interface, what, file, line, func ); + D_BREAK( "unknown instance" ); +} + +#else /* DIRECT_BUILD_DEBUG */ + +void +direct_print_interface_leaks( void ) +{ +} + +#endif /* DIRECT_BUILD_DEBUG */ + diff --git a/Source/DirectFB/lib/direct/interface.h b/Source/DirectFB/lib/direct/interface.h new file mode 100755 index 0000000..5e6200d --- /dev/null +++ b/Source/DirectFB/lib/direct/interface.h @@ -0,0 +1,215 @@ +/* + (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 __DIRECT__INTERFACE_H__ +#define __DIRECT__INTERFACE_H__ + +#include +#include + +/* + * Forward declaration macro for interfaces. + */ +#define DECLARE_INTERFACE( IFACE ) \ + typedef struct _##IFACE IFACE; + +/* + * Macro for an interface definition. + */ +#define DEFINE_INTERFACE( IFACE, IDATA... ) \ + struct _##IFACE { \ + void *priv; \ + int magic; \ + \ + DirectResult (*AddRef)( IFACE *thiz ); \ + DirectResult (*Release)( IFACE *thiz ); \ + \ + IDATA \ + }; + +/* + * Declare base interface + */ +DECLARE_INTERFACE( IAny ) + +/* + * Define base interface + */ +DEFINE_INTERFACE( IAny, ) + +/* + * Function type for probing of interface implementations + */ +typedef DirectResult (*DirectInterfaceGenericProbeFunc)( void *ctx, ... ); + +/* + * Function type for initialization of interface instances + */ +typedef DirectResult (*DirectInterfaceGenericConstructFunc)( void *interface, ... ); + +/* + * Function table for interface implementations + */ +typedef struct { + const char * (*GetType)(void); + const char * (*GetImplementation)(void); + DirectResult (*Allocate)( void **interface ); + + DirectInterfaceGenericProbeFunc Probe; + DirectInterfaceGenericConstructFunc Construct; +} DirectInterfaceFuncs; + +/* + * Callback type for user probing interface implementations + */ +typedef DirectResult (*DirectInterfaceProbeFunc)( DirectInterfaceFuncs *impl, void *ctx ); + +/* + * Loads an interface of a specific 'type'. + * Optionally an 'implementation' can be chosen. + * A 'probe' function can be used to check available implementations. + * + * After success 'funcs' is set. + */ +DirectResult DirectGetInterface( DirectInterfaceFuncs **funcs, + const char *type, + const char *implementation, + DirectInterfaceProbeFunc probe, + void *probe_ctx ); + +/* + * Default probe function. Calls "funcs->Probe(ctx)". + * Can be used as the 'probe' argument to DirectGetInterface. + * 'probe_ctx' should then be set to the interface specific probe context. + */ +DirectResult DirectProbeInterface( DirectInterfaceFuncs *funcs, void *ctx ); + +/* + * Called by implementation modules during 'dlopen'ing or at startup if linked + * into the executable. + */ +void DirectRegisterInterface( DirectInterfaceFuncs *funcs ); + +void DirectUnregisterInterface( DirectInterfaceFuncs *funcs ); + +void direct_print_interface_leaks(void); + +#if DIRECT_BUILD_DEBUGS +void direct_dbg_interface_add ( const char *func, + const char *file, + int line, + const char *what, + const void *interface, + const char *name ); + +void direct_dbg_interface_remove( const char *func, + const char *file, + int line, + const char *what, + const void *interface ); +#endif + +#if DIRECT_BUILD_DEBUG || defined(DIRECT_ENABLE_DEBUG) || defined(DIRECT_FORCE_DEBUG) + +#if !DIRECT_BUILD_DEBUGS +#error Building with debug, but library headers suggest that debug is not supported. +#endif + +#define DIRECT_DBG_INTERFACE_ADD direct_dbg_interface_add +#define DIRECT_DBG_INTERFACE_REMOVE direct_dbg_interface_remove + +#else + +#define DIRECT_DBG_INTERFACE_ADD(func,file,line,what,interface,name) do {} while (0) +#define DIRECT_DBG_INTERFACE_REMOVE(func,file,line,what,interface) do {} while (0) + +#endif + + + +#define DIRECT_ALLOCATE_INTERFACE(p,i) \ + do { \ + (p) = (__typeof__(p))D_CALLOC( 1, sizeof(i) ); \ + \ + D_MAGIC_SET( (IAny*)(p), DirectInterface ); \ + \ + DIRECT_DBG_INTERFACE_ADD( __FUNCTION__, __FILE__, __LINE__, #p, p, #i ); \ + } while (0) + + +#define DIRECT_ALLOCATE_INTERFACE_DATA(p,i) \ + i##_data *data; \ + \ + D_MAGIC_ASSERT( (IAny*)(p), DirectInterface ); \ + \ + if (!(p)->priv) \ + (p)->priv = D_CALLOC( 1, sizeof(i##_data) ); \ + \ + data = (i##_data*)((p)->priv); + + +#define DIRECT_DEALLOCATE_INTERFACE(p) \ + DIRECT_DBG_INTERFACE_REMOVE( __FUNCTION__, __FILE__, __LINE__, #p, p ); \ + \ + if ((p)->priv) { \ + D_FREE( (p)->priv ); \ + (p)->priv = NULL; \ + } \ + \ + D_MAGIC_CLEAR( (IAny*)(p) ); \ + \ + D_FREE( (p) ); + + +#define DIRECT_INTERFACE_GET_DATA(i) \ + i##_data *data; \ + \ + if (!thiz) \ + return DR_THIZNULL; \ + \ + D_MAGIC_ASSERT( (IAny*)thiz, DirectInterface ); \ + \ + data = (i##_data*) thiz->priv; \ + \ + if (!data) \ + return DR_DEAD; + + +#define DIRECT_INTERFACE_GET_DATA_FROM(interface,data,prefix) \ + do { \ + D_MAGIC_ASSERT( (IAny*)(interface), DirectInterface ); \ + \ + (data) = (prefix##_data*) (interface)->priv; \ + \ + if (!(data)) \ + return DR_DEAD; \ + } while (0) + + +#endif + diff --git a/Source/DirectFB/lib/direct/interface_implementation.h b/Source/DirectFB/lib/direct/interface_implementation.h new file mode 100755 index 0000000..7951b59 --- /dev/null +++ b/Source/DirectFB/lib/direct/interface_implementation.h @@ -0,0 +1,91 @@ +/* + (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 __DIRECT__INTERFACE_IMPLEMENTATION_H__ +#define __DIRECT__INTERFACE_IMPLEMENTATION_H__ + +#include + + +static const char *GetType( void ); +static const char *GetImplementation( void ); +static DirectResult Allocate( void **interface ); + +static DirectInterfaceFuncs interface_funcs = { + .GetType = GetType, + .GetImplementation = GetImplementation, + .Allocate = Allocate, + .Probe = (DirectInterfaceGenericProbeFunc) Probe, + .Construct = (DirectInterfaceGenericConstructFunc) Construct +}; + +#define DIRECT_INTERFACE_IMPLEMENTATION(type, impl) \ + \ +static const char * \ +GetType( void ) \ +{ \ + return #type; \ +} \ + \ +static const char * \ +GetImplementation( void ) \ +{ \ + return #impl; \ +} \ + \ +static DirectResult \ +Allocate( void **interface ) \ +{ \ + DIRECT_ALLOCATE_INTERFACE( *interface, type ); \ + return DR_OK; \ +} \ + \ +__attribute__((constructor)) \ +void \ +type##_##impl##_ctor(void); \ + \ +__attribute__((constructor)) \ +void \ +type##_##impl##_ctor(void) \ +{ \ + DirectRegisterInterface( &interface_funcs ); \ +} \ + \ +__attribute__((destructor)) \ +void \ +type##_##impl##_dtor(void); \ + \ +__attribute__((destructor)) \ +void \ +type##_##impl##_dtor(void) \ +{ \ + DirectUnregisterInterface( &interface_funcs ); \ +} + +#endif + diff --git a/Source/DirectFB/lib/direct/list.c b/Source/DirectFB/lib/direct/list.c new file mode 100755 index 0000000..8a82bfa --- /dev/null +++ b/Source/DirectFB/lib/direct/list.c @@ -0,0 +1,35 @@ +/* + (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 + + diff --git a/Source/DirectFB/lib/direct/list.h b/Source/DirectFB/lib/direct/list.h new file mode 100755 index 0000000..25ecdf8 --- /dev/null +++ b/Source/DirectFB/lib/direct/list.h @@ -0,0 +1,224 @@ +/* + (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 __DIRECT__LIST_H__ +#define __DIRECT__LIST_H__ + +#include +#include + + +struct __D_DirectLink { + int magic; + + DirectLink *next; + DirectLink *prev; /* The 'prev' pointer of the first element always points + to the last element of the list, for fast appending ;-) */ +}; + +static __inline__ void +direct_list_prepend( DirectLink **list, DirectLink *link ) +{ + DirectLink *first = *list; + + link->next = first; + + if (first) { + D_MAGIC_ASSERT( first, DirectLink ); + + link->prev = first->prev; + + first->prev = link; + } + else + link->prev = link; + + *list = link; + + D_MAGIC_SET( link, DirectLink ); +} + +static __inline__ void +direct_list_append( DirectLink **list, DirectLink *link ) +{ + DirectLink *first = *list; + + link->next = NULL; + + if (first) { + DirectLink *last = first->prev; + + D_MAGIC_ASSERT( first, DirectLink ); + D_MAGIC_ASSERT( last, DirectLink ); + + link->prev = last; + + last->next = first->prev = link; + } + else + *list = link->prev = link; + + D_MAGIC_SET( link, DirectLink ); +} + +static __inline__ bool +direct_list_contains_element_EXPENSIVE( DirectLink *list, DirectLink *link ) +{ + D_MAGIC_ASSERT_IF( list, DirectLink ); + + while (list) { + if (list == link) + return true; + + list = list->next; + } + + return false; +} + +static __inline__ int +direct_list_count_elements_EXPENSIVE( DirectLink *list ) +{ + int count = 0; + + while (list) { + D_MAGIC_ASSERT( list, DirectLink ); + + count++; + + list = list->next; + } + + return count; +} + +static __inline__ void +direct_list_remove( DirectLink **list, DirectLink *link ) +{ + DirectLink *next; + DirectLink *prev; + + D_ASSERT( list != NULL ); + + D_ASSERT( direct_list_contains_element_EXPENSIVE( *list, link ) ); + + D_MAGIC_ASSERT( *list, DirectLink ); + D_MAGIC_ASSERT( link, DirectLink ); + + next = link->next; + prev = link->prev; + + if (next) { + D_MAGIC_ASSERT( next, DirectLink ); + + next->prev = prev; + } + else + (*list)->prev = prev; + + if (link == *list) + *list = next; + else { + D_MAGIC_ASSERT( prev, DirectLink ); + + prev->next = next; + } + + link->next = link->prev = NULL; + + D_MAGIC_CLEAR( link ); +} + +static __inline__ void +direct_list_move_to_front( DirectLink **list, DirectLink *link ) +{ + DirectLink *next; + DirectLink *prev; + DirectLink *first; + + D_ASSERT( list != NULL ); + + first = *list; + + D_ASSERT( direct_list_contains_element_EXPENSIVE( first, link ) ); + + D_MAGIC_ASSERT( first, DirectLink ); + D_MAGIC_ASSERT( link, DirectLink ); + + if (first == link) + return; + + next = link->next; + prev = link->prev; + + D_MAGIC_ASSERT_IF( next, DirectLink ); + D_MAGIC_ASSERT( prev, DirectLink ); + + if (next) { + next->prev = prev; + + link->prev = first->prev; + } + else + link->prev = prev; + + prev->next = next; + + link->next = first; + + first->prev = link; + + *list = link; +} + +static __inline__ bool +direct_list_check_link( const DirectLink *link ) +{ + D_MAGIC_ASSERT_IF( link, DirectLink ); + + return link != NULL; +} + + +#define direct_list_foreach(elem, list) \ + for (elem = (__typeof__(elem))(list); \ + direct_list_check_link( (DirectLink*)(elem) ); \ + elem = (__typeof__(elem))(((DirectLink*)(elem))->next)) + +#define direct_list_foreach_reverse(elem, list) \ + for (elem = (__typeof__(elem))((list) ? (list)->prev : NULL); \ + direct_list_check_link( (DirectLink*)(elem) ); \ + elem = (__typeof__(elem))((((DirectLink*)(elem))->prev->next) ? ((DirectLink*)(elem))->prev : NULL)) + +#define direct_list_foreach_safe(elem, temp, list) \ + for (elem = (__typeof__(elem))(list), temp = ((__typeof__(temp))(elem) ? (__typeof__(temp))(((DirectLink*)(elem))->next) : NULL); \ + direct_list_check_link( (DirectLink*)(elem) ); \ + elem = (__typeof__(elem))(temp), temp = ((__typeof__(temp))(elem) ? (__typeof__(temp))(((DirectLink*)(elem))->next) : NULL)) + +#endif + diff --git a/Source/DirectFB/lib/direct/log.c b/Source/DirectFB/lib/direct/log.c new file mode 100755 index 0000000..774b7a5 --- /dev/null +++ b/Source/DirectFB/lib/direct/log.c @@ -0,0 +1,414 @@ +/* + (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 + + +struct __D_DirectLog { + int magic; + + DirectLogType type; + + int fd; + + pthread_mutex_t lock; +}; + +/**********************************************************************************************************************/ + +/* Statically allocated to avoid endless loops between D_CALLOC() and D_DEBUG(), while the latter would only + * call the allocation once, if there wouldn't be the loopback... + */ +static DirectLog fallback_log; + +static DirectLog *default_log = NULL; +static pthread_once_t init_fallback = PTHREAD_ONCE_INIT; + +/**********************************************************************************************************************/ + +static DirectResult init_stderr( DirectLog *log ); + +static DirectResult init_file ( DirectLog *log, + const char *filename ); + +static DirectResult init_udp ( DirectLog *log, + const char *hostport ); + +/**********************************************************************************************************************/ + +DirectResult +direct_log_create( DirectLogType type, + const char *param, + DirectLog **ret_log ) +{ + DirectResult ret = DR_INVARG; + DirectLog *log; + + log = D_CALLOC( 1, sizeof(DirectLog) ); + if (!log) + return D_OOM(); + + log->type = type; + + switch (type) { + case DLT_STDERR: + ret = init_stderr( log ); + break; + + case DLT_FILE: + ret = init_file( log, param ); + break; + + case DLT_UDP: + ret = init_udp( log, param ); + break; + } + + if (ret) + D_FREE( log ); + else { + direct_util_recursive_pthread_mutex_init( &log->lock ); + + D_MAGIC_SET( log, DirectLog ); + + *ret_log = log; + } + + return ret; +} + +DirectResult +direct_log_destroy( DirectLog *log ) +{ + D_MAGIC_ASSERT( log, DirectLog ); + + D_ASSERT( &fallback_log != log ); + + if (log == default_log) + default_log = NULL; + + close( log->fd ); + + D_MAGIC_CLEAR( log ); + + D_FREE( log ); + + return DR_OK; +} + +__attribute__((no_instrument_function)) +DirectResult +direct_log_printf( DirectLog *log, + const char *format, ... ) +{ + va_list args; + + /* + * Don't use D_MAGIC_ASSERT or any other + * macros/functions that might cause an endless loop. + */ + + va_start( args, format ); + + /* Use the default log if passed log is invalid. */ + if (!log || log->magic != D_MAGIC("DirectLog")) + log = direct_log_default(); + + /* Write to stderr as a fallback if default is invalid, too. */ + if (!log || log->magic != D_MAGIC("DirectLog")) { + + printf(format,args); + + + + //vfprintf( stderr, format, args ); + + + + + fflush( stderr ); + } + else { + int len; + char buf[512]; + + len = vsnprintf( buf, sizeof(buf), format, args ); + + pthread_mutex_lock( &log->lock ); + + + + + // write( log->fd, buf, len ); + printf("%s\n",buf); + + + + + pthread_mutex_unlock( &log->lock ); + } + + va_end( args ); + + return DR_OK; +} + +DirectResult +direct_log_set_default( DirectLog *log ) +{ + D_MAGIC_ASSERT( log, DirectLog ); + + default_log = log; + + return DR_OK; +} + +__attribute__((no_instrument_function)) +void +direct_log_lock( DirectLog *log ) +{ + D_MAGIC_ASSERT_IF( log, DirectLog ); + + if (!log) + log = direct_log_default(); + + D_MAGIC_ASSERT( log, DirectLog ); + + pthread_mutex_lock( &log->lock ); +} + +__attribute__((no_instrument_function)) +void +direct_log_unlock( DirectLog *log ) +{ + D_MAGIC_ASSERT_IF( log, DirectLog ); + + if (!log) + log = direct_log_default(); + + D_MAGIC_ASSERT( log, DirectLog ); + + pthread_mutex_unlock( &log->lock ); +} + +__attribute__((no_instrument_function)) +static void +init_fallback_log( void ) +{ + fallback_log.type = DLT_STDERR; + fallback_log.fd = fileno( stderr ); + + direct_util_recursive_pthread_mutex_init( &fallback_log.lock ); + + D_MAGIC_SET( &fallback_log, DirectLog ); +} + +__attribute__((no_instrument_function)) +DirectLog * +direct_log_default( void ) +{ + pthread_once( &init_fallback, init_fallback_log ); + + if (!default_log) + default_log = &fallback_log; + + D_MAGIC_ASSERT( default_log, DirectLog ); + + return default_log; +} + +/**********************************************************************************************************************/ + +static DirectResult +init_stderr( DirectLog *log ) +{ + log->fd = dup( fileno( stderr ) ); + + return DR_OK; +} + +static DirectResult +init_file( DirectLog *log, + const char *filename ) +{ + DirectResult ret; + int fd; + + fd = open( filename, O_WRONLY | O_CREAT | O_APPEND, 0664 ); + if (fd < 0) { + ret = errno2result( errno ); + D_PERROR( "Direct/Log: Could not open '%s' for writing!\n", filename ); + return ret; + } + + log->fd = fd; + + return DR_OK; +} + +static DirectResult +parse_host_addr( const char *hostport, + struct addrinfo **ret_addr ) +{ + int i, ret; + + int size = strlen( hostport ) + 1; + char buf[size]; + + char *hoststr = buf; + char *portstr = NULL; + char *end; + + struct addrinfo hints; + + memcpy( buf, hostport, size ); + + for (i=0; i:'!\n", hostport ); + return DR_INVARG; + } + + strtoul( portstr, &end, 10 ); + if (end && *end) { + D_ERROR( "Direct/Log: Parse error in port number '%s'!\n", portstr ); + return DR_INVARG; + } + + memset( &hints, 0, sizeof(hints) ); + hints.ai_socktype = SOCK_DGRAM; + hints.ai_family = PF_UNSPEC; + + ret = getaddrinfo( hoststr, portstr, &hints, ret_addr ); + if (ret) { + switch (ret) { + case EAI_FAMILY: + D_ERROR( "Direct/Log: Unsupported address family!\n" ); + return DR_UNSUPPORTED; + + case EAI_SOCKTYPE: + D_ERROR( "Direct/Log: Unsupported socket type!\n" ); + return DR_UNSUPPORTED; + + case EAI_NONAME: + D_ERROR( "Direct/Log: Host not found!\n" ); + return DR_FAILURE; + + case EAI_SERVICE: + D_ERROR( "Direct/Log: Port %s is unreachable!\n", portstr ); + return DR_FAILURE; + +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: +#endif + case EAI_NODATA: + D_ERROR( "Direct/Log: Host found, but has no address!\n" ); + return DR_FAILURE; + + case EAI_MEMORY: + return D_OOM(); + + case EAI_FAIL: + D_ERROR( "Direct/Log: A non-recoverable name server error occurred!\n" ); + return DR_FAILURE; + + case EAI_AGAIN: + D_ERROR( "Direct/Log: Temporary error, try again!\n" ); + return DR_TEMPUNAVAIL; + + default: + D_ERROR( "Direct/Log: Unknown error occured!?\n" ); + return DR_FAILURE; + } + } + + return DR_OK; +} + +static DirectResult +init_udp( DirectLog *log, + const char *hostport ) +{ + DirectResult ret; + int fd; + struct addrinfo *addr; + + ret = parse_host_addr( hostport, &addr ); + if (ret) + return ret; + + fd = socket( addr->ai_family, SOCK_DGRAM, 0 ); + if (fd < 0) { + ret = errno2result( errno ); + D_PERROR( "Direct/Log: Could not create a UDP socket!\n" ); + freeaddrinfo( addr ); + return ret; + } + + ret = connect( fd, addr->ai_addr, addr->ai_addrlen ); + freeaddrinfo( addr ); + + if (ret) { + ret = errno2result( errno ); + D_PERROR( "Direct/Log: Could not connect UDP socket to '%s'!\n", hostport ); + close( fd ); + return ret; + } + + log->fd = fd; + + return DR_OK; +} diff --git a/Source/DirectFB/lib/direct/log.h b/Source/DirectFB/lib/direct/log.h new file mode 100755 index 0000000..68eeccb --- /dev/null +++ b/Source/DirectFB/lib/direct/log.h @@ -0,0 +1,89 @@ +/* + (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 __DIRECT__LOG_H__ +#define __DIRECT__LOG_H__ + +#include +#include + + +typedef enum { + DLT_STDERR, /* Simply print out log on stderr. */ + DLT_FILE, /* Write log into a file. */ + DLT_UDP /* Send out log via UDP. */ +} DirectLogType; + + +/* + * Creates a logging facility. + * + * For each 'type' the 'param' has a different meaning: + * DLT_STDERR ignored (leave NULL) + * DLT_FILE file name + * DLT_UDP : + */ +DirectResult direct_log_create ( DirectLogType type, + const char *param, + DirectLog **ret_log ); + +/* + * Destroys a logging facility. + */ +DirectResult direct_log_destroy ( DirectLog *log ); + +/* + * Write to the log in a printf fashion. + * + * If log is NULL, the default log is used if it's valid, + * otherwise stderr is used a fallback until now. + */ +DirectResult direct_log_printf ( DirectLog *log, + const char *format, ... ) D_FORMAT_PRINTF(2); + +/* + * Set the default log that's used when no valid log is passed. + */ +DirectResult direct_log_set_default( DirectLog *log ); + +/* + * Locks a logging facility for non-intermixed output of multiple calls in multiple threads. Not mandatory. + */ +void direct_log_lock ( DirectLog *log ); + +/* + * Unlocks a logging facility. + */ +void direct_log_unlock ( DirectLog *log ); + +/* + * Returns the default log. + */ +DirectLog *direct_log_default( void ); + +#endif diff --git a/Source/DirectFB/lib/direct/mem.c b/Source/DirectFB/lib/direct/mem.c new file mode 100755 index 0000000..7b65a32 --- /dev/null +++ b/Source/DirectFB/lib/direct/mem.c @@ -0,0 +1,350 @@ +/* + (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 + + +#if DIRECT_BUILD_DEBUGS /* Build with debug support? */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +D_DEBUG_DOMAIN( Direct_Mem, "Direct/Mem", "libdirect memory allocation (debugging)" ); + +/**********************************************************************************************************************/ + +typedef struct { + const void *mem; + size_t bytes; + const char *func; + const char *file; + int line; + DirectTraceBuffer *trace; +} MemDesc; + +/**********************************************************************************************************************/ + +static int alloc_count = 0; +static int alloc_capacity = 0; +static MemDesc *alloc_list = NULL; +static pthread_mutex_t alloc_lock = PTHREAD_MUTEX_INITIALIZER; + +/**********************************************************************************************************************/ + +void +direct_print_memleaks( void ) +{ + unsigned int i; + + /* Debug only. */ + pthread_mutex_lock( &alloc_lock ); + + if (alloc_count && (!direct_config || direct_config->debugmem)) { + direct_log_printf( NULL, "Local memory allocations remaining (%d): \n", alloc_count ); + + for (i=0; ibytes, desc->mem, desc->func, desc->file, desc->line ); + + if (desc->trace) + direct_trace_print_stack( desc->trace ); + } + } + + pthread_mutex_unlock( &alloc_lock ); +} + +/**********************************************************************************************************************/ + +/* FIXME: Replace array by linked list, or at least avoid the memmove on free of an item. */ + +static MemDesc * +allocate_mem_desc( void ) +{ + int cap = alloc_capacity; + + if (!cap) + cap = 64; + else if (cap == alloc_count) + cap <<= 1; + + if (cap != alloc_capacity) { + void *new_list = malloc( sizeof(MemDesc) * cap ); + + if (!new_list) { + D_WARN( "could not allocate more descriptors (%d->%d)", alloc_capacity, cap ); + return NULL; + } + + direct_memcpy( new_list, alloc_list, sizeof(MemDesc) * alloc_count ); + + free( alloc_list ); + + alloc_capacity = cap; + alloc_list = new_list; + } + + return &alloc_list[alloc_count++]; +} + +static inline void +fill_mem_desc( MemDesc *desc, const void *mem, int bytes, + const char *func, const char *file, int line, DirectTraceBuffer *trace ) +{ + desc->mem = mem; + desc->bytes = bytes; + desc->func = func; + desc->file = file; + desc->line = line; + desc->trace = trace; +} + +/**********************************************************************************************************************/ + +void * +direct_malloc( const char* file, int line, const char *func, size_t bytes ) +{ + void *mem; + MemDesc *desc; + + D_DEBUG_AT( Direct_Mem, " +%6zu bytes [%s:%d in %s()]\n", bytes, file, line, func ); + + mem = malloc( bytes ); + if (!mem) + return NULL; + + if (!direct_config->debugmem) + return mem; + + + /* Debug only. */ + pthread_mutex_lock( &alloc_lock ); + desc = allocate_mem_desc(); + pthread_mutex_unlock( &alloc_lock ); + + if (desc) + fill_mem_desc( desc, mem, bytes, func, file, line, direct_trace_copy_buffer(NULL) ); + + return mem; +} + +void * +direct_calloc( const char* file, int line, const char *func, size_t count, size_t bytes ) +{ + void *mem; + MemDesc *desc; + + D_DEBUG_AT( Direct_Mem, " +%6zu bytes [%s:%d in %s()]\n", count * bytes, file, line, func ); + + mem = calloc( count, bytes ); + if (!mem) + return NULL; + + if (!direct_config->debugmem) + return mem; + + + /* Debug only. */ + pthread_mutex_lock( &alloc_lock ); + desc = allocate_mem_desc(); + pthread_mutex_unlock( &alloc_lock ); + + if (desc) + fill_mem_desc( desc, mem, count * bytes, func, file, line, direct_trace_copy_buffer(NULL) ); + + return mem; +} + +void * +direct_realloc( const char *file, int line, const char *func, const char *what, void *mem, size_t bytes ) +{ + int i; + + if (!mem) + return direct_malloc( file, line, func, bytes ); + + if (!bytes) { + direct_free( file, line, func, what, mem ); + return NULL; + } + + if (!direct_config->debugmem) { + D_DEBUG_AT( Direct_Mem, " *%6zu bytes [%s:%d in %s()] '%s'\n", bytes, file, line, func, what ); + return realloc( mem, bytes ); + } + + + /* Debug only. */ + pthread_mutex_lock( &alloc_lock ); + + for (i=0; imem == mem) { + void *new_mem = realloc( mem, bytes ); + + D_DEBUG_AT( Direct_Mem, " %c%6zu bytes [%s:%d in %s()] (%s%zu) <- %p -> %p '%s'\n", + (bytes > desc->bytes) ? '>' : '<', bytes, file, line, func, + (bytes > desc->bytes) ? "+" : "", bytes - desc->bytes, mem, new_mem, what); + + if (desc->trace) { + direct_trace_free_buffer( desc->trace ); + desc->trace = NULL; + } + + if (!new_mem) { + D_WARN( "could not reallocate memory (%p: %zu->%zu)", mem, desc->bytes, bytes ); + + alloc_count--; + + /* FIXME: This can be very slow. */ + if (i < alloc_count) + direct_memmove( desc, desc + 1, (alloc_count - i) * sizeof(MemDesc) ); + } + else + fill_mem_desc( desc, new_mem, bytes, func, file, line, direct_trace_copy_buffer(NULL) ); + + pthread_mutex_unlock( &alloc_lock ); + + return new_mem; + } + } + + pthread_mutex_unlock( &alloc_lock ); + + D_ERROR( "Direct/Mem: Not reallocating unknown %p (%s) from [%s:%d in %s()] - corrupt/incomplete list?\n", + mem, what, file, line, func ); + + return direct_malloc( file, line, func, bytes ); +} + +void +direct_free( const char *file, int line, const char *func, const char *what, void *mem ) +{ + unsigned int i; + + if (!mem) { + D_WARN( "%s (NULL) called", __FUNCTION__ ); + return; + } + + if (!direct_config->debugmem) { + D_DEBUG_AT( Direct_Mem, " - number of bytes of %s [%s:%d in %s()] -> %p\n", what, file, line, func, mem ); + free( mem ); + return; + } + + + /* Debug only. */ + pthread_mutex_lock( &alloc_lock ); + + for (i=0; imem == mem) { + free( mem ); + + D_DEBUG_AT( Direct_Mem, " -%6zu bytes [%s:%d in %s()] -> %p '%s'\n", + desc->bytes, file, line, func, mem, what ); + + if (desc->trace) + direct_trace_free_buffer( desc->trace ); + + alloc_count--; + + /* FIXME: This can be very slow. */ + if (i < alloc_count) + direct_memmove( desc, desc + 1, (alloc_count - i) * sizeof(MemDesc) ); + + pthread_mutex_unlock( &alloc_lock ); + + return; + } + } + + pthread_mutex_unlock( &alloc_lock ); + + D_ERROR( "Direct/Mem: Not freeing unknown %p (%s) from [%s:%d in %s()] - corrupt/incomplete list?\n", + mem, what, file, line, func ); +} + +char * +direct_strdup( const char* file, int line, const char *func, const char *string ) +{ + void *mem; + MemDesc *desc; + size_t length = strlen( string ) + 1; + + mem = malloc( length ); + D_DEBUG_AT( Direct_Mem, " +%6zu bytes [%s:%d in %s()] -> %p \"%30s\"\n", length, file, line, func, mem, string ); + if (!mem) + return NULL; + + direct_memcpy( mem, string, length ); + + if (!direct_config->debugmem) + return mem; + + + /* Debug only. */ + pthread_mutex_lock( &alloc_lock ); + desc = allocate_mem_desc(); + pthread_mutex_unlock( &alloc_lock ); + + if (desc) + fill_mem_desc( desc, mem, length, func, file, line, direct_trace_copy_buffer(NULL) ); + + return mem; +} + +/**********************************************************************************************************************/ + +#else + +void +direct_print_memleaks( void ) +{ +} + +#endif + diff --git a/Source/DirectFB/lib/direct/mem.h b/Source/DirectFB/lib/direct/mem.h new file mode 100755 index 0000000..2366e26 --- /dev/null +++ b/Source/DirectFB/lib/direct/mem.h @@ -0,0 +1,84 @@ +/* + (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 __DIRECT__MEM_H__ +#define __DIRECT__MEM_H__ + +#include + +#include + +void direct_print_memleaks( void ); + + +void direct_free ( const char *file, int line, + const char *func, const char *what, void *mem ); + +void *direct_malloc ( const char *file, int line, + const char *func, size_t bytes ); + +void *direct_calloc ( const char *file, int line, + const char *func, size_t count, size_t bytes); + +void *direct_realloc( const char *file, int line, + const char *func, const char *what, void *mem, + size_t bytes ); + +char *direct_strdup ( const char *file, int line, + const char *func, const char *string ); + + +#if 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 D_FREE(mem) direct_free( __FILE__, __LINE__, __FUNCTION__, #mem, mem ) +#define D_MALLOC(bytes) direct_malloc( __FILE__, __LINE__, __FUNCTION__, bytes ) +#define D_CALLOC(count,bytes) direct_calloc( __FILE__, __LINE__, __FUNCTION__, count, bytes ) +#define D_REALLOC(mem,bytes) direct_realloc( __FILE__, __LINE__, __FUNCTION__, #mem, mem, bytes ) +#define D_STRDUP(string) direct_strdup( __FILE__, __LINE__, __FUNCTION__, string ) + +#else + +#include +#include + +#define D_FREE free +#define D_MALLOC malloc +#define D_CALLOC calloc +#define D_REALLOC realloc +#define D_STRDUP strdup + +#endif + + +#endif + diff --git a/Source/DirectFB/lib/direct/memcpy.c b/Source/DirectFB/lib/direct/memcpy.c new file mode 100755 index 0000000..918853f --- /dev/null +++ b/Source/DirectFB/lib/direct/memcpy.c @@ -0,0 +1,265 @@ +/* + (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 . + + Fast memcpy code was taken from xine (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. +*/ + +#include + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#if defined (ARCH_PPC) || defined (ARCH_ARM) || (SIZEOF_LONG == 8) +# define RUN_BENCHMARK 1 +#else +# define RUN_BENCHMARK 0 +#endif + +#if RUN_BENCHMARK +D_DEBUG_DOMAIN( Direct_Memcpy, "Direct/Memcpy", "Direct's Memcpy Routines" ); +#endif + +#ifdef USE_PPCASM +#include "ppcasm_memcpy.h" +#endif + +#if defined(USE_ARMASM) && !defined(WORDS_BIGENDIAN) +#include "armasm_memcpy.h" +#endif + + +#if SIZEOF_LONG == 8 + +static void * generic64_memcpy( void * to, const void * from, size_t len ) +{ + register u8 *d = (u8*)to; + register const u8 *s = (const u8*)from; + size_t n; + + if (len >= 128) { + unsigned long delta; + + /* Align destination to 8-byte boundary */ + delta = (unsigned long)d & 7; + if (delta) { + len -= 8 - delta; + + if ((unsigned long)d & 1) { + *d++ = *s++; + } + if ((unsigned long)d & 2) { + *((u16*)d) = *((const u16*)s); + d += 2; s += 2; + } + if ((unsigned long)d & 4) { + *((u32*)d) = *((const u32*)s); + d += 4; s += 4; + } + } + + n = len >> 6; + len &= 63; + + for (; n; n--) { + ((u64*)d)[0] = ((const u64*)s)[0]; + ((u64*)d)[1] = ((const u64*)s)[1]; + ((u64*)d)[2] = ((const u64*)s)[2]; + ((u64*)d)[3] = ((const u64*)s)[3]; + ((u64*)d)[4] = ((const u64*)s)[4]; + ((u64*)d)[5] = ((const u64*)s)[5]; + ((u64*)d)[6] = ((const u64*)s)[6]; + ((u64*)d)[7] = ((const u64*)s)[7]; + d += 64; s += 64; + } + } + /* + * Now do the tail of the block + */ + if (len) { + n = len >> 3; + + for (; n; n--) { + *((u64*)d) = *((const u64*)s); + d += 8; s += 8; + } + if (len & 4) { + *((u32*)d) = *((const u32*)s); + d += 4; s += 4; + } + if (len & 2) { + *((u16*)d) = *((const u16*)s); + d += 2; s += 2; + } + if (len & 1) + *d = *s; + } + + return to; +} + +#endif /* SIZEOF_LONG == 8 */ + + +typedef void* (*memcpy_func)(void *to, const void *from, size_t len); + +static struct { + char *name; + char *desc; + memcpy_func function; + unsigned long long time; + u32 cpu_require; +} memcpy_method[] = +{ + { NULL, NULL, NULL, 0, 0}, + { "libc", "libc memcpy()", (memcpy_func) memcpy, 0, 0}, +#if SIZEOF_LONG == 8 + { "generic64","Generic 64bit memcpy()", generic64_memcpy, 0, 0}, +#endif /* SIZEOF_LONG == 8 */ +#ifdef USE_PPCASM + { "ppc", "ppcasm_memcpy()", direct_ppcasm_memcpy, 0, 0}, +#ifdef __LINUX__ + { "ppccache", "ppcasm_cacheable_memcpy()", direct_ppcasm_cacheable_memcpy, 0, 0}, +#endif /* __LINUX__ */ +#endif /* USE_PPCASM */ +#if defined(USE_ARMASM) && !defined(WORDS_BIGENDIAN) + { "arm", "armasm_memcpy()", direct_armasm_memcpy, 0, 0}, +#endif + { NULL, NULL, NULL, 0, 0} +}; + + +static inline unsigned long long int rdtsc( void ) +{ + struct timeval tv; + + gettimeofday (&tv, NULL); + return (tv.tv_sec * 1000000 + tv.tv_usec); +} + + +memcpy_func direct_memcpy = (memcpy_func) memcpy; + +#define BUFSIZE 1024 + +void +direct_find_best_memcpy( void ) +{ + /* Save library size and startup time + on platforms without a special memcpy() implementation. */ +#if RUN_BENCHMARK + unsigned long long t; + char *buf1, *buf2; + int i, j, best = 0; + u32 config_flags = 0; + + if (direct_config->memcpy) { + for (i=1; memcpy_method[i].name; i++) { + if (!strcmp( direct_config->memcpy, memcpy_method[i].name )) { + if (memcpy_method[i].cpu_require & ~config_flags) + break; + + direct_memcpy = memcpy_method[i].function; + + D_INFO( "Direct/Memcpy: Forced to use %s\n", memcpy_method[i].desc ); + + return; + } + } + } + + if (!(buf1 = D_MALLOC( BUFSIZE * 500 ))) + return; + + if (!(buf2 = D_MALLOC( BUFSIZE * 500 ))) { + D_FREE( buf1 ); + return; + } + + D_DEBUG_AT( Direct_Memcpy, "Benchmarking memcpy methods (smaller is better):\n"); + + /* make sure buffers are present on physical memory */ + memcpy( buf1, buf2, BUFSIZE * 500 ); + memcpy( buf2, buf1, BUFSIZE * 500 ); + + for (i=1; memcpy_method[i].name; i++) { + if (memcpy_method[i].cpu_require & ~config_flags) + continue; + + t = rdtsc(); + + for (j=0; j<500; j++) + memcpy_method[i].function( buf1 + j*BUFSIZE, buf2 + j*BUFSIZE, BUFSIZE ); + + t = rdtsc() - t; + memcpy_method[i].time = t; + + D_DEBUG_AT( Direct_Memcpy, "\t%-10s %20lld\n", memcpy_method[i].name, t ); + + if (best == 0 || t < memcpy_method[best].time) + best = i; + } + + if (best) { + direct_memcpy = memcpy_method[best].function; + + D_INFO( "Direct/Memcpy: Using %s\n", memcpy_method[best].desc ); + } + + D_FREE( buf1 ); + D_FREE( buf2 ); +#endif +} + +void +direct_print_memcpy_routines( void ) +{ + int i; + u32 config_flags = 0; + + direct_log_printf( NULL, "\nPossible values for memcpy option are:\n\n" ); + + for (i=1; memcpy_method[i].name; i++) { + bool unsupported = (memcpy_method[i].cpu_require & ~config_flags); + + direct_log_printf( NULL, " %-10s %-27s %s\n", memcpy_method[i].name, + memcpy_method[i].desc, unsupported ? "" : "supported" ); + } + + direct_log_printf( NULL, "\n" ); +} + diff --git a/Source/DirectFB/lib/direct/memcpy.h b/Source/DirectFB/lib/direct/memcpy.h new file mode 100755 index 0000000..374bc54 --- /dev/null +++ b/Source/DirectFB/lib/direct/memcpy.h @@ -0,0 +1,51 @@ +/* + (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 __DIRECT__MEMCPY_H__ +#define __DIRECT__MEMCPY_H__ + +#include +#include + + +void direct_find_best_memcpy( void ); +void direct_print_memcpy_routines( void ); + +extern void *(*direct_memcpy)( void *to, const void *from, size_t len ); + +static __inline__ void *direct_memmove( void *to, const void *from, size_t len ) +{ + if ((from < to && ((const char*) from + len) < ((char*) to)) || + (((char*) to + len) < ((const char*) from))) + return direct_memcpy( to, from, len ); + else + return memmove( to, from, len ); +} + +#endif + diff --git a/Source/DirectFB/lib/direct/messages.c b/Source/DirectFB/lib/direct/messages.c new file mode 100755 index 0000000..21b5978 --- /dev/null +++ b/Source/DirectFB/lib/direct/messages.c @@ -0,0 +1,215 @@ +/* + (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 + + +#if DIRECT_BUILD_TEXT + +__attribute__((no_instrument_function)) +void +direct_messages_info( const char *format, ... ) +{ + char buf[512]; + + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + direct_log_printf( NULL, "(*) %s", buf ); +} + +__attribute__((no_instrument_function)) +void +direct_messages_error( const char *format, ... ) +{ + char buf[512]; + + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + direct_log_printf( NULL, "(!) %s", buf ); + + direct_trace_print_stack( NULL ); +} + +__attribute__((no_instrument_function)) +void +direct_messages_derror( DirectResult result, const char *format, ... ) +{ + char buf[512]; + + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + direct_log_printf( NULL, "(!) %s --> %s\n", buf, DirectResultString( result ) ); + + direct_trace_print_stack( NULL ); +} + +__attribute__((no_instrument_function)) +void +direct_messages_perror( int erno, const char *format, ... ) +{ + char buf[512]; + + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + direct_log_printf( NULL, "(!) %s --> %s\n", buf, strerror( erno ) ); + + direct_trace_print_stack( NULL ); +} + +__attribute__((no_instrument_function)) +void +direct_messages_dlerror( const char *dlerr, const char *format, ... ) +{ + char buf[512]; + + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + direct_log_printf( NULL, "(!) %s --> %s\n", buf, dlerr ); + + direct_trace_print_stack( NULL ); +} + +__attribute__((no_instrument_function)) +void +direct_messages_once( const char *func, + const char *file, + int line, + const char *format, ... ) +{ + char buf[512]; + + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + direct_log_printf( NULL, " (!!!) *** ONCE [%s] *** [%s:%d in %s()]\n", buf, file, line, func ); + + direct_trace_print_stack( NULL ); +} + +__attribute__((no_instrument_function)) +void +direct_messages_unimplemented( const char *func, + const char *file, + int line ) +{ + direct_log_printf( NULL, " (!!!) *** UNIMPLEMENTED [%s] *** [%s:%d]\n", func, file, line ); + + direct_trace_print_stack( NULL ); +} + +__attribute__((no_instrument_function)) +void +direct_messages_bug( const char *func, + const char *file, + int line, + const char *format, ... ) +{ + char buf[512]; + + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + direct_log_printf( NULL, " (!?!) *** BUG [%s] *** [%s:%d in %s()]\n", buf, file, line, func ); + + direct_trace_print_stack( NULL ); +} + +__attribute__((no_instrument_function)) +void +direct_messages_warn( const char *func, + const char *file, + int line, + const char *format, ... ) +{ + char buf[512]; + + va_list ap; + + va_start( ap, format ); + + vsnprintf( buf, sizeof(buf), format, ap ); + + va_end( ap ); + + direct_log_printf( NULL, " (!!!) *** WARNING [%s] *** [%s:%d in %s()]\n", buf, file, line, func ); + + direct_trace_print_stack( NULL ); +} + +#endif + diff --git a/Source/DirectFB/lib/direct/messages.h b/Source/DirectFB/lib/direct/messages.h new file mode 100755 index 0000000..bafce88 --- /dev/null +++ b/Source/DirectFB/lib/direct/messages.h @@ -0,0 +1,173 @@ +/* + (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 __DIRECT__MESSAGES_H__ +#define __DIRECT__MESSAGES_H__ + +#include +#include + + +#if __GNUC__ >= 3 +#define D_FORMAT_PRINTF(n) __attribute__((__format__ (__printf__, n, n+1))) +#else +#define D_FORMAT_PRINTF(n) +#endif + +typedef enum { + DMT_NONE = 0x00000000, /* No message type. */ + + DMT_BANNER = 0x00000001, /* Startup banner. */ + DMT_INFO = 0x00000002, /* Info messages. */ + DMT_WARNING = 0x00000004, /* Warnings. */ + DMT_ERROR = 0x00000008, /* Error messages: regular, with DFBResult, bugs, + system call errors, dlopen errors */ + DMT_UNIMPLEMENTED = 0x00000010, /* Messages notifying unimplemented functionality. */ + DMT_ONCE = 0x00000020, /* One-shot messages .*/ + + DMT_ALL = 0x0000003f /* All types. */ +} DirectMessageType; + +#if DIRECT_BUILD_TEXT + +#include + +#include + + +void direct_messages_info ( const char *format, ... ) D_FORMAT_PRINTF(1); + +void direct_messages_error ( const char *format, ... ) D_FORMAT_PRINTF(1); + +void direct_messages_derror ( DirectResult result, + const char *format, ... ) D_FORMAT_PRINTF(2); + +void direct_messages_perror ( int erno, + const char *format, ... ) D_FORMAT_PRINTF(2); + +void direct_messages_dlerror ( const char *dlerr, + const char *format, ... ) D_FORMAT_PRINTF(2); + +void direct_messages_once ( const char *func, + const char *file, + int line, + const char *format, ... ) D_FORMAT_PRINTF(4); + +void direct_messages_unimplemented( const char *func, + const char *file, + int line ); + +void direct_messages_bug ( const char *func, + const char *file, + int line, + const char *format, ... ) D_FORMAT_PRINTF(4); + +void direct_messages_warn ( const char *func, + const char *file, + int line, + const char *format, ... ) D_FORMAT_PRINTF(4); + + +#define D_INFO(x...) do { \ + if (!(direct_config->quiet & DMT_INFO)) \ + direct_messages_info( x ); \ + } while (0) + +#define D_ERROR(x...) do { \ + if (!(direct_config->quiet & DMT_ERROR)) \ + direct_messages_error( x ); \ + } while (0) + +#define D_DERROR(r,x...) do { \ + if (!(direct_config->quiet & DMT_ERROR)) \ + direct_messages_derror( r, x ); \ + } while (0) + +#define D_PERROR(x...) do { \ + if (!(direct_config->quiet & DMT_ERROR)) \ + direct_messages_perror( errno, x ); \ + } while (0) + +#define D_DLERROR(x...) do { \ + if (!(direct_config->quiet & DMT_ERROR)) \ + direct_messages_dlerror( dlerror(), x ); \ + } while (0) + + +#define D_ONCE(x...) do { \ + if (!(direct_config->quiet & DMT_ONCE)) { \ + static bool first = true; \ + if (first) { \ + direct_messages_once( __FUNCTION__, \ + __FILE__, __LINE__, x ); \ + first = false; \ + } \ + } \ + } while (0) + +#define D_UNIMPLEMENTED() do { \ + if (!(direct_config->quiet & DMT_UNIMPLEMENTED)) { \ + static bool first = true; \ + if (first) { \ + direct_messages_unimplemented( __FUNCTION__, \ + __FILE__, __LINE__ ); \ + first = false; \ + } \ + } \ + } while (0) + +#define D_BUG(x...) do { \ + if (!(direct_config->quiet & DMT_ERROR)) \ + direct_messages_bug( __FUNCTION__, __FILE__, __LINE__, x ); \ + } while (0) + +#define D_WARN(x...) do { \ + if (!(direct_config->quiet & DMT_WARNING)) \ + direct_messages_warn( __FUNCTION__, __FILE__, __LINE__, x );\ + } while (0) + +#define D_OOM() (direct_messages_warn( __FUNCTION__, __FILE__, __LINE__, \ + "out of memory" ), DR_NOLOCALMEMORY) + + +#else + #define D_INFO(x...) do { } while (0) + #define D_ERROR(x...) do { } while (0) + #define D_DERROR(x...) do { } while (0) + #define D_PERROR(x...) do { } while (0) + #define D_DLERROR(x...) do { } while (0) + #define D_ONCE(x...) do { } while (0) + #define D_UNIMPLEMENTED() do { } while (0) + #define D_BUG(x...) do { } while (0) + #define D_WARN(x...) do { } while (0) + #define D_OOM() (printf("out of memory\n"), DR_NOLOCALMEMORY) +#endif + + +#endif + diff --git a/Source/DirectFB/lib/direct/modules.c b/Source/DirectFB/lib/direct/modules.c new file mode 100755 index 0000000..ba3d59b --- /dev/null +++ b/Source/DirectFB/lib/direct/modules.c @@ -0,0 +1,463 @@ +/* + (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 + +#ifdef PIC +#define DYNAMIC_LINKING +#endif + +#ifdef DYNAMIC_LINKING +#include +#endif + +D_DEBUG_DOMAIN( Direct_Modules, "Direct/Modules", "Module loading and registration" ); + +/******************************************************************************/ + +#ifdef DYNAMIC_LINKING + +static DirectModuleEntry *lookup_by_name( const DirectModuleDir *directory, + const char *name ); + +static DirectModuleEntry *lookup_by_file( const DirectModuleDir *directory, + const char *file ); + +static void *open_module ( DirectModuleEntry *module ); +static bool load_module ( DirectModuleEntry *module ); +static void unload_module( DirectModuleEntry *module ); + +#endif + +/******************************************************************************/ + +static int +suppress_module (const char *name) +{ + int i = 0; + + if (!direct_config || !direct_config->disable_module) + return 0; + + while (direct_config->disable_module[i]) { + if (strcmp (direct_config->disable_module[i], name) == 0) { + D_INFO( "Direct/Modules: suppress module '%s'\n", direct_config->disable_module[i] ); + return 1; + } + + i++; + } + + return 0; +} + +void +direct_modules_register( DirectModuleDir *directory, + unsigned int abi_version, + const char *name, + const void *funcs ) +{ + DirectModuleEntry *entry; + + D_ASSERT( directory != NULL ); + D_ASSERT( name != NULL ); + D_ASSERT( funcs != NULL ); + + D_DEBUG_AT( Direct_Modules, "Registering '%s' ('%s')...\n", name, directory->path ); + +#ifdef DYNAMIC_LINKING + if ((entry = lookup_by_name( directory, name )) != NULL) { + D_MAGIC_ASSERT( entry, DirectModuleEntry ); + + entry->loaded = true; + entry->funcs = funcs; + + return; + } +#endif + + if (directory->loading) { + entry = directory->loading; + D_MAGIC_ASSERT( entry, DirectModuleEntry ); + + directory->loading = NULL; + } + else { + entry = D_CALLOC( 1, sizeof(DirectModuleEntry) ); + if (!entry) { + D_OOM(); + return; + } + + D_MAGIC_SET( entry, DirectModuleEntry ); + } + + entry->directory = directory; + entry->loaded = true; + entry->name = D_STRDUP( name ); + entry->funcs = funcs; + + entry->disabled = suppress_module( name ); + + if (abi_version != directory->abi_version) { + D_ERROR( "Direct/Modules: ABI version of '%s' (%d) does not match %d!\n", + entry->file ? entry->file : entry->name, + abi_version, directory->abi_version ); + + entry->disabled = true; + } + + direct_list_prepend( &directory->entries, &entry->link ); + + D_DEBUG_AT( Direct_Modules, "...registered.\n" ); +} + +void +direct_modules_unregister( DirectModuleDir *directory, + const char *name ) +{ + DirectModuleEntry *entry; + + D_DEBUG_AT( Direct_Modules, "Unregistering '%s' ('%s')...\n", name, directory->path ); + +#ifdef DYNAMIC_LINKING + entry = lookup_by_name( directory, name ); + if (!entry) { + D_ERROR( "Direct/Modules: Unregister failed, could not find '%s' module!\n", name ); + return; + } + + D_MAGIC_ASSERT( entry, DirectModuleEntry ); + + D_FREE( entry->name ); + + direct_list_remove( &directory->entries, &entry->link ); + + D_MAGIC_CLEAR( entry ); + + D_FREE( entry ); +#endif + + D_DEBUG_AT( Direct_Modules, "...unregistered.\n" ); +} + +int +direct_modules_explore_directory( DirectModuleDir *directory ) +{ +#ifdef DYNAMIC_LINKING + DIR *dir; + struct dirent *entry = NULL; + struct dirent tmp; + int count = 0; + const char *pathfront = ""; + const char *path; + char *buf; + + D_ASSERT( directory != NULL ); + D_ASSERT( directory->path != NULL ); + + D_DEBUG_AT( Direct_Modules, "%s( '%s' )\n", __FUNCTION__, directory->path ); + + path = directory->path; + + if (path[0] != '/') { + pathfront = direct_config->module_dir; + if (!pathfront) + pathfront = MODULEDIR; + } + + buf = alloca( strlen(pathfront) + 1 + strlen(path) + 1 ); /* pre, slash, post, 0 */ + sprintf( buf, "%s/%s", pathfront, path ); + + dir = opendir( buf ); + if (!dir) { + D_DEBUG_AT( Direct_Modules, " -> ERROR opening directory: %s!\n", strerror(errno) ); + return 0; + } + + while (readdir_r( dir, &tmp, &entry ) == 0 && entry) { + void *handle; + DirectModuleEntry *module; + int entry_len = strlen(entry->d_name); + + if (entry_len < 4 || + entry->d_name[entry_len-1] != 'o' || + entry->d_name[entry_len-2] != 's') + continue; + + if (lookup_by_file( directory, entry->d_name )) + continue; + + + module = D_CALLOC( 1, sizeof(DirectModuleEntry) ); + if (!module) + continue; + + D_MAGIC_SET( module, DirectModuleEntry ); + + module->directory = directory; + module->dynamic = true; + module->file = D_STRDUP( entry->d_name ); + if (!module->file) { + D_MAGIC_CLEAR( module ); + D_FREE( module ); + continue; + } + + directory->loading = module; + + if ((handle = open_module( module )) != NULL) { + if (!module->loaded) { + int len; + void (*func)( void ); + + D_ERROR( "Direct/Modules: Module '%s' did not register itself after loading! " + "Trying default module constructor...\n", entry->d_name ); + + len = strlen( entry->d_name ); + + entry->d_name[len-3] = 0; + + func = dlsym( handle, entry->d_name + 3 ); + if (func) { + func(); + + if (!module->loaded) { + D_ERROR( "Direct/Modules: ... even did not register after " + "explicitly calling the module constructor!\n" ); + } + } + else { + D_ERROR( "Direct/Modules: ... default contructor not found!\n" ); + } + + if (!module->loaded) { + module->disabled = true; + + direct_list_prepend( &directory->entries, + &module->link ); + } + } + + if (module->disabled) { + module->loaded = false; + + /* may call direct_modules_unregister() */ + dlclose( handle ); + } + else { + module->handle = handle; + + count++; + } + } + else { + module->disabled = true; + + direct_list_prepend( &directory->entries, &module->link ); + } + + directory->loading = NULL; + } + + closedir( dir ); + + return count; +#else + return 0; +#endif +} + +const void * +direct_module_ref( DirectModuleEntry *module ) +{ + D_MAGIC_ASSERT( module, DirectModuleEntry ); + + if (module->disabled) + return NULL; + +#ifdef DYNAMIC_LINKING + if (!module->loaded && !load_module( module )) + return NULL; +#endif + + module->refs++; + + return module->funcs; +} + +void +direct_module_unref( DirectModuleEntry *module ) +{ + D_MAGIC_ASSERT( module, DirectModuleEntry ); + D_ASSERT( module->refs > 0 ); + + if (--module->refs) + return; + +#ifdef DYNAMIC_LINKING + if (module->dynamic) + unload_module( module ); +#endif +} + +/******************************************************************************/ + +#ifdef DYNAMIC_LINKING + +static DirectModuleEntry * +lookup_by_name( const DirectModuleDir *directory, + const char *name ) +{ + DirectLink *l; + + D_ASSERT( directory != NULL ); + D_ASSERT( name != NULL ); + + direct_list_foreach (l, directory->entries) { + DirectModuleEntry *entry = (DirectModuleEntry*) l; + + D_MAGIC_ASSERT( entry, DirectModuleEntry ); + + if (!entry->name) + continue; + + if (!strcmp( entry->name, name )) + return entry; + } + + return NULL; +} + +static DirectModuleEntry * +lookup_by_file( const DirectModuleDir *directory, + const char *file ) +{ + DirectLink *l; + + D_ASSERT( directory != NULL ); + D_ASSERT( file != NULL ); + + direct_list_foreach (l, directory->entries) { + DirectModuleEntry *entry = (DirectModuleEntry*) l; + + D_MAGIC_ASSERT( entry, DirectModuleEntry ); + + if (!entry->file) + continue; + + if (!strcmp( entry->file, file )) + return entry; + } + + return NULL; +} + +static bool +load_module( DirectModuleEntry *module ) +{ + D_MAGIC_ASSERT( module, DirectModuleEntry ); + D_ASSERT( module->dynamic == true ); + D_ASSERT( module->file != NULL ); + D_ASSERT( module->loaded == false ); + D_ASSERT( module->disabled == false ); + + module->handle = open_module( module ); + + return module->loaded; +} + +static void +unload_module( DirectModuleEntry *module ) +{ + void *handle; + + D_MAGIC_ASSERT( module, DirectModuleEntry ); + D_ASSERT( module->dynamic == true ); + D_ASSERT( module->handle != NULL ); + D_ASSERT( module->loaded == true ); + + handle = module->handle; + + module->handle = NULL; + module->loaded = false; + + /* may call direct_modules_unregister() */ + dlclose( handle ); +} + +static void * +open_module( DirectModuleEntry *module ) +{ + DirectModuleDir *directory; + const char *pathfront = ""; + const char *path; + char *buf; + void *handle; + + D_MAGIC_ASSERT( module, DirectModuleEntry ); + + D_ASSERT( module->file != NULL ); + D_ASSERT( module->directory != NULL ); + D_ASSERT( module->directory->path != NULL ); + + directory = module->directory; + path = directory->path; + + if (path[0] != '/') { + pathfront = direct_config->module_dir; + if (!pathfront) + pathfront = MODULEDIR; + } + + buf = alloca( strlen( pathfront ) + 1 + strlen( path ) + 1 + strlen( module->file ) + 1 ); + sprintf( buf, "%s/%s/%s", pathfront, path, module->file ); + + D_DEBUG_AT( Direct_Modules, "Loading '%s'...\n", buf ); + + handle = dlopen( buf, RTLD_NOW ); + if (!handle) + D_DLERROR( "Direct/Modules: Unable to dlopen `%s'!\n", buf ); + + return handle; +} + +#endif + diff --git a/Source/DirectFB/lib/direct/modules.h b/Source/DirectFB/lib/direct/modules.h new file mode 100755 index 0000000..ba11b83 --- /dev/null +++ b/Source/DirectFB/lib/direct/modules.h @@ -0,0 +1,95 @@ +/* + (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 __DIRECT__MODULES_H__ +#define __DIRECT__MODULES_H__ + +#include + +#include +#include +#include + + +struct __D_DirectModuleEntry { + DirectLink link; + + int magic; + + DirectModuleDir *directory; + + bool loaded; + bool dynamic; + bool disabled; + + char *name; + const void *funcs; + + int refs; + char *file; + void *handle; +}; + +struct __D_DirectModuleDir { + pthread_mutex_t lock; + + const char *path; + unsigned int abi_version; + + DirectLink *entries; + + DirectModuleEntry *loading; +}; + +#define DECLARE_MODULE_DIRECTORY(d) \ + extern DirectModuleDir d + +#define DEFINE_MODULE_DIRECTORY(d,p,n) \ + DirectModuleDir d = { \ + .lock = PTHREAD_MUTEX_INITIALIZER, \ + .path = p, \ + .abi_version = n, \ + .entries = NULL, \ + .loading = NULL, \ + } + +int direct_modules_explore_directory( DirectModuleDir *directory ); + +void direct_modules_register( DirectModuleDir *directory, + unsigned int abi_version, + const char *name, + const void *funcs ); + +void direct_modules_unregister( DirectModuleDir *directory, + const char *name ); + +const void *direct_module_ref ( DirectModuleEntry *module ); +void direct_module_unref( DirectModuleEntry *module ); + +#endif + diff --git a/Source/DirectFB/lib/direct/ppc_asm.h b/Source/DirectFB/lib/direct/ppc_asm.h new file mode 100755 index 0000000..c35192b --- /dev/null +++ b/Source/DirectFB/lib/direct/ppc_asm.h @@ -0,0 +1,115 @@ +/* Condition Register Bit Fields */ + +#define cr0 0 +#define cr1 1 +#define cr2 2 +#define cr3 3 +#define cr4 4 +#define cr5 5 +#define cr6 6 +#define cr7 7 + + +/* General Purpose Registers (GPRs) */ + +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 +#define r21 21 +#define r22 22 +#define r23 23 +#define r24 24 +#define r25 25 +#define r26 26 +#define r27 27 +#define r28 28 +#define r29 29 +#define r30 30 +#define r31 31 + + +/* Floating Point Registers (FPRs) */ + +#define fr0 0 +#define fr1 1 +#define fr2 2 +#define fr3 3 +#define fr4 4 +#define fr5 5 +#define fr6 6 +#define fr7 7 +#define fr8 8 +#define fr9 9 +#define fr10 10 +#define fr11 11 +#define fr12 12 +#define fr13 13 +#define fr14 14 +#define fr15 15 +#define fr16 16 +#define fr17 17 +#define fr18 18 +#define fr19 19 +#define fr20 20 +#define fr21 21 +#define fr22 22 +#define fr23 23 +#define fr24 24 +#define fr25 25 +#define fr26 26 +#define fr27 27 +#define fr28 28 +#define fr29 29 +#define fr30 30 +#define fr31 31 + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 diff --git a/Source/DirectFB/lib/direct/ppcasm_memcpy.S b/Source/DirectFB/lib/direct/ppcasm_memcpy.S new file mode 100755 index 0000000..04b695b --- /dev/null +++ b/Source/DirectFB/lib/direct/ppcasm_memcpy.S @@ -0,0 +1,77 @@ +/* + * String handling functions for PowerPC. + * + * Copyright (C) 1996 Paul Mackerras. + * + * + * In a mail from Paul on 23.10.2006 05:47: + * + * You may put an LGPL permission statement on that code, replacing the + * GPL permission statement. From a technical point of view, I'm not + * sure that the code in ppcasm_memcpy_cachable.S is the best thing to + * use in userspace, though; for one thing, it has a cache line size + * assumption encoded into it. Why don't you just use the glibc memcpy? + * It's pretty well optimized these days, AFAIK. + * + * Paul. + * + * + * 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 "ppc_asm.h" + + .globl direct_ppcasm_memcpy +direct_ppcasm_memcpy: + srwi. r7,r5,3 + addi r6,r3,-4 + addi r4,r4,-4 + beq 2f /* if less than 8 bytes to do */ + andi. r0,r6,3 /* get dest word aligned */ + mtctr r7 + bne 5f +1: lwz r7,4(r4) + lwzu r8,8(r4) + stw r7,4(r6) + stwu r8,8(r6) + bdnz 1b + andi. r5,r5,7 +2: cmplwi 0,r5,4 + blt 3f + lwzu r0,4(r4) + addi r5,r5,-4 + stwu r0,4(r6) +3: cmpwi 0,r5,0 + beqlr + mtctr r5 + addi r4,r4,3 + addi r6,r6,3 +4: lbzu r0,1(r4) + stbu r0,1(r6) + bdnz 4b + blr +5: subfic r0,r0,4 + mtctr r0 +6: lbz r7,4(r4) + addi r4,r4,1 + stb r7,4(r6) + addi r6,r6,1 + bdnz 6b + subf r5,r0,r5 + rlwinm. r7,r5,32-3,3,31 + beq 2b + mtctr r7 + b 1b diff --git a/Source/DirectFB/lib/direct/ppcasm_memcpy.h b/Source/DirectFB/lib/direct/ppcasm_memcpy.h new file mode 100755 index 0000000..4e7edaf --- /dev/null +++ b/Source/DirectFB/lib/direct/ppcasm_memcpy.h @@ -0,0 +1,7 @@ +#ifndef __DIRECT__PPCASM_MEMCPY_H__ +#define __DIRECT__PPCASM_MEMCPY_H__ + +void *direct_ppcasm_cacheable_memcpy( void *dest, const void *src, size_t n); +void *direct_ppcasm_memcpy ( void *dest, const void *src, size_t n); + +#endif diff --git a/Source/DirectFB/lib/direct/ppcasm_memcpy_cachable.S b/Source/DirectFB/lib/direct/ppcasm_memcpy_cachable.S new file mode 100755 index 0000000..920dea2 --- /dev/null +++ b/Source/DirectFB/lib/direct/ppcasm_memcpy_cachable.S @@ -0,0 +1,180 @@ +/* + * String handling functions for PowerPC. + * + * Copyright (C) 1996 Paul Mackerras. + * + * + * In a mail from Paul on 23.10.2006 05:47: + * + * You may put an LGPL permission statement on that code, replacing the + * GPL permission statement. From a technical point of view, I'm not + * sure that the code in ppcasm_memcpy_cachable.S is the best thing to + * use in userspace, though; for one thing, it has a cache line size + * assumption encoded into it. Why don't you just use the glibc memcpy? + * It's pretty well optimized these days, AFAIK. + * + * Paul. + * + * + * 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. + */ + +#define __ASSEMBLY__ + +#include + +#if defined(CONFIG_8xx) || defined(CONFIG_403GCX) +#define L1_CACHE_LINE_SIZE 16 +#define LG_L1_CACHE_LINE_SIZE 4 +#elif defined(CONFIG_PPC64BRIDGE) +#define L1_CACHE_LINE_SIZE 128 +#define LG_L1_CACHE_LINE_SIZE 7 +#else +#define L1_CACHE_LINE_SIZE 32 +#define LG_L1_CACHE_LINE_SIZE 5 +#endif + +#include "ppc_asm.h" + +#define COPY_16_BYTES \ + lwz r7,4(r4); \ + lwz r8,8(r4); \ + lwz r9,12(r4); \ + lwzu r10,16(r4); \ + stw r7,4(r6); \ + stw r8,8(r6); \ + stw r9,12(r6); \ + stwu r10,16(r6) + +#define COPY_16_BYTES_WITHEX(n) \ +8 ## n ## 0: \ + lwz r7,4(r4); \ +8 ## n ## 1: \ + lwz r8,8(r4); \ +8 ## n ## 2: \ + lwz r9,12(r4); \ +8 ## n ## 3: \ + lwzu r10,16(r4); \ +8 ## n ## 4: \ + stw r7,4(r6); \ +8 ## n ## 5: \ + stw r8,8(r6); \ +8 ## n ## 6: \ + stw r9,12(r6); \ +8 ## n ## 7: \ + stwu r10,16(r6) + +#define COPY_16_BYTES_EXCODE(n) \ +9 ## n ## 0: \ + addi r5,r5,-(16 * n); \ + b 104f; \ +9 ## n ## 1: \ + addi r5,r5,-(16 * n); \ + b 105f; \ +.section __ex_table,"a"; \ + .align 2; \ + .long 8 ## n ## 0b,9 ## n ## 0b; \ + .long 8 ## n ## 1b,9 ## n ## 0b; \ + .long 8 ## n ## 2b,9 ## n ## 0b; \ + .long 8 ## n ## 3b,9 ## n ## 0b; \ + .long 8 ## n ## 4b,9 ## n ## 1b; \ + .long 8 ## n ## 5b,9 ## n ## 1b; \ + .long 8 ## n ## 6b,9 ## n ## 1b; \ + .long 8 ## n ## 7b,9 ## n ## 1b; \ + .text + + .text + + +CACHELINE_MASK = (L1_CACHE_LINE_SIZE - 1) + + .global direct_ppcasm_cacheable_memcpy +direct_ppcasm_cacheable_memcpy: +#if 0 /* this part causes "error loading shared library: unexpected reloc type + 0x0b (???) */ + add r7,r3,r5 /* test if the src & dst overlap */ + add r8,r4,r5 + cmplw 0,r4,r7 + cmplw 1,r3,r8 + crand 0,0,4 /* cr0.lt &= cr1.lt */ + blt ppcasm_memcpy /* if regions overlap */ +#endif + addi r4,r4,-4 + addi r6,r3,-4 + neg r0,r3 + andi. r0,r0,CACHELINE_MASK /* # bytes to start of cache line */ + beq 58f + + cmplw 0,r5,r0 /* is this more than total to do? */ + blt 63f /* if not much to do */ + andi. r8,r0,3 /* get it word-aligned first */ + subf r5,r0,r5 + mtctr r8 + beq+ 61f +70: lbz r9,4(r4) /* do some bytes */ + stb r9,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 70b +61: srwi. r0,r0,2 + mtctr r0 + beq 58f +72: lwzu r9,4(r4) /* do some words */ + stwu r9,4(r6) + bdnz 72b + +58: srwi. r0,r5,LG_L1_CACHE_LINE_SIZE /* complete cachelines */ + clrlwi r5,r5,32-LG_L1_CACHE_LINE_SIZE + li r11,4 + mtctr r0 + beq 63f +53: +#if !defined(CONFIG_8xx) + dcbz r11,r6 +#endif + COPY_16_BYTES +#if L1_CACHE_LINE_SIZE >= 32 + COPY_16_BYTES +#if L1_CACHE_LINE_SIZE >= 64 + COPY_16_BYTES + COPY_16_BYTES +#if L1_CACHE_LINE_SIZE >= 128 + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES + COPY_16_BYTES +#endif +#endif +#endif + bdnz 53b + +63: srwi. r0,r5,2 + mtctr r0 + beq 64f +30: lwzu r0,4(r4) + stwu r0,4(r6) + bdnz 30b + +64: andi. r0,r5,3 + mtctr r0 + beq+ 65f +40: lbz r0,4(r4) + stb r0,4(r6) + addi r4,r4,1 + addi r6,r6,1 + bdnz 40b +65: blr + diff --git a/Source/DirectFB/lib/direct/serial.h b/Source/DirectFB/lib/direct/serial.h new file mode 100755 index 0000000..d201708 --- /dev/null +++ b/Source/DirectFB/lib/direct/serial.h @@ -0,0 +1,118 @@ +/* + (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 __DIRECT__SERIAL_H__ +#define __DIRECT__SERIAL_H__ + +#include +#include + +struct __D_DirectSerial { + int magic; + + u32 value; + u32 overflow; +}; + +static __inline__ void +direct_serial_init( DirectSerial *serial ) +{ + D_ASSERT( serial != NULL ); + + serial->value = 0; + serial->overflow = 0; + + D_MAGIC_SET( serial, DirectSerial ); +} + +static __inline__ void +direct_serial_deinit( DirectSerial *serial ) +{ + D_MAGIC_CLEAR( serial ); +} + +static __inline__ void +direct_serial_increase( DirectSerial *serial ) +{ + D_MAGIC_ASSERT( serial, DirectSerial ); + + if (! ++serial->value) + serial->overflow++; +} + +static __inline__ void +direct_serial_copy( DirectSerial *serial, const DirectSerial *source ) +{ + D_MAGIC_ASSERT( serial, DirectSerial ); + D_MAGIC_ASSERT( source, DirectSerial ); + + serial->value = source->value; + serial->overflow = source->overflow; +} + +static __inline__ bool +direct_serial_check( DirectSerial *serial, const DirectSerial *source ) +{ + D_MAGIC_ASSERT( serial, DirectSerial ); + D_MAGIC_ASSERT( source, DirectSerial ); + + if (serial->overflow < source->overflow) + return false; + else if (serial->overflow == source->overflow && serial->value < source->value) + return false; + + D_ASSUME( serial->value == source->value ); + + return true; +} + +static __inline__ bool +direct_serial_update( DirectSerial *serial, const DirectSerial *source ) +{ + D_MAGIC_ASSERT( serial, DirectSerial ); + D_MAGIC_ASSERT( source, DirectSerial ); + + if (serial->overflow < source->overflow) { + serial->overflow = source->overflow; + serial->value = source->value; + + return true; + } + else if (serial->overflow == source->overflow && serial->value < source->value) { + serial->value = source->value; + + return true; + } + + D_ASSUME( serial->value == source->value ); + + return false; +} + +#endif + diff --git a/Source/DirectFB/lib/direct/signals.c b/Source/DirectFB/lib/direct/signals.c new file mode 100755 index 0000000..5b0310a --- /dev/null +++ b/Source/DirectFB/lib/direct/signals.c @@ -0,0 +1,480 @@ +/* + (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 + +D_DEBUG_DOMAIN( Direct_Signals, "Direct/Signals", "Signal handling" ); + + +struct __D_DirectSignalHandler { + DirectLink link; + + int magic; + + int num; + DirectSignalHandlerFunc func; + void *ctx; +}; + +/**************************************************************************************************/ + +typedef struct { + int signum; + struct sigaction old_action; +} SigHandled; + +static int sigs_to_handle[] = { /*SIGALRM,*/ SIGHUP, SIGINT, /*SIGPIPE,*/ /*SIGPOLL,*/ + SIGTERM, /*SIGUSR1, SIGUSR2,*/ /*SIGVTALRM,*/ + /*SIGSTKFLT,*/ SIGABRT, SIGFPE, SIGILL, SIGQUIT, + SIGSEGV, SIGTRAP, /*SIGSYS, SIGEMT,*/ SIGBUS, + SIGXCPU, SIGXFSZ }; + +#define NUM_SIGS_TO_HANDLE ((int)D_ARRAY_SIZE( sigs_to_handle )) + +static SigHandled sigs_handled[NUM_SIGS_TO_HANDLE]; + +static DirectLink *handlers = NULL; +static pthread_mutex_t handlers_lock; + +/**************************************************************************************************/ + +static void install_handlers( void ); +static void remove_handlers( void ); + +/**************************************************************************************************/ + +DirectResult +direct_signals_initialize( void ) +{ + D_DEBUG_AT( Direct_Signals, "Initializing...\n" ); + + direct_util_recursive_pthread_mutex_init( &handlers_lock ); + + install_handlers(); + + return DR_OK; +} + +DirectResult +direct_signals_shutdown( void ) +{ + D_DEBUG_AT( Direct_Signals, "Shutting down...\n" ); + + remove_handlers(); + + pthread_mutex_destroy( &handlers_lock ); + + return DR_OK; +} + +void +direct_signals_block_all( void ) +{ + sigset_t signals; + + D_DEBUG_AT( Direct_Signals, "Blocking all signals from now on!\n" ); + + sigfillset( &signals ); + + if (pthread_sigmask( SIG_BLOCK, &signals, NULL )) + D_PERROR( "Direct/Signals: Setting signal mask failed!\n" ); +} + +DirectResult +direct_signal_handler_add( int num, + DirectSignalHandlerFunc func, + void *ctx, + DirectSignalHandler **ret_handler ) +{ + DirectSignalHandler *handler; + + D_ASSERT( func != NULL ); + D_ASSERT( ret_handler != NULL ); + + D_DEBUG_AT( Direct_Signals, + "Adding handler %p for signal %d with context %p...\n", func, num, ctx ); + + handler = D_CALLOC( 1, sizeof(DirectSignalHandler) ); + if (!handler) { + D_WARN( "out of memory" ); + return DR_NOLOCALMEMORY; + } + + handler->num = num; + handler->func = func; + handler->ctx = ctx; + + D_MAGIC_SET( handler, DirectSignalHandler ); + + pthread_mutex_lock( &handlers_lock ); + direct_list_append( &handlers, &handler->link ); + pthread_mutex_unlock( &handlers_lock ); + + *ret_handler = handler; + + return DR_OK; +} + +DirectResult +direct_signal_handler_remove( DirectSignalHandler *handler ) +{ + D_MAGIC_ASSERT( handler, DirectSignalHandler ); + + D_DEBUG_AT( Direct_Signals, "Removing handler %p for signal %d with context %p...\n", + handler->func, handler->num, handler->ctx ); + + pthread_mutex_lock( &handlers_lock ); + direct_list_remove( &handlers, &handler->link ); + pthread_mutex_unlock( &handlers_lock ); + + D_MAGIC_CLEAR( handler ); + + D_FREE( handler ); + + return DR_OK; +} + +/**************************************************************************************************/ + +static bool +show_segv( const siginfo_t *info ) +{ + switch (info->si_code) { +#ifdef SEGV_MAPERR + case SEGV_MAPERR: + direct_log_printf( NULL, " (at %p, invalid address) <--\n", info->si_addr ); + return true; +#endif +#ifdef SEGV_ACCERR + case SEGV_ACCERR: + direct_log_printf( NULL, " (at %p, invalid permissions) <--\n", info->si_addr ); + return true; +#endif + } + return false; +} + +static bool +show_bus( const siginfo_t *info ) +{ + switch (info->si_code) { +#ifdef BUG_ADRALN + case BUS_ADRALN: + direct_log_printf( NULL, " (at %p, invalid address alignment) <--\n", info->si_addr ); + return true; +#endif +#ifdef BUS_ADRERR + case BUS_ADRERR: + direct_log_printf( NULL, " (at %p, non-existent physical address) <--\n", info->si_addr ); + return true; +#endif +#ifdef BUS_OBJERR + case BUS_OBJERR: + direct_log_printf( NULL, " (at %p, object specific hardware error) <--\n", info->si_addr ); + return true; +#endif + } + + return false; +} + +static bool +show_ill( const siginfo_t *info ) +{ + switch (info->si_code) { +#ifdef ILL_ILLOPC + case ILL_ILLOPC: + direct_log_printf( NULL, " (at %p, illegal opcode) <--\n", info->si_addr ); + return true; +#endif +#ifdef ILL_ILLOPN + case ILL_ILLOPN: + direct_log_printf( NULL, " (at %p, illegal operand) <--\n", info->si_addr ); + return true; +#endif +#ifdef ILL_ILLADR + case ILL_ILLADR: + direct_log_printf( NULL, " (at %p, illegal addressing mode) <--\n", info->si_addr ); + return true; +#endif +#ifdef ILL_ILLTRP + case ILL_ILLTRP: + direct_log_printf( NULL, " (at %p, illegal trap) <--\n", info->si_addr ); + return true; +#endif +#ifdef ILL_PRVOPC + case ILL_PRVOPC: + direct_log_printf( NULL, " (at %p, privileged opcode) <--\n", info->si_addr ); + return true; +#endif +#ifdef ILL_PRVREG + case ILL_PRVREG: + direct_log_printf( NULL, " (at %p, privileged register) <--\n", info->si_addr ); + return true; +#endif +#ifdef ILL_COPROC + case ILL_COPROC: + direct_log_printf( NULL, " (at %p, coprocessor error) <--\n", info->si_addr ); + return true; +#endif +#ifdef ILL_BADSTK + case ILL_BADSTK: + direct_log_printf( NULL, " (at %p, internal stack error) <--\n", info->si_addr ); + return true; +#endif + } + + return false; +} + +static bool +show_fpe( const siginfo_t *info ) +{ + switch (info->si_code) { +#ifdef FPE_INTDIV + case FPE_INTDIV: + direct_log_printf( NULL, " (at %p, integer divide by zero) <--\n", info->si_addr ); + return true; +#endif +#ifdef FPE_FLTDIV + case FPE_FLTDIV: + direct_log_printf( NULL, " (at %p, floating point divide by zero) <--\n", info->si_addr ); + return true; +#endif + } + + direct_log_printf( NULL, " (at %p) <--\n", info->si_addr ); + + return true; +} + +static bool +show_any( const siginfo_t *info ) +{ + switch (info->si_code) { +#ifdef SI_USER + case SI_USER: + direct_log_printf( NULL, " (sent by pid %d, uid %d) <--\n", info->si_pid, info->si_uid ); + return true; +#endif +#ifdef SI_KERNEL + case SI_KERNEL: + direct_log_printf( NULL, " (sent by the kernel) <--\n" ); + return true; +#endif + } + return false; +} + +static void +#ifdef SA_SIGINFO +signal_handler( int num, siginfo_t *info, void *foo ) +#else +signal_handler( int num ) +#endif +{ + DirectLink *l, *n; + void *addr = NULL; + int pid = direct_gettid(); + long long millis = direct_clock_get_millis(); + + fflush(stdout); + fflush(stderr); + + direct_log_printf( NULL, "(!) [%5d: %4lld.%03lld] --> Caught signal %d", + pid, millis/1000, millis%1000, num ); + +#ifdef SA_SIGINFO + if (info && info > (siginfo_t*) 0x100) { + bool shown = false; + + if (info->si_code > 0 && info->si_code < 0x80) { + addr = info->si_addr; + + switch (num) { + case SIGSEGV: + shown = show_segv( info ); + break; + + case SIGBUS: + shown = show_bus( info ); + break; + + case SIGILL: + shown = show_ill( info ); + break; + + case SIGFPE: + shown = show_fpe( info ); + break; + + default: + direct_log_printf( NULL, " <--\n" ); + addr = NULL; + shown = true; + break; + } + } + else + shown = show_any( info ); + + if (!shown) + direct_log_printf( NULL, " (unknown origin) <--\n" ); + } + else +#endif + direct_log_printf( NULL, ", no siginfo available <--\n" ); + + direct_trace_print_stacks(); + + /* Loop through all handlers. */ + pthread_mutex_lock( &handlers_lock ); + + direct_list_foreach_safe (l, n, handlers) { + DirectSignalHandler *handler = (DirectSignalHandler*) l; + + if (handler->num != num && handler->num != DIRECT_SIGNAL_ANY) + continue; + + switch (handler->func( num, addr, handler->ctx )) { + case DSHR_OK: + break; + + case DSHR_REMOVE: + direct_list_remove( &handlers, &handler->link ); + D_MAGIC_CLEAR( handler ); + D_FREE( handler ); + break; + + case DSHR_RESUME: + millis = direct_clock_get_millis(); + + direct_log_printf( NULL, "(!) [%5d: %4lld.%03lld] -> cured!\n", + pid, millis / 1000, millis % 1000 ); + pthread_mutex_unlock( &handlers_lock ); + return; + + default: + D_BUG( "unknown result" ); + break; + } + } + + pthread_mutex_unlock( &handlers_lock ); + + +// sleep(100); + + + remove_handlers(); + + raise( num ); + + abort(); + + exit( -num ); +} + +/**************************************************************************************************/ + +static void +install_handlers( void ) +{ + int i; + + for (i=0; isighandler && !sigismember( &direct_config->dont_catch, + sigs_to_handle[i] )) + { + struct sigaction action; + int signum = sigs_to_handle[i]; + +#ifdef SA_SIGINFO + action.sa_sigaction = signal_handler; + action.sa_flags = SA_SIGINFO; +#else + action.sa_handler = signal_handler; + action.sa_flags = 0; +#endif + + if (signum != SIGSEGV) + action.sa_flags |= SA_NODEFER; + + sigemptyset( &action.sa_mask ); + + if (sigaction( signum, &action, &sigs_handled[i].old_action )) { + D_PERROR( "Direct/Signals: " + "Unable to install signal handler for signal %d!\n", signum ); + continue; + } + + sigs_handled[i].signum = signum; + } + } +} + +static void +remove_handlers( void ) +{ + int i; + + for (i=0; i, + 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 __DIRECT__SIGNALS_H__ +#define __DIRECT__SIGNALS_H__ + +#include + + +typedef enum { + DSHR_OK, + DSHR_REMOVE, + DSHR_RESUME +} DirectSignalHandlerResult; + +typedef DirectSignalHandlerResult (*DirectSignalHandlerFunc)( int num, + void *addr, + void *ctx ); + + +DirectResult direct_signals_initialize( void ); +DirectResult direct_signals_shutdown( void ); + +/* + * Modifies the current thread's signal mask to block everything. + * Should be called by input threads once to avoid killing themselves + * in the signal handler by deinitializing all input drivers. + */ +void direct_signals_block_all( void ); + +/* + * Signal number to use when registering a handler for any interrupt. + */ +#define DIRECT_SIGNAL_ANY -1 + + +DirectResult direct_signal_handler_add ( int num, + DirectSignalHandlerFunc func, + void *ctx, + DirectSignalHandler **ret_handler ); + +DirectResult direct_signal_handler_remove( DirectSignalHandler *handler ); + + +#endif diff --git a/Source/DirectFB/lib/direct/stream.c b/Source/DirectFB/lib/direct/stream.c new file mode 100755 index 0000000..1e531d9 --- /dev/null +++ b/Source/DirectFB/lib/direct/stream.c @@ -0,0 +1,2286 @@ +/* + (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 + + +struct __D_DirectStream { + int magic; + int ref; + + int fd; + unsigned int offset; + int length; + + char *mime; + + /* cache for piped streams */ + void *cache; + unsigned int cache_size; + +#if DIRECT_BUILD_NETWORK + /* remote streams data */ + struct { + int sd; + + char *host; + int port; + struct addrinfo *addr; + + char *user; + char *pass; + char *auth; + + char *path; + + int redirects; + + void *data; + + bool real_rtsp; + bool real_pack; + } remote; +#endif + + DirectResult (*wait) ( DirectStream *stream, + unsigned int length, + struct timeval *tv ); + DirectResult (*peek) ( DirectStream *stream, + unsigned int length, + int offset, + void *buf, + unsigned int *read_out ); + DirectResult (*read) ( DirectStream *stream, + unsigned int length, + void *buf, + unsigned int *read_out ); + DirectResult (*seek) ( DirectStream *stream, + unsigned int offset ); +}; + + +static void direct_stream_close( DirectStream *stream ); + + +#if DIRECT_BUILD_NETWORK +D_DEBUG_DOMAIN( Direct_Stream, "Direct/Stream", "Stream wrapper" ); +#endif + +/************************** Begin Network Support ***************************/ + +#if DIRECT_BUILD_NETWORK + +#define NET_TIMEOUT 15 +#define HTTP_PORT 80 +#define FTP_PORT 21 +#define RTSP_PORT 554 +#define HTTP_MAX_REDIRECTS 15 + +static DirectResult http_open( DirectStream *stream, const char *filename ); +static DirectResult ftp_open ( DirectStream *stream, const char *filename ); +static DirectResult rtsp_open( DirectStream *stream, const char *filename ); + + +static inline char* trim( char *s ) +{ + char *e; + +#define space( c ) ((c) == ' ' || (c) == '\t' || \ + (c) == '\r' || (c) == '\n' || \ + (c) == '"' || (c) == '\'') + + for (; space(*s); s++); + + e = s + strlen(s) - 1; + for (; e > s && space(*e); *e-- = '\0'); + +#undef space + + return s; +} + +static void +parse_url( const char *url, char **ret_host, int *ret_port, + char **ret_user, char **ret_pass, char **ret_path ) +{ + char *host = NULL; + int port = 0; + char *user = NULL; + char *pass = NULL; + char *path; + char *tmp; + + tmp = strchr( url, '/' ); + if (tmp) { + host = alloca( tmp - url + 1 ); + memcpy( host, url, tmp - url ); + host[tmp-url] = '\0'; + path = tmp; + } else { + host = alloca( strlen( url ) + 1 ); + memcpy( host, url, strlen( url ) + 1 ); + path = "/"; + } + + tmp = strrchr( host, '@' ); + if (tmp) { + *tmp = '\0'; + pass = strchr( host, ':' ); + if (pass) { + *pass = '\0'; + pass++; + } + user = host; + host = tmp + 1; + } + + tmp = strchr( host, ':' ); + if (tmp) { + port = strtol( tmp+1, NULL, 10 ); + *tmp = '\0'; + } + + /* IPv6 variant (host within brackets) */ + if (*host == '[') { + host++; + tmp = strchr( host, ']' ); + if (tmp) + *tmp = '\0'; + } + + if (ret_host) + *ret_host = D_STRDUP( host ); + + if (ret_port && port) + *ret_port = port; + + if (ret_user && user) + *ret_user = D_STRDUP( user ); + + if (ret_pass && pass) + *ret_pass = D_STRDUP( pass ); + + if (ret_path) + *ret_path = D_STRDUP( path ); +} + +/*****************************************************************************/ + +static int +net_response( DirectStream *stream, char *buf, size_t size ) +{ + fd_set set; + struct timeval tv; + int i; + + FD_ZERO( &set ); + FD_SET( stream->remote.sd, &set ); + + for (i = 0; i < size-1; i++) { + tv.tv_sec = NET_TIMEOUT; + tv.tv_usec = 0; + select( stream->remote.sd+1, &set, NULL, NULL, &tv ); + + if (recv( stream->remote.sd, buf+i, 1, 0 ) != 1) + break; + + if (buf[i] == '\n') { + if (i > 0 && buf[i-1] == '\r') + i--; + break; + } + } + + buf[i] = '\0'; + + D_DEBUG_AT( Direct_Stream, "got [%s].\n", buf ); + + return i; +} + +static int +net_command( DirectStream *stream, char *buf, size_t size ) +{ + fd_set s; + struct timeval t; + int status; + int version; + char space; + + FD_ZERO( &s ); + FD_SET( stream->remote.sd, &s ); + + t.tv_sec = NET_TIMEOUT; + t.tv_usec = 0; + + switch (select( stream->remote.sd+1, NULL, &s, NULL, &t )) { + case 0: + D_DEBUG_AT( Direct_Stream, "Timeout!\n" ); + case -1: + return -1; + } + + send( stream->remote.sd, buf, strlen(buf), 0 ); + send( stream->remote.sd, "\r\n", 2, 0 ); + + D_DEBUG_AT( Direct_Stream, "sent [%s].\n", buf ); + + while (net_response( stream, buf, size ) > 0) { + status = 0; + if (sscanf( buf, "HTTP/1.%d %3d", &version, &status ) == 2 || + sscanf( buf, "RTSP/1.%d %3d", &version, &status ) == 2 || + sscanf( buf, "ICY %3d", &status ) == 1 || + sscanf( buf, "%3d%[ ]", &status, &space ) == 2) + return status; + } + + return 0; +} + +static DirectResult +net_wait( DirectStream *stream, + unsigned int length, + struct timeval *tv ) +{ + fd_set s; + + if (stream->cache_size >= length) + return DR_OK; + + if (stream->fd == -1) + return DR_EOF; + + FD_ZERO( &s ); + FD_SET( stream->fd, &s ); + + switch (select( stream->fd+1, &s, NULL, NULL, tv )) { + case 0: + if (!tv && !stream->cache_size) + return DR_EOF; + return DR_TIMEOUT; + case -1: + return errno2result( errno ); + } + + return DR_OK; +} + +static DirectResult +net_peek( DirectStream *stream, + unsigned int length, + int offset, + void *buf, + unsigned int *read_out ) +{ + char *tmp; + int size; + + if (offset < 0) + return DR_UNSUPPORTED; + + tmp = alloca( length + offset ); + + size = recv( stream->fd, tmp, length+offset, MSG_PEEK ); + switch (size) { + case 0: + return DR_EOF; + case -1: + if (errno == EAGAIN || errno == EWOULDBLOCK) + return DR_BUFFEREMPTY; + return errno2result( errno ); + default: + if (size < offset) + return DR_BUFFEREMPTY; + size -= offset; + break; + } + + direct_memcpy( buf, tmp+offset, size ); + + if (read_out) + *read_out = size; + + return DR_OK; +} + +static DirectResult +net_read( DirectStream *stream, + unsigned int length, + void *buf, + unsigned int *read_out ) +{ + int size; + + size = recv( stream->fd, buf, length, 0 ); + switch (size) { + case 0: + return DR_EOF; + case -1: + if (errno == EAGAIN || errno == EWOULDBLOCK) + return DR_BUFFEREMPTY; + return errno2result( errno ); + } + + stream->offset += size; + + if (read_out) + *read_out = size; + + return DR_OK; +} + +static DirectResult +net_connect( struct addrinfo *addr, int sock, int proto, int *ret_fd ) +{ + DirectResult ret = DR_OK; + int fd = -1; + struct addrinfo *tmp; + + D_ASSERT( addr != NULL ); + D_ASSERT( ret_fd != NULL ); + + for (tmp = addr; tmp; tmp = tmp->ai_next) { + int err; + + fd = socket( tmp->ai_family, sock, proto ); + if (fd < 0) { + ret = errno2result( errno ); + D_DEBUG_AT( Direct_Stream, + "failed to create socket!\n\t->%s", + strerror(errno) ); + continue; + } + + fcntl( fd, F_SETFL, fcntl( fd, F_GETFL ) | O_NONBLOCK ); + + D_DEBUG_AT( Direct_Stream, + "connecting to %s...\n", tmp->ai_canonname ); + + if (proto == IPPROTO_UDP) + err = bind( fd, tmp->ai_addr, tmp->ai_addrlen ); + else + err = connect( fd, tmp->ai_addr, tmp->ai_addrlen ); + + if (err == 0 || errno == EINPROGRESS) { + struct timeval t = { NET_TIMEOUT, 0 }; + fd_set s; + + /* Join multicast group? */ + if (tmp->ai_addr->sa_family == AF_INET) { + struct sockaddr_in *saddr = (struct sockaddr_in *) tmp->ai_addr; + + if (IN_MULTICAST( ntohl(saddr->sin_addr.s_addr) )) { + struct ip_mreq req; + + D_DEBUG_AT( Direct_Stream, + "joining multicast group (%u.%u.%u.%u)...\n", + (u8)tmp->ai_addr->sa_data[2], (u8)tmp->ai_addr->sa_data[3], + (u8)tmp->ai_addr->sa_data[4], (u8)tmp->ai_addr->sa_data[5] ); + + req.imr_multiaddr.s_addr = saddr->sin_addr.s_addr; + req.imr_interface.s_addr = 0; + + err = setsockopt( fd, SOL_IP, IP_ADD_MEMBERSHIP, &req, sizeof(req) ); + if (err < 0) { + ret = errno2result( errno ); + D_PERROR( "Direct/Stream: Could not join multicast group (%u.%u.%u.%u)!\n", + (u8)tmp->ai_addr->sa_data[2], (u8)tmp->ai_addr->sa_data[3], + (u8)tmp->ai_addr->sa_data[4], (u8)tmp->ai_addr->sa_data[5] ); + close( fd ); + continue; + } + + setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, saddr, sizeof(*saddr) ); + } + } + + FD_ZERO( &s ); + FD_SET( fd, &s ); + + err = select( fd+1, NULL, &s, NULL, &t ); + if (err < 1) { + D_DEBUG_AT( Direct_Stream, "...connection failed.\n" ); + + close( fd ); + fd = -1; + + if (err == 0) { + ret = DR_TIMEOUT; + continue; + } else { + ret = errno2result( errno ); + break; + } + } + + D_DEBUG_AT( Direct_Stream, "...connected.\n" ); + + ret = DR_OK; + break; + } + } + + *ret_fd = fd; + + return ret; +} + +static DirectResult +net_open( DirectStream *stream, const char *filename, int proto ) +{ + DirectResult ret = DR_OK; + int sock = (proto == IPPROTO_TCP) ? SOCK_STREAM : SOCK_DGRAM; + struct addrinfo hints; + char port[16]; + + parse_url( filename, + &stream->remote.host, + &stream->remote.port, + &stream->remote.user, + &stream->remote.pass, + &stream->remote.path ); + + snprintf( port, sizeof(port), "%d", stream->remote.port ); + + memset( &hints, 0, sizeof(hints) ); + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = sock; + hints.ai_family = PF_UNSPEC; + + if (getaddrinfo( stream->remote.host, port, + &hints, &stream->remote.addr )) { + D_ERROR( "Direct/Stream: " + "failed to resolve host '%s'!\n", stream->remote.host ); + return DR_FAILURE; + } + + ret = net_connect( stream->remote.addr, sock, proto, &stream->remote.sd ); + if (ret) + return ret; + + stream->fd = stream->remote.sd; + stream->length = -1; + stream->wait = net_wait; + stream->peek = net_peek; + stream->read = net_read; + + return ret; +} + +/*****************************************************************************/ + +static DirectResult +http_seek( DirectStream *stream, unsigned int offset ) +{ + DirectResult ret; + char buf[1280]; + int status, len; + + close( stream->remote.sd ); + stream->remote.sd = -1; + + ret = net_connect( stream->remote.addr, + SOCK_STREAM, IPPROTO_TCP, &stream->remote.sd ); + if (ret) + return ret; + + stream->fd = stream->remote.sd; + + len = snprintf( buf, sizeof(buf), + "GET %s HTTP/1.0\r\n" + "Host: %s:%d\r\n", + stream->remote.path, + stream->remote.host, + stream->remote.port ); + if (stream->remote.auth) { + len += snprintf( buf+len, sizeof(buf)-len, + "Authorization: Basic %s\r\n", + stream->remote.auth ); + } + snprintf( buf+len, sizeof(buf)-len, + "User-Agent: DirectFB/%s\r\n" + "Accept: */*\r\n" + "Range: bytes=%d-\r\n" + "Connection: Close\r\n", + DIRECTFB_VERSION, offset ); + + status = net_command( stream, buf, sizeof(buf) ); + switch (status) { + case 200 ... 299: + stream->offset = offset; + break; + default: + if (status) + D_DEBUG_AT( Direct_Stream, + "server returned status %d.\n", status ); + return DR_FAILURE; + } + + /* discard remaining headers */ + while (net_response( stream, buf, sizeof(buf) ) > 0); + + return DR_OK; +} + +static DirectResult +http_open( DirectStream *stream, const char *filename ) +{ + DirectResult ret; + char buf[1280]; + int status, len; + + stream->remote.port = HTTP_PORT; + + ret = net_open( stream, filename, IPPROTO_TCP ); + if (ret) + return ret; + + if (stream->remote.user) { + char *tmp; + + if (stream->remote.pass) { + tmp = alloca( strlen( stream->remote.user ) + + strlen( stream->remote.pass ) + 2 ); + len = sprintf( tmp, "%s:%s", + stream->remote.user, stream->remote.pass ); + } else { + tmp = alloca( strlen( stream->remote.user ) + 2 ); + len = sprintf( tmp, "%s:", stream->remote.user ); + } + + stream->remote.auth = direct_base64_encode( tmp, len ); + } + + len = snprintf( buf, sizeof(buf), + "GET %s HTTP/1.0\r\n" + "Host: %s:%d\r\n", + stream->remote.path, + stream->remote.host, + stream->remote.port ); + if (stream->remote.auth) { + len += snprintf( buf+len, sizeof(buf)-len, + "Authorization: Basic %s\r\n", + stream->remote.auth ); + } + snprintf( buf+len, sizeof(buf)-len, + "User-Agent: DirectFB/%s\r\n" + "Accept: */*\r\n" + "Connection: Close\r\n", + DIRECTFB_VERSION ); + + status = net_command( stream, buf, sizeof(buf) ); + + while (net_response( stream, buf, sizeof(buf) ) > 0) { + if (!strncasecmp( buf, "Accept-Ranges:", 14 )) { + if (strcmp( trim( buf+14 ), "none" )) + stream->seek = http_seek; + } + else if (!strncasecmp( buf, "Content-Type:", 13 )) { + char *mime = trim( buf+13 ); + char *tmp = strchr( mime, ';' ); + if (tmp) + *tmp = '\0'; + if (stream->mime) + D_FREE( stream->mime ); + stream->mime = D_STRDUP( mime ); + } + else if (!strncasecmp( buf, "Content-Length:", 15 )) { + char *tmp = trim( buf+15 ); + if (sscanf( tmp, "%d", &stream->length ) < 1) + sscanf( tmp, "bytes=%d", &stream->length ); + } + else if (!strncasecmp( buf, "Location:", 9 )) { + direct_stream_close( stream ); + stream->seek = NULL; + + if (++stream->remote.redirects > HTTP_MAX_REDIRECTS) { + D_ERROR( "Direct/Stream: " + "reached maximum number of redirects (%d).\n", + HTTP_MAX_REDIRECTS ); + return DR_LIMITEXCEEDED; + } + + filename = trim( buf+9 ); + if (!strncmp( filename, "http://", 7 )) + return http_open( stream, filename+7 ); + if (!strncmp( filename, "ftp://", 6 )) + return ftp_open( stream, filename+6 ); + if (!strncmp( filename, "rtsp://", 7 )) + return rtsp_open( stream, filename+7 ); + + return DR_UNSUPPORTED; + } + } + + switch (status) { + case 200 ... 299: + break; + default: + if (status) + D_DEBUG_AT( Direct_Stream, + "server returned status %d.\n", status ); + return (status == 404) ? DR_FILENOTFOUND : DR_FAILURE; + } + + return DR_OK; +} + +/*****************************************************************************/ + +static DirectResult +ftp_open_pasv( DirectStream *stream, char *buf, size_t size ) +{ + DirectResult ret; + int i, len; + + snprintf( buf, size, "PASV" ); + if (net_command( stream, buf, size ) != 227) + return DR_FAILURE; + + /* parse IP and port for passive mode */ + for (i = 4; buf[i]; i++) { + unsigned int d[6]; + + if (sscanf( &buf[i], "%u,%u,%u,%u,%u,%u", + &d[0], &d[1], &d[2], &d[3], &d[4], &d[5] ) == 6) + { + struct addrinfo hints, *addr; + + /* address */ + len = snprintf( buf, size, + "%u.%u.%u.%u", + d[0], d[1], d[2], d[3] ); + /* port */ + snprintf( buf+len+1, size-len-1, + "%u", ((d[4] & 0xff) << 8) | (d[5] & 0xff) ); + + memset( &hints, 0, sizeof(hints) ); + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + + if (getaddrinfo( buf, buf+len+1, &hints, &addr )) { + D_DEBUG_AT( Direct_Stream, + "failed to resolve host '%s'.\n", buf ); + return DR_FAILURE; + } + + ret = net_connect( addr, SOCK_STREAM, IPPROTO_TCP, &stream->fd ); + + freeaddrinfo( addr ); + + return ret; + } + } + + return DR_FAILURE; +} + +static DirectResult +ftp_seek( DirectStream *stream, unsigned int offset ) +{ + DirectResult ret = DR_OK; + char buf[512]; + + if (stream->fd > 0) { + int status; + + close( stream->fd ); + stream->fd = -1; + + /* ignore response */ + while (net_response( stream, buf, sizeof(buf) ) > 0) { + if (sscanf( buf, "%3d%[ ]", &status, buf ) == 2) + break; + } + } + + ret = ftp_open_pasv( stream, buf, sizeof(buf) ); + if (ret) + return ret; + + snprintf( buf, sizeof(buf), "REST %d", offset ); + if (net_command( stream, buf, sizeof(buf) ) != 350) + goto error; + + snprintf( buf, sizeof(buf), "RETR %s", stream->remote.path ); + switch (net_command( stream, buf, sizeof(buf) )) { + case 150: + case 125: + break; + default: + goto error; + } + + stream->offset = offset; + + return DR_OK; + +error: + close( stream->fd ); + stream->fd = -1; + + return DR_FAILURE; +} + +static DirectResult +ftp_open( DirectStream *stream, const char *filename ) +{ + DirectResult ret; + int status = 0; + char buf[512]; + + stream->remote.port = FTP_PORT; + + ret = net_open( stream, filename, IPPROTO_TCP ); + if (ret) + return ret; + + while (net_response( stream, buf, sizeof(buf) ) > 0) { + if (sscanf( buf, "%3d%[ ]", &status, buf ) == 2) + break; + } + if (status != 220) + return DR_FAILURE; + + /* login */ + snprintf( buf, sizeof(buf), "USER %s", stream->remote.user ? : "anonymous" ); + switch (net_command( stream, buf, sizeof(buf) )) { + case 230: + case 331: + break; + default: + return DR_FAILURE; + } + + if (stream->remote.pass) { + snprintf( buf, sizeof(buf), "PASS %s", stream->remote.pass ); + if (net_command( stream, buf, sizeof(buf) ) != 230) + return DR_FAILURE; + } + + /* enter binary mode */ + snprintf( buf, sizeof(buf), "TYPE I" ); + if (net_command( stream, buf, sizeof(buf) ) != 200) + return DR_FAILURE; + + /* get file size */ + snprintf( buf, sizeof(buf), "SIZE %s", stream->remote.path ); + if (net_command( stream, buf, sizeof(buf) ) == 213) + stream->length = strtol( buf+4, NULL, 10 ); + + /* enter passive mode by default */ + ret = ftp_open_pasv( stream, buf, sizeof(buf) ); + if (ret) + return ret; + + /* retrieve file */ + snprintf( buf, sizeof(buf), "RETR %s", stream->remote.path ); + switch (net_command( stream, buf, sizeof(buf) )) { + case 125: + case 150: + break; + default: + return DR_FAILURE; + } + + stream->seek = ftp_seek; + + return DR_OK; +} + +/*****************************************************************************/ + +typedef struct { + s8 pt; // payload type (-1: dymanic) + u8 type; // codec type + const char *name; + const char *mime; + u32 fcc; +} RTPPayload; + +typedef struct { + char *control; + + int pt; + const RTPPayload *payload; + + int dur; // duration + int abr; // avg bitrate + int mbr; // max bitrate + int aps; // avg packet size + int mps; // max packet size + int str; // start time + int prl; // preroll + + char *mime; + int mime_size; + + void *data; + int data_size; +} SDPStreamDesc; + +#define PAYLOAD_VIDEO 1 +#define PAYLOAD_AUDIO 2 + +#define FCC( a, b, c, d ) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) + +static const RTPPayload payloads[] = { + { 31, PAYLOAD_VIDEO, "H261", "video/h261", FCC('H','2','6','1') }, + { 34, PAYLOAD_VIDEO, "H263", "video/h263", FCC('H','2','6','3') }, + //{ -1, PAYLOAD_VIDEO, "H264", "video/h264", FCC('H','2','6','4') }, + { 32, PAYLOAD_VIDEO, "MPV", "video/mpeg", FCC('M','P','E','G') }, + { 33, 0, "MP2T", "video/mpegts", 0 }, + { -1, PAYLOAD_VIDEO, "MP4V-ES", "video/mpeg4", FCC('M','P','4','S') }, + { 14, PAYLOAD_AUDIO, "MPA", "audio/mpeg", 0x0055 }, + //{ -1, PAYLOAD_AUDIO, "mpeg4-generic", "audio/aac", 0x00ff }, +}; + +#define NUM_PAYLOADS D_ARRAY_SIZE( payloads ) + +static DirectResult +sdp_parse( DirectStream *stream, int length, SDPStreamDesc **ret_streams, int *ret_num ) +{ + char *buf, *tmp; + SDPStreamDesc *desc = NULL; + int num = 0; + fd_set set; + struct timeval tv; + int i; + + buf = D_CALLOC( 1, length+1 ); + if (!buf) + return D_OOM(); + + FD_ZERO( &set ); + FD_SET( stream->remote.sd, &set ); + + for (tmp = buf; length;) { + int size; + + tv.tv_sec = NET_TIMEOUT; + tv.tv_usec = 0; + select( stream->remote.sd+1, &set, NULL, NULL, &tv ); + + size = recv( stream->remote.sd, tmp, length, MSG_WAITALL ); + if (size < 1) + break; + tmp += size; + length -= size; + } + + for (tmp = buf; tmp && *tmp;) { + char *end; + + end = strchr( tmp, '\n' ); + if (end) { + if (end > tmp && *(end-1) == '\r') + *(end-1) = '\0'; + *end = '\0'; + } + + D_DEBUG_AT( Direct_Stream, "SDP [%s]\n", tmp ); + + switch (*tmp) { + case 'm': + /* media */ + if (*(tmp+1) == '=') { + desc = D_REALLOC( desc, ++num*sizeof(SDPStreamDesc) ); + memset( &desc[num-1], 0, sizeof(SDPStreamDesc) ); + + tmp += 2; + if (sscanf( tmp, "audio %d RTP/AVP %d", &i, &desc[num-1].pt ) == 2 || + sscanf( tmp, "video %d RTP/AVP %d", &i, &desc[num-1].pt ) == 2) { + for (i = 0; i < NUM_PAYLOADS; i++) { + if (desc[num-1].pt == payloads[i].pt) { + desc[num-1].payload = &payloads[i]; + desc[num-1].mime = D_STRDUP( payloads[i].mime ); + desc[num-1].mime_size = strlen( payloads[i].mime ); + break; + } + } + } + } + break; + case 'a': + /* attribute */ + if (*(tmp+1) == '=' && num) { + tmp += 2; + if (!strncmp( tmp, "control:", 8 )) { + desc[num-1].control = D_STRDUP( trim( tmp+8 ) ); + } + else if (!strncmp( tmp, "rtpmap:", 7 )) { + if (!desc[num-1].payload && desc[num-1].pt) { + char *sep; + + tmp = strchr( trim( tmp+7 ), ' ' ); + if (!tmp) break; + sep = strchr( ++tmp, '/' ); + if (sep) *sep = '\0'; + + for (i = 0; i < NUM_PAYLOADS; i++) { + if (strcmp( tmp, payloads[i].name )) + continue; + desc[num-1].payload = &payloads[i]; + desc[num-1].mime = D_STRDUP( payloads[i].mime ); + desc[num-1].mime_size = strlen( payloads[i].mime ); + break; + } + } + } + else if (!strncmp( tmp, "length:npt=", 11 )) { + double val = atof( tmp+11 ); + desc[num-1].dur = val * 1000.0; + } + else if (!strncmp( tmp, "mimetype:string;", 16 )) { + if (desc[num-1].mime) + D_FREE( desc[num-1].mime ); + desc[num-1].mime = D_STRDUP( trim( tmp+16 ) ); + desc[num-1].mime_size = strlen( desc[num-1].mime ); + } + else if (!strncmp( tmp, "AvgBitRate:", 11 )) { + sscanf( tmp+11, "integer;%d", &desc[num-1].abr ); + } + else if (!strncmp( tmp, "MaxBitRate:", 11 )) { + sscanf( tmp+11, "integer;%d", &desc[num-1].mbr ); + } + else if (!strncmp( tmp, "AvgPacketSize:", 14 )) { + sscanf( tmp+14, "integer;%d", &desc[num-1].aps ); + } + else if (!strncmp( tmp, "MaxPacketSize:", 14 )) { + sscanf( tmp+14, "integer;%d", &desc[num-1].mps ); + } + else if (!strncmp( tmp, "StartTime:", 10 )) { + sscanf( tmp+10, "integer;%d", &desc[num-1].str ); + } + else if (!strncmp( tmp, "Preroll:", 8 )) { + sscanf( tmp+8, "integer;%d", &desc[num-1].prl ); + } + else if (!strncmp( tmp, "OpaqueData:buffer;", 18 )) { + desc[num-1].data = + direct_base64_decode( trim( tmp+18 ), + &desc[num-1].data_size ); + } + } + break; + default: + break; + } + + tmp = end; + if (tmp) tmp++; + } + + D_FREE( buf ); + + *ret_streams = desc; + *ret_num = num; + + return desc ? DR_OK : DR_EOF; +} + +static void +sdp_free( SDPStreamDesc *streams, int num ) +{ + int i; + + for (i = 0; i < num; i++) { + if (streams[i].control) + D_FREE( streams[i].control ); + if (streams[i].mime) + D_FREE( streams[i].mime ); + if (streams[i].data) + D_FREE( streams[i].data ); + } + D_FREE( streams ); +} + +static DirectResult +rmf_write_header( SDPStreamDesc *streams, int n_streams, void **ret_buf, unsigned int *ret_size ) +{ + unsigned char *dst, *tmp; + int abr = 0; + int mbr = 0; + int aps = 0; + int mps = 0; + int str = 0; + int prl = 0; + int dur = 0; + int i, len; + + len = 86 + n_streams*46; + for (i = 0; i < n_streams; i++) { + abr += streams[i].abr; + aps += streams[i].aps; + if (mbr < streams[i].mbr) + mbr = streams[i].mbr; + if (mps < streams[i].mps) + mps = streams[i].mps; + if (dur < streams[i].dur) + dur = streams[i].dur; + if (streams[i].mime) + len += streams[i].mime_size; + if (streams[i].data) + len += streams[i].data_size; + else if (streams[i].payload) + len += 74; + } + + *ret_buf = dst = D_MALLOC( len ); + if (!dst) + return D_OOM(); + *ret_size = len; + + /* RMF */ + dst[0] = '.'; dst[1] = 'R', dst[2] = 'M'; dst[3] = 'F'; + dst[4] = dst[5] = dst[6] = 0; dst[7] = 18; // size + dst[8] = dst[9] = 0; // version + dst[10] = dst[11] = dst[12] = dst[13] = 0; // ?? + dst[14] = dst[15] = dst[16] = 0; dst[17] = 4+n_streams; // num streams + dst += 18; + + /* PROP */ + dst[0] = 'P'; dst[1] = 'R'; dst[2] = 'O'; dst[3] = 'P'; + dst[4] = dst[5] = dst[6] = 0; dst[7] = 50; + dst[8] = dst[9] = 0; + dst[10] = mbr>>24; dst[11] = mbr>>16; dst[12] = mbr>>8; dst[13] = mbr; + dst[14] = abr>>24; dst[15] = abr>>16; dst[16] = abr>>8; dst[17] = abr; + dst[18] = mps>>24; dst[19] = mps>>16; dst[20] = mps>>8; dst[21] = mps; + dst[22] = aps>>24; dst[23] = aps>>16; dst[24] = aps>>8; dst[25] = aps; + dst[26] = dst[27] = dst[28] = dst[29] = 0; // num packets + dst[30] = dur>>24; dst[31] = dur>>16; dst[32] = dur>>8; dst[33] = dur; + dst[34] = dst[35] = dst[36] = dst[37] = 0; // preroll + dst[38] = dst[39] = dst[40] = dst[41] = 0; // index offset + dst[42] = len>>24; dst[43] = len>>16; dst[44] = len>>8; dst[45] = len; + dst[46] = 0; dst[47] = n_streams; // num streams + dst[48] = 0; dst[49] = 7; // flags + dst += 50; + + for (i = 0; i < n_streams; i++) { + len = 46 + streams[i].mime_size; + if (streams[i].data) + len += streams[i].data_size; + else if (streams[i].payload) + len += 74; + + abr = streams[i].abr; + mbr = streams[i].mbr; + aps = streams[i].aps; + mps = streams[i].mps; + str = streams[i].str; + prl = streams[i].prl; + dur = streams[i].dur; + + /* MDPR */ + dst[0] = 'M'; dst[1] = 'D'; dst[2] = 'P'; dst[3] = 'R'; + dst[4] = len>>24; dst[5] = len>>16; dst[6] = len>>8; dst[7] = len; + dst[8] = dst[9] = 0; + dst[10] = 0; dst[11] = i; + dst[12] = mbr>>24; dst[13] = mbr>>16; dst[14] = mbr>>8; dst[15] = mbr; + dst[16] = abr>>24; dst[17] = abr>>16; dst[18] = abr>>8; dst[19] = abr; + dst[20] = mps>>24; dst[21] = mps>>16; dst[22] = mps>>8; dst[23] = mps; + dst[24] = aps>>24; dst[25] = aps>>16; dst[26] = aps>>8; dst[27] = aps; + dst[28] = str>>24; dst[29] = str>>16; dst[30] = str>>8; dst[31] = str; + dst[32] = prl>>24; dst[33] = prl>>16; dst[34] = prl>>8; dst[35] = prl; + dst[36] = dur>>24; dst[37] = dur>>16; dst[38] = dur>>8; dst[39] = dur; + dst += 40; + + /* description */ + *dst++ = 0; + /* mimetype */ + *dst++ = streams[i].mime_size; + for (tmp = (unsigned char*)streams[i].mime; tmp && *tmp;) + *dst++ = *tmp++; + + /* codec data */ + if (streams[i].data) { + len = streams[i].data_size; + dst[0] = len>>24; dst[1] = len>>16; dst[2] = len>>8; dst[3] = len; + direct_memcpy( dst+4, streams[i].data, streams[i].data_size ); + dst += len+4; + } + else if (streams[i].payload) { + u32 fcc = streams[i].payload->fcc; + + dst[0] = dst[1] = dst[2] = 0; dst[3] = 74; + dst += 4; + memset( dst, 0, 74 ); + + if (streams[i].payload->type == PAYLOAD_AUDIO) { + dst[0] = '.'; dst[1] = 'r'; dst[2] = 'a'; dst[3] = 0xfd; + dst[4] = 0; dst[5] = 5; // version + dst[66] = fcc; dst[67] = fcc>>8; dst[68] = fcc>>16; dst[69] = fcc>>24; + } + else { + dst[0] = dst[1] = dst[2] = 0; dst[3] = 34; + dst[4] = 'V'; dst[5] = 'I'; dst[6] = 'D'; dst[7] = 'O'; + dst[8] = fcc; dst[9] = fcc>>8; dst[10] = fcc>>16; dst[11] = fcc>>24; + dst[30] = 0x10; + } + dst += 74; + } + else { + dst[0] = dst[1] = dst[2] = dst[3] = 0; + dst += 4; + } + } + + /* DATA */ + dst[0] = 'D'; dst[1] = 'A'; dst[2] = 'T'; dst[3] = 'A'; + dst[4] = dst[5] = dst[6] = 0; dst[7] = 18; // size + dst[8] = dst[9] = 0; // version + dst[10] = dst[11] = dst[12] = dst[13] = 0; // num packets + dst[14] = dst[15] = dst[16] = dst[17] = 0; // next data + + return DR_OK; +} + +static int +rmf_write_pheader( unsigned char *dst, int id, int sz, unsigned int ts ) +{ + /* version */ + dst[0] = dst[1] = 0; + /* length */ + dst[2] = (sz+12)>>8; dst[3] = sz+12; + /* indentifier */ + dst[4] = id>>8; dst[5] = id; + /* timestamp */ + dst[6] = ts>>24; dst[7] = ts>>16; dst[8] = ts>>8; dst[9] = ts; + /* reserved */ + dst[10] = 0; + /* flags */ + dst[11] = 0; + + return 12; +} + +static void +real_calc_challenge2( char response[64], char checksum[32], char *challenge ) +{ + const unsigned char xor_table[37] = { + 0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53, + 0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70, + 0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09, + 0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02, + 0x10, 0x57, 0x05, 0x18, 0x54 + }; + char buf[128]; + char md5[16]; + int len; + int i; + + memset( response, 0, 64 ); + memset( checksum, 0, 32 ); + + buf[0] = 0xa1; buf[1] = 0xe9; buf[2] = 0x14; buf[3] = 0x9d; + buf[4] = 0x0e; buf[5] = 0x6b; buf[6] = 0x3b; buf[7] = 0x59; + memset( buf+8, 0, 120 ); + + len = strlen( challenge ); + if (len == 40) { + challenge[32] = '\0'; + len = 32; + } + memcpy( buf+8, challenge, MAX(len,56) ); + + for (i = 0; i < 37; i++) + buf[8+i] ^= xor_table[i]; + + /* compute response */ + direct_md5_sum( md5, buf, 64 ); + /* convert to ascii */ + for (i = 0; i < 16; i++) { + char a, b; + a = (md5[i] >> 4) & 15; + b = md5[i] & 15; + response[i*2+0] = ((a < 10) ? (a + 48) : (a + 87)) & 255; + response[i*2+1] = ((b < 10) ? (b + 48) : (b + 87)) & 255; + } + /* tail */ + len = strlen( response ); + direct_snputs( &response[len], "01d0a8e3", 64-len ); + + /* compute checksum */ + for (i = 0; i < len/4; i++) + checksum[i] = response[i*4]; +} + +static DirectResult +rtsp_session_open( DirectStream *stream ) +{ + DirectResult ret; + int status; + int cseq = 0; + SDPStreamDesc *streams = NULL; + int n_streams = 0; + char session[32] = {0, }; + char challen[64] = {0, }; + char buf[1280]; + int i, len; + + snprintf( buf, sizeof(buf), + "OPTIONS rtsp://%s:%d RTSP/1.0\r\n" + "CSeq: %d\r\n" + "User-Agent: DirectFB/%s\r\n" + "ClientChallenge: 9e26d33f2984236010ef6253fb1887f7\r\n" + "PlayerStarttime: [28/03/2003:22:50:23 00:00]\r\n" + "CompanyID: KnKV4M4I/B2FjJ1TToLycw==\r\n" + "GUID: 00000000-0000-0000-0000-000000000000\r\n" + "RegionData: 0\r\n", + stream->remote.host, + stream->remote.port, + ++cseq, DIRECTFB_VERSION ); + + if (net_command( stream, buf, sizeof(buf) ) != 200) + return DR_FAILURE; + + while (net_response( stream, buf, sizeof(buf) ) > 0) { + if (!strncmp( buf, "RealChallenge1:", 15 )) { + snprintf( challen, sizeof(challen), "%s", trim( buf+15 ) ); + stream->remote.real_rtsp = true; + } + } + + len = snprintf( buf, sizeof(buf), + "DESCRIBE rtsp://%s:%d%s RTSP/1.0\r\n" + "CSeq: %d\r\n" + "Accept: application/sdp\r\n" + "Bandwidth: 10485800\r\n", + stream->remote.host, + stream->remote.port, + stream->remote.path, + ++cseq ); + if (stream->remote.real_rtsp) { + snprintf( buf+len, sizeof(buf)-len, + "GUID: 00000000-0000-0000-0000-000000000000\r\n" + "RegionData: 0\r\n" + "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586\r\n" + "SupportsMaximumASMBandwidth: 1\r\n" + "Require: com.real.retain-entity-for-setup\r\n" ); + } + + status = net_command( stream, buf, sizeof(buf) ); + if (status != 200) + return (status == 404) ? DR_FILENOTFOUND : DR_FAILURE; + + len = 0; + while (net_response( stream, buf, sizeof(buf) ) > 0) { + if (!strncasecmp( buf, "ETag:", 5 )) { + snprintf( session, sizeof(session), "%s", trim( buf+5 ) ); + } + else if (!strncasecmp( buf, "Content-Length:", 15 )) { + char *tmp = trim( buf+15 ); + if (sscanf( tmp, "%d", &len ) != 1) + sscanf( tmp, "bytes=%d", &len ); + } + } + + if (!len) { + D_DEBUG_AT( Direct_Stream, "Couldn't get sdp length!\n" ); + return DR_FAILURE; + } + + ret = sdp_parse( stream, len, &streams, &n_streams ); + if (ret) + return ret; + + for (i = 0; i < n_streams; i++) { + /* skip unhandled payload types */ + if (!stream->remote.real_rtsp && !streams[i].payload) + continue; + + len = snprintf( buf, sizeof(buf), + "SETUP rtsp://%s:%d%s/%s RTSP/1.0\r\n" + "CSeq: %d\r\n", + stream->remote.host, + stream->remote.port, + stream->remote.path, + streams[i].control, ++cseq ); + if (*session) { + if (*challen) { + char response[64]; + char checksum[32]; + + real_calc_challenge2( response, checksum, challen ); + len += snprintf( buf+len, sizeof(buf)-len, + "RealChallenge2: %s, sd=%s\r\n", + response, checksum ); + *challen = '\0'; + } + len += snprintf( buf+len, sizeof(buf)-len, + "%s: %s\r\n", + i ? "Session" : "If-Match", session ); + } + snprintf( buf+len, sizeof(buf)-len, + "Transport: %s\r\n", + stream->remote.real_rtsp + ? "x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play" + : "RTP/AVP/TCP;unicast" ); + + if (net_command( stream, buf, sizeof(buf) ) != 200) { + sdp_free( streams, n_streams ); + return DR_FAILURE; + } + + while (net_response( stream, buf, sizeof(buf) ) > 0) { + if (!strncmp( buf, "Session:", 8 )) + snprintf( session, sizeof(session), "%s", trim( buf+8 ) ); + } + } + + len = snprintf( buf, sizeof(buf), + "PLAY rtsp://%s:%d%s RTSP/1.0\r\n" + "CSeq: %d\r\n", + stream->remote.host, + stream->remote.port, + stream->remote.path, + ++cseq ); + if (*session) { + len += snprintf( buf+len, sizeof(buf)-len, + "Session: %s\r\n", session ); + } + snprintf( buf+len, sizeof(buf)-len, + "Range: npt=0-\r\n" + "Connection: Close\r\n" ); + + if (net_command( stream, buf, sizeof(buf) ) != 200) { + sdp_free( streams, n_streams ); + return DR_FAILURE; + } + + /* discard remaining headers */ + while (net_response( stream, buf, sizeof(buf) ) > 0); + + /* revert to blocking mode */ + fcntl( stream->fd, F_SETFL, + fcntl( stream->fd, F_GETFL ) & ~O_NONBLOCK ); + + if (!stream->remote.real_rtsp) { + RTPPayload *p; + + stream->remote.data = D_CALLOC( 1, (n_streams+1)*sizeof(RTPPayload) ); + if (!stream->remote.data) { + sdp_free( streams, n_streams ); + return D_OOM(); + } + + p = (RTPPayload*) stream->remote.data; + for (i = 0; i < n_streams; i++) { + if (streams[i].payload) { + *p = *(streams[i].payload); + p->pt = streams[i].pt; + p++; + } + } + } + + stream->remote.real_pack = true; + if (n_streams == 1 && streams[0].mime) { + if (!strcmp( streams[0].mime, "audio/mpeg" ) || + !strcmp( streams[0].mime, "audio/aac" ) || + !strcmp( streams[0].mime, "video/mpeg" ) || + !strcmp( streams[0].mime, "video/mpegts" )) + { + stream->mime = D_STRDUP( streams[0].mime ); + stream->remote.real_pack = false; + } + } + if (stream->remote.real_pack) { + ret = rmf_write_header( streams, n_streams, + &stream->cache, &stream->cache_size ); + if (ret) { + sdp_free( streams, n_streams ); + return ret; + } + stream->mime = D_STRDUP( "application/vnd.rn-realmedia" ); + } + + sdp_free( streams, n_streams ); + + return DR_OK; +} + +static DirectResult +rvp_read_packet( DirectStream *stream ) +{ + unsigned char buf[9]; + int size; + int len; + unsigned char id; + unsigned int ts; + + while (1) { + do { + size = recv( stream->fd, buf, 1, MSG_WAITALL ); + if (size < 1) + return DR_EOF; + } while (buf[0] != '$'); + + size = recv( stream->fd, buf, 7, MSG_WAITALL ); + if (size < 7) + return DR_EOF; + + len = (buf[0] << 16) + (buf[1] << 8) + buf[2]; + id = buf[3]; + if (id != 0x40 && id != 0x42) { + if (buf[5] == 0x06) // EOS + return DR_EOF; + size = recv( stream->fd, buf, 9, MSG_WAITALL ); + if (size < 9) + return DR_EOF; + id = buf[5]; + len -= 9; + } + id = (id >> 1) & 1; + + size = recv( stream->fd, buf, 6, MSG_WAITALL ); + if (size < 6) + return DR_EOF; + ts = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + + len -= 10; + if (len > 0) { + unsigned char *dst; + + size = len + 12; + stream->cache = D_REALLOC( stream->cache, stream->cache_size+size ); + if (!stream->cache) + return D_OOM(); + dst = stream->cache+stream->cache_size; + stream->cache_size += size; + + dst += rmf_write_pheader( dst, id, len, ts ); + + while (len) { + size = recv( stream->fd, dst, len, MSG_WAITALL ); + if (size < 1) + return DR_EOF; + dst += size; + len -= size; + } + break; + } + } + + return DR_OK; +} + +static DirectResult +rtp_read_packet( DirectStream *stream ) +{ + RTPPayload *payloads = (RTPPayload*)stream->remote.data; + unsigned char buf[12]; + int size; + int len; + unsigned char id; + unsigned short seq; + unsigned int ts; + int skip; + + while (1) { + RTPPayload *p; + + do { + size = recv( stream->fd, buf, 1, MSG_WAITALL ); + if (size < 1) + return DR_EOF; + } while (buf[0] != '$'); + + size = recv( stream->fd, buf, 3, MSG_WAITALL ); + if (size < 3) + return DR_EOF; + + id = buf[0]; + len = (buf[1] << 8) | buf[2]; + if (len < 12) + continue; + + size = recv( stream->fd, buf, 12, MSG_WAITALL ); + if (size < 12) + return DR_EOF; + len -= 12; + + if ((buf[0] & 0xc0) != (2 << 6)) + D_DEBUG_AT( Direct_Stream, "Bad RTP version %d!\n", buf[0] ); + seq = (buf[2] << 8) | buf[3]; + ts = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; + + for (p = payloads; p->pt; p++) { + if (p->pt == (buf[1] & 0x7f)) + break; + } + + switch (p->pt) { + case 0: // Unhandled + skip = len; + break; + case 14: // MPEG Audio + skip = 4; + break; + case 32: // MPEG Video + size = recv( stream->fd, buf, 1, MSG_WAITALL ); + if (size < 1) + return DR_EOF; + len--; + skip = 3; + if (buf[0] & (1 << 2)) + skip += 4; + break; + case 34: // H263 + size = recv( stream->fd, buf, 1, MSG_WAITALL ); + if (size < 1) + return DR_EOF; + len--; + skip = 3; + if (buf[0] & (1 << 7)) + skip += 4; + if (buf[0] & (1 << 6)) + skip += 4; + break; + default: + skip = 0; + break; + } + + while (skip) { + size = recv( stream->fd, buf, MIN(skip,12), MSG_WAITALL ); + if (size < 1) + return DR_EOF; + len -= size; + skip -= size; + } + + if (len > 0) { + unsigned char *dst; + + size = len; + if (stream->remote.real_pack) { + size += 12; + if (p->type == PAYLOAD_VIDEO) + size += 7; + } + + stream->cache = D_REALLOC( stream->cache, stream->cache_size+size ); + if (!stream->cache) + return D_OOM(); + dst = stream->cache+stream->cache_size; + stream->cache_size += size; + + if (stream->remote.real_pack) { + if (p->type == PAYLOAD_VIDEO) { + dst += rmf_write_pheader( dst, id, len+7, ts ); + dst[0] = 0x81; + dst[1] = 0x01; + dst[2] = (len | 0x4000)>>8; dst[3] = len; + dst[4] = (len | 0x4000)>>8; dst[5] = len; + dst[6] = seq; + dst += 7; + } else { + dst += rmf_write_pheader( dst, id, len, ts ); + } + } + + while (len) { + size = recv( stream->fd, dst, len, MSG_WAITALL ); + if (size < 1) + return DR_EOF; + dst += size; + len -= size; + } + break; + } + } + + return DR_OK; +} + +static DirectResult +rtsp_peek( DirectStream *stream, + unsigned int length, + int offset, + void *buf, + unsigned int *read_out ) +{ + DirectResult ret; + unsigned int len; + + if (offset < 0) + return DR_UNSUPPORTED; + + len = length + offset; + while (len > stream->cache_size) { + ret = (stream->remote.real_rtsp) + ? rvp_read_packet( stream ) + : rtp_read_packet( stream ); + if (ret) { + if (stream->cache_size < offset) + return ret; + break; + } + } + + len = MIN( stream->cache_size-offset, length ); + direct_memcpy( buf, stream->cache+offset, len ); + + if (read_out) + *read_out = len; + + return DR_OK; +} + +static DirectResult +rtsp_read( DirectStream *stream, + unsigned int length, + void *buf, + unsigned int *read_out ) +{ + DirectResult ret; + unsigned int size = 0; + + while (size < length) { + if (stream->cache_size) { + unsigned int len = MIN( stream->cache_size, length-size ); + + direct_memcpy( buf+size, stream->cache, len ); + size += len; + stream->cache_size -= len; + + if (stream->cache_size) { + direct_memcpy( stream->cache, + stream->cache+len, stream->cache_size ); + } else { + D_FREE( stream->cache ); + stream->cache = NULL; + } + } + + if (size < length) { + ret = (stream->remote.real_rtsp) + ? rvp_read_packet( stream ) + : rtp_read_packet( stream ); + if (ret) { + if (!size) + return ret; + break; + } + } + } + + stream->offset += size; + + if (read_out) + *read_out = size; + + return DR_OK; +} + +static DirectResult +rtsp_open( DirectStream *stream, const char *filename ) +{ + DirectResult ret; + + stream->remote.port = RTSP_PORT; + + ret = net_open( stream, filename, IPPROTO_TCP ); + if (ret) + return ret; + + ret = rtsp_session_open( stream ); + if (ret) { + close( stream->remote.sd ); + return ret; + } + + stream->peek = rtsp_peek; + stream->read = rtsp_read; + + return DR_OK; +} + +#endif /* DIRECT_BUILD_NETWORK */ + +/************************** End of Network Support ***************************/ + +static DirectResult +pipe_wait( DirectStream *stream, + unsigned int length, + struct timeval *tv ) +{ + fd_set s; + + if (stream->cache_size >= length) + return DR_OK; + + FD_ZERO( &s ); + FD_SET( stream->fd, &s ); + + switch (select( stream->fd+1, &s, NULL, NULL, tv )) { + case 0: + if (!tv && !stream->cache_size) + return DR_EOF; + return DR_TIMEOUT; + case -1: + return errno2result( errno ); + } + + return DR_OK; +} + +static DirectResult +pipe_peek( DirectStream *stream, + unsigned int length, + int offset, + void *buf, + unsigned int *read_out ) +{ + unsigned int size = length; + int len; + + if (offset < 0) + return DR_UNSUPPORTED; + + len = length + offset; + if (len > stream->cache_size) { + ssize_t s; + + stream->cache = D_REALLOC( stream->cache, len ); + if (!stream->cache) { + stream->cache_size = 0; + return D_OOM(); + } + + s = read( stream->fd, + stream->cache + stream->cache_size, + len - stream->cache_size ); + if (s < 0) { + if (errno != EAGAIN || stream->cache_size == 0) + return errno2result( errno ); + s = 0; + } + + stream->cache_size += s; + if (stream->cache_size <= offset) + return DR_BUFFEREMPTY; + + size = stream->cache_size - offset; + } + + direct_memcpy( buf, stream->cache+offset, size ); + + if (read_out) + *read_out = size; + + return DR_OK; +} + +static DirectResult +pipe_read( DirectStream *stream, + unsigned int length, + void *buf, + unsigned int *read_out ) +{ + unsigned int size = 0; + + if (stream->cache_size) { + size = MIN( stream->cache_size, length ); + + direct_memcpy( buf, stream->cache, size ); + + length -= size; + stream->cache_size -= size; + + if (stream->cache_size) { + direct_memcpy( stream->cache, + stream->cache+size, stream->cache_size ); + } else { + D_FREE( stream->cache ); + stream->cache = NULL; + } + } + + if (length) { + ssize_t s; + + s = read( stream->fd, buf+size, length-size ); + switch (s) { + case 0: + if (!size) + return DR_EOF; + break; + case -1: + if (!size) { + return (errno == EAGAIN) + ? DR_BUFFEREMPTY + : errno2result( errno ); + } + break; + default: + size += s; + break; + } + } + + stream->offset += size; + + if (read_out) + *read_out = size; + + return DR_OK; +} + +/*****************************************************************************/ + +static DirectResult +file_peek( DirectStream *stream, + unsigned int length, + int offset, + void *buf, + unsigned int *read_out ) +{ + DirectResult ret = DR_OK; + ssize_t size; + + if (lseek( stream->fd, offset, SEEK_CUR ) < 0) + return DR_FAILURE; + + size = read( stream->fd, buf, length ); + switch (size) { + case 0: + ret = DR_EOF; + break; + case -1: + ret = (errno == EAGAIN) + ? DR_BUFFEREMPTY + : errno2result( errno ); + size = 0; + break; + } + + if (lseek( stream->fd, - offset - size, SEEK_CUR ) < 0) + return DR_FAILURE; + + if (read_out) + *read_out = size; + + return ret; +} + +static DirectResult +file_read( DirectStream *stream, + unsigned int length, + void *buf, + unsigned int *read_out ) +{ + ssize_t size; + + size = read( stream->fd, buf, length ); + switch (size) { + case 0: + return DR_EOF; + case -1: + if (errno == EAGAIN) + return DR_BUFFEREMPTY; + return errno2result( errno ); + } + + stream->offset += size; + + if (read_out) + *read_out = size; + + return DR_OK; +} + +static DirectResult +file_seek( DirectStream *stream, unsigned int offset ) +{ + off_t off; + + off = lseek( stream->fd, offset, SEEK_SET ); + if (off < 0) + return DR_FAILURE; + + stream->offset = off; + + return DR_OK; +} + +static DirectResult +file_open( DirectStream *stream, const char *filename, int fileno ) +{ + if (filename) + stream->fd = open( filename, O_RDONLY | O_NONBLOCK ); + else + stream->fd = dup( fileno ); + + if (stream->fd < 0) + return errno2result( errno ); + + fcntl( stream->fd, F_SETFL, + fcntl( stream->fd, F_GETFL ) | O_NONBLOCK ); + + if (lseek( stream->fd, 0, SEEK_CUR ) < 0 && errno == ESPIPE) { + stream->length = -1; + stream->wait = pipe_wait; + stream->peek = pipe_peek; + stream->read = pipe_read; + } + else { + struct stat s; + + if (fstat( stream->fd, &s ) < 0) + return errno2result( errno ); + + stream->length = s.st_size; + stream->peek = file_peek; + stream->read = file_read; + stream->seek = file_seek; + } + + return DR_OK; +} + +/*****************************************************************************/ + +DirectResult +direct_stream_create( const char *filename, + DirectStream **ret_stream ) +{ + DirectStream *stream; + DirectResult ret; + + D_ASSERT( filename != NULL ); + D_ASSERT( ret_stream != NULL ); + + stream = D_CALLOC( 1, sizeof(DirectStream) ); + if (!stream) + return D_OOM(); + + D_MAGIC_SET( stream, DirectStream ); + + stream->ref = 1; + stream->fd = -1; + + if (!strncmp( filename, "stdin:/", 7 )) { + ret = file_open( stream, NULL, STDIN_FILENO ); + } + else if (!strncmp( filename, "file:/", 6 )) { + ret = file_open( stream, filename+6, -1 ); + } + else if (!strncmp( filename, "fd:/", 4 )) { + ret = (filename[4] >= '0' && filename[4] <= '9') + ? file_open( stream, NULL, atoi(filename+4) ) : DR_INVARG; + } +#if DIRECT_BUILD_NETWORK + else if (!strncmp( filename, "http://", 7 ) || + !strncmp( filename, "unsv://", 7 )) { + ret = http_open( stream, filename+7 ); + } + else if (!strncmp( filename, "ftp://", 6 )) { + ret = ftp_open( stream, filename+6 ); + } + else if (!strncmp( filename, "rtsp://", 7 )) { + ret = rtsp_open( stream, filename+7 ); + } + else if (!strncmp( filename, "tcp://", 6 )) { + ret = net_open( stream, filename+6, IPPROTO_TCP ); + } + else if (!strncmp( filename, "udp://", 6 )) { + ret = net_open( stream, filename+6, IPPROTO_UDP ); + } +#endif + else { + ret = file_open( stream, filename, -1 ); + } + + if (ret) { + direct_stream_close( stream ); + D_FREE( stream ); + return ret; + } + + *ret_stream = stream; + + return DR_OK; +} + +DirectStream* +direct_stream_dup( DirectStream *stream ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + stream->ref++; + + return stream; +} + +int +direct_stream_fileno( DirectStream *stream ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + return stream->fd; +} + +bool +direct_stream_seekable( DirectStream *stream ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + return stream->seek ? true : false; +} + +bool +direct_stream_remote( DirectStream *stream ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + +#if DIRECT_BUILD_NETWORK + if (stream->remote.host) + return true; +#endif + return false; +} + +const char* +direct_stream_mime( DirectStream *stream ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + return stream->mime; +} + +unsigned int +direct_stream_offset( DirectStream *stream ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + return stream->offset; +} + +unsigned int +direct_stream_length( DirectStream *stream ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + return (stream->length >= 0) ? stream->length : stream->offset; +} + +DirectResult +direct_stream_wait( DirectStream *stream, + unsigned int length, + struct timeval *tv ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + if (length && stream->wait) + return stream->wait( stream, length, tv ); + + return DR_OK; +} + +DirectResult +direct_stream_peek( DirectStream *stream, + unsigned int length, + int offset, + void *buf, + unsigned int *read_out ) +{ + D_ASSERT( stream != NULL ); + D_ASSERT( length != 0 ); + D_ASSERT( buf != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + if (stream->length >= 0 && (stream->offset + offset) >= stream->length) + return DR_EOF; + + if (stream->peek) + return stream->peek( stream, length, offset, buf, read_out ); + + return DR_UNSUPPORTED; +} + +DirectResult +direct_stream_read( DirectStream *stream, + unsigned int length, + void *buf, + unsigned int *read_out ) +{ + D_ASSERT( stream != NULL ); + D_ASSERT( length != 0 ); + D_ASSERT( buf != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + if (stream->length >= 0 && stream->offset >= stream->length) + return DR_EOF; + + if (stream->read) + return stream->read( stream, length, buf, read_out ); + + return DR_UNSUPPORTED; +} + +DirectResult +direct_stream_seek( DirectStream *stream, + unsigned int offset ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + if (stream->offset == offset) + return DR_OK; + + if (stream->length >= 0 && offset > stream->length) + offset = stream->length; + + if (stream->seek) + return stream->seek( stream, offset ); + + return DR_UNSUPPORTED; +} + +static void +direct_stream_close( DirectStream *stream ) +{ +#if DIRECT_BUILD_NETWORK + if (stream->remote.host) { + D_FREE( stream->remote.host ); + stream->remote.host = NULL; + } + + if (stream->remote.user) { + D_FREE( stream->remote.user ); + stream->remote.user = NULL; + } + + if (stream->remote.pass) { + D_FREE( stream->remote.pass ); + stream->remote.pass = NULL; + } + + if (stream->remote.auth) { + D_FREE( stream->remote.auth ); + stream->remote.auth = NULL; + } + + if (stream->remote.path) { + D_FREE( stream->remote.path ); + stream->remote.path = NULL; + } + + if (stream->remote.addr) { + freeaddrinfo( stream->remote.addr ); + stream->remote.addr = NULL; + } + + if (stream->remote.data) { + D_FREE( stream->remote.data ); + stream->remote.data = NULL; + } + + if (stream->remote.sd > 0) { + close( stream->remote.sd ); + stream->remote.sd = -1; + } +#endif + + if (stream->mime) { + D_FREE( stream->mime ); + stream->mime = NULL; + } + + if (stream->cache) { + D_FREE( stream->cache ); + stream->cache = NULL; + stream->cache_size = 0; + } + + if (stream->fd >= 0) { + fcntl( stream->fd, F_SETFL, + fcntl( stream->fd, F_GETFL ) & ~O_NONBLOCK ); + close( stream->fd ); + stream->fd = -1; + } +} + +void +direct_stream_destroy( DirectStream *stream ) +{ + D_ASSERT( stream != NULL ); + + D_MAGIC_ASSERT( stream, DirectStream ); + + if (--stream->ref == 0) { + direct_stream_close( stream ); + + D_FREE( stream ); + } +} diff --git a/Source/DirectFB/lib/direct/stream.h b/Source/DirectFB/lib/direct/stream.h new file mode 100755 index 0000000..6b77690 --- /dev/null +++ b/Source/DirectFB/lib/direct/stream.h @@ -0,0 +1,129 @@ +/* + (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 __DIRECT__STREAM_H__ +#define __DIRECT__STREAM_H__ + +#include +#include + +#include + +/* + * Create a stream wrapper. + * + * 'filename' can be a plain file name or one of the following: + * http://[:]/ + * unsv://[:]/ + * ftp://[:]/ + * rtsp://[:]/ + * tcp://: + * udp://: + * file:/ + * fd:/ + * stdin:/ + */ +DirectResult direct_stream_create ( const char *filename, + DirectStream **ret_stream ); + +/* + * Duplicate the stream (never fails). + */ +DirectStream *direct_stream_dup ( DirectStream *stream ); + +/* + * Return the file descriptor associated to the stream. + */ +int direct_stream_fileno ( DirectStream *stream ); + +/* + * True if stream is seekable. + */ +bool direct_stream_seekable( DirectStream *stream ); + +/* + * True if stream originates from a remote host. + */ +bool direct_stream_remote ( DirectStream *stream ); + +/* + * Get the mime description of the stream. + * Returns NULL if the information is not available. + */ +const char* direct_stream_mime ( DirectStream *stream ); + +/* + * Get stream length. + */ +unsigned int direct_stream_length ( DirectStream *stream ); + +/* + * Get stream position. + */ +unsigned int direct_stream_offset ( DirectStream *stream ); + +/* + * Wait for data to be available. + * If 'timeout' is NULL, the function blocks indefinitely. + * Set the 'timeout' to 0 to make the function return immediatly. + */ +DirectResult direct_stream_wait ( DirectStream *stream, + unsigned int length, + struct timeval *timeout ); + +/* + * Peek 'length' bytes of data at offset 'offset' from the stream. + */ +DirectResult direct_stream_peek ( DirectStream *stream, + unsigned int length, + int offset, + void *buf, + unsigned int *read_out ); + +/* + * Fetch 'length' bytes of data from the stream. + */ +DirectResult direct_stream_read ( DirectStream *stream, + unsigned int length, + void *buf, + unsigned int *read_out ); + +/* + * Seek to the specified absolute offset within the stream. + */ +DirectResult direct_stream_seek ( DirectStream *stream, + unsigned int offset ); + +/* + * Destroy the stream wrapper. + */ +void direct_stream_destroy ( DirectStream *stream ); + + +#endif /* __DIRECT__STREAM_H__ */ + diff --git a/Source/DirectFB/lib/direct/system.c b/Source/DirectFB/lib/direct/system.c new file mode 100755 index 0000000..b4b5b29 --- /dev/null +++ b/Source/DirectFB/lib/direct/system.c @@ -0,0 +1,68 @@ +/* + (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 + +#if DIRECT_BUILD_GETTID && defined(HAVE_LINUX_UNISTD_H) +#include +#endif + +__attribute__((no_instrument_function)) +pid_t +direct_gettid( void ) +{ + pid_t tid = -1; +#if DIRECT_BUILD_GETTID && defined(__NR_gettid) /* present on linux >= 2.4.20 */ + tid = syscall(__NR_gettid); +#endif + if (tid < 0) + tid = getpid(); + + return tid; +} + +long +direct_pagesize( void ) +{ + return sysconf( _SC_PAGESIZE ); +} + +unsigned long +direct_page_align( unsigned long value ) +{ + unsigned long mask = sysconf( _SC_PAGESIZE ) - 1; + + return (value + mask) & ~mask; +} + diff --git a/Source/DirectFB/lib/direct/system.h b/Source/DirectFB/lib/direct/system.h new file mode 100755 index 0000000..5cfe74e --- /dev/null +++ b/Source/DirectFB/lib/direct/system.h @@ -0,0 +1,40 @@ +/* + (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 __DIRECT__SYSTEM_H__ +#define __DIRECT__SYSTEM_H__ + +#include + +pid_t direct_gettid( void ); +long direct_pagesize( void ); + +unsigned long direct_page_align( unsigned long value ); + +#endif + diff --git a/Source/DirectFB/lib/direct/thread.c b/Source/DirectFB/lib/direct/thread.c new file mode 100755 index 0000000..91c66fc --- /dev/null +++ b/Source/DirectFB/lib/direct/thread.c @@ -0,0 +1,795 @@ +/* + (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 + +D_DEBUG_DOMAIN( Direct_Thread, "Direct/Thread", "Thread management" ); +D_DEBUG_DOMAIN( Direct_ThreadInit, "Direct/Thread/Init", "Thread initialization" ); + + +/* FIXME: DIRECT_THREAD_WAIT_INIT is required, but should be optional. */ +#define DIRECT_THREAD_WAIT_INIT + + +struct __D_DirectThread { + int magic; + + pthread_t thread; /* The pthread thread identifier. */ + pid_t tid; + + char *name; + + DirectThreadType type; /* The thread's type, e.g. input thread. */ + DirectThreadMainFunc main; /* The thread's main routine (or entry point). */ + void *arg; /* Custom argument passed to the main routine. */ + + bool canceled; /* Set when direct_thread_cancel() is called. */ + bool joining; /* Set when direct_thread_join() is called. */ + bool joined; /* Set when direct_thread_join() has finished. */ + bool detached; /* Set when direct_thread_detach() is called. */ + bool terminated; /* Set when direct_thread_terminate() is called. */ + +#ifdef DIRECT_THREAD_WAIT_INIT + bool init; /* Set to true before calling the main routine. */ +#endif + + pthread_mutex_t lock; + pthread_cond_t cond; + + unsigned int counter; +}; + +struct __D_DirectThreadInitHandler { + DirectLink link; + + int magic; + + DirectThreadInitFunc func; + void *arg; +}; + +/******************************************************************************/ + +/* + * Wrapper around pthread's main routine to pass additional arguments + * and setup things like signal masks and scheduling priorities. + */ +static void *direct_thread_main( void *arg ); + +/******************************************************************************/ + +static pthread_mutex_t handler_lock = PTHREAD_MUTEX_INITIALIZER; +static DirectLink *handlers = NULL; + +/******************************************************************************/ + +DirectThreadInitHandler * +direct_thread_add_init_handler( DirectThreadInitFunc func, + void *arg ) +{ + DirectThreadInitHandler *handler; + + handler = D_CALLOC( 1, sizeof(DirectThreadInitHandler) ); + if (!handler) { + D_WARN( "out of memory" ); + return NULL; + } + + handler->func = func; + handler->arg = arg; + + D_MAGIC_SET( handler, DirectThreadInitHandler ); + + pthread_mutex_lock( &handler_lock ); + + direct_list_append( &handlers, &handler->link ); + + pthread_mutex_unlock( &handler_lock ); + + return handler; +} + +void +direct_thread_remove_init_handler( DirectThreadInitHandler *handler ) +{ + D_MAGIC_ASSERT( handler, DirectThreadInitHandler ); + + pthread_mutex_lock( &handler_lock ); + + direct_list_remove( &handlers, &handler->link ); + + pthread_mutex_unlock( &handler_lock ); + + D_MAGIC_CLEAR( handler ); + + D_FREE( handler ); +} + +/******************************************************************************/ + +static pthread_mutex_t key_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_key_t thread_key = -1; + +/******************************************************************************/ + +DirectThread * +direct_thread_create( DirectThreadType thread_type, + DirectThreadMainFunc thread_main, + void *arg, + const char *name ) +{ + DirectThread *thread; + pthread_attr_t attr; + struct sched_param param; + int policy; + int priority; + size_t stack_size; + + D_ASSERT( thread_main != NULL ); + D_ASSERT( name != NULL ); + + D_DEBUG_AT( Direct_Thread, "%s( %s, %p(%p), '%s' )\n", __FUNCTION__, + direct_thread_type_name(thread_type), thread_main, arg, name ); + + /* Create the key for the TSD (thread specific data). */ + pthread_mutex_lock( &key_lock ); + + if (thread_key == -1) + pthread_key_create( &thread_key, NULL ); + + pthread_mutex_unlock( &key_lock ); + + /* Allocate thread structure. */ + thread = D_CALLOC( 1, sizeof(DirectThread) ); + if (!thread) { + D_OOM(); + return NULL; + } + + /* Write thread information to structure. */ + thread->name = D_STRDUP( name ); + thread->type = thread_type; + thread->main = thread_main; + thread->arg = arg; + + /* Initialize to -1 for synchronization. */ + thread->thread = (pthread_t) -1; + thread->tid = (pid_t) -1; + + /* Initialize mutex and condition. */ + direct_util_recursive_pthread_mutex_init( &thread->lock ); + pthread_cond_init( &thread->cond, NULL ); + + D_MAGIC_SET( thread, DirectThread ); + + /* Initialize scheduling and other parameters. */ + pthread_attr_init( &attr ); + +#ifdef PTHREAD_EXPLICIT_SCHED + pthread_attr_setinheritsched( &attr, PTHREAD_EXPLICIT_SCHED ); +#endif + + /* Select scheduler. */ + switch (direct_config->thread_scheduler) { + case DCTS_FIFO: + policy = SCHED_FIFO; + break; + + case DCTS_RR: + policy = SCHED_RR; + break; + + default: + policy = SCHED_OTHER; + break; + } + + if (pthread_attr_setschedpolicy( &attr, policy )) + D_PERROR( "Direct/Thread: Could not set scheduling policy to %s!\n", direct_thread_policy_name(policy) ); + + /* Read (back) value. */ + pthread_attr_getschedpolicy( &attr, &policy ); + + /* Select priority. */ + switch (thread->type) { + case DTT_CLEANUP: + case DTT_INPUT: + case DTT_OUTPUT: + case DTT_MESSAGING: + case DTT_CRITICAL: + priority = thread->type * direct_config->thread_priority_scale / 100; + break; + + default: + priority = direct_config->thread_priority; + break; + } + + D_DEBUG_AT( Direct_ThreadInit, " -> %s (%d) [%d;%d]\n", direct_thread_policy_name(policy), priority, + sched_get_priority_min( policy ), sched_get_priority_max( policy ) ); + + if (priority < sched_get_priority_min( policy )) + priority = sched_get_priority_min( policy ); + + if (priority > sched_get_priority_max( policy )) + priority = sched_get_priority_max( policy ); + + param.sched_priority = priority; + + if (pthread_attr_setschedparam( &attr, ¶m )) + D_PERROR( "Direct/Thread: Could not set scheduling priority to %d!\n", priority ); + + /* Select stack size? */ + if (direct_config->thread_stack_size > 0) { + if (pthread_attr_setstacksize( &attr, direct_config->thread_stack_size )) + D_PERROR( "Direct/Thread: Could not set stack size to %d!\n", direct_config->thread_stack_size ); + } + + /* Read (back) value. */ + pthread_attr_getstacksize( &attr, &stack_size ); + + /* Lock the thread mutex. */ + D_DEBUG_AT( Direct_ThreadInit, " -> locking...\n" ); + pthread_mutex_lock( &thread->lock ); + + /* Create and run the thread. */ + D_DEBUG_AT( Direct_ThreadInit, " -> creating...\n" ); + pthread_create( &thread->thread, &attr, direct_thread_main, thread ); + + pthread_attr_destroy( &attr ); + + pthread_getschedparam( thread->thread, &policy, ¶m ); + + D_INFO( "Direct/Thread: Started '%s' (%d) [%s %s/%s %d/%d] <%zu>...\n", + name, thread->tid, direct_thread_type_name(thread_type), + direct_thread_policy_name(policy), direct_thread_scheduler_name(direct_config->thread_scheduler), + param.sched_priority, priority, stack_size ); + +#ifdef DIRECT_THREAD_WAIT_INIT + /* Wait for completion of the thread's initialization. */ + while (!thread->init) { + D_DEBUG_AT( Direct_ThreadInit, " -> waiting...\n" ); + pthread_cond_wait( &thread->cond, &thread->lock ); + } + + D_DEBUG_AT( Direct_ThreadInit, " -> ...thread is running.\n" ); +#endif + + /* Unlock the thread mutex. */ + D_DEBUG_AT( Direct_ThreadInit, " -> unlocking...\n" ); + pthread_mutex_unlock( &thread->lock ); + + D_DEBUG_AT( Direct_ThreadInit, " -> returning %p\n", thread ); + + return thread; +} + +DirectThread * +direct_thread_self( void ) +{ + DirectThread *thread = pthread_getspecific( thread_key ); + + if (thread) + D_MAGIC_ASSERT( thread, DirectThread ); + + return thread; +} + +const char * +direct_thread_get_name( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->name != NULL ); + + return thread->name; +} + +pid_t +direct_thread_get_tid( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + + return thread->tid; +} + +__attribute__((no_instrument_function)) +const char * +direct_thread_self_name( void ) +{ + DirectThread *thread = pthread_getspecific( thread_key ); + + /* + * This function is called by debugging functions, e.g. debug messages, assertions etc. + * Therefore no assertions are made here, because they would loop forever if they fail. + */ + +#ifndef MACOS + return thread ? thread->name : NULL; +#else + return "debug"; +#endif +} + +void +direct_thread_set_name( const char *name ) +{ + char *copy; + DirectThread *thread = pthread_getspecific( thread_key ); + + D_DEBUG_AT( Direct_Thread, "%s( '%s' )\n", __FUNCTION__, name ); + + /* Support this function for non-direct threads. */ + if (!thread) { + D_DEBUG_AT( Direct_Thread, " -> attaching unknown thread %d\n", direct_gettid() ); + + /* Create the key for the TSD (thread specific data). */ + pthread_mutex_lock( &key_lock ); + + if (thread_key == -1) + pthread_key_create( &thread_key, NULL ); + + pthread_mutex_unlock( &key_lock ); + + + thread = D_CALLOC( 1, sizeof(DirectThread) ); + if (!thread) { + D_OOM(); + return; + } + + thread->thread = pthread_self(); + thread->tid = direct_gettid(); + + D_MAGIC_SET( thread, DirectThread ); + + pthread_setspecific( thread_key, thread ); + } + else + D_DEBUG_AT( Direct_Thread, " -> was '%s' (%d)\n", thread->name, direct_gettid() ); + + /* Duplicate string. */ + copy = D_STRDUP( name ); + if (!copy) { + D_OOM(); + return; + } + + /* Free old string. */ + if (thread->name) + D_FREE( thread->name ); + + /* Keep the copy. */ + thread->name = copy; +} + +DirectResult +direct_thread_wait( DirectThread *thread, int timeout_ms ) +{ + unsigned int old_counter = thread->counter; + + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->thread != -1 ); + + D_ASSUME( !thread->canceled ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d, %dms )\n", __FUNCTION__, + thread->main, thread->name, thread->tid, timeout_ms ); + + while (old_counter == thread->counter && !thread->terminated) + pthread_cond_wait( &thread->cond, &thread->lock ); + + if (thread->terminated) + return DR_DEAD; + + return DR_OK; +} + +void +direct_thread_notify( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->thread != -1 ); + + D_ASSUME( !thread->canceled ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); + + pthread_mutex_lock( &thread->lock ); + + thread->counter++; + + pthread_mutex_unlock( &thread->lock ); + + pthread_cond_broadcast( &thread->cond ); +} + +void +direct_thread_lock( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->thread != -1 ); + + D_ASSUME( !thread->canceled ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); + + pthread_mutex_lock( &thread->lock ); +} + +void +direct_thread_unlock( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->thread != -1 ); + + D_ASSUME( !thread->canceled ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); + + pthread_mutex_unlock( &thread->lock ); +} + +void +direct_thread_terminate( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->thread != -1 ); + D_ASSUME( !pthread_equal( thread->thread, pthread_self() ) ); + + D_ASSUME( !thread->canceled ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); + + thread->terminated = true; + + direct_thread_notify( thread ); +} + +void +direct_thread_cancel( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->thread != -1 ); + D_ASSERT( !pthread_equal( thread->thread, pthread_self() ) ); + + D_ASSUME( !thread->canceled ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); + + thread->canceled = true; + +#if DIRECT_BUILD_NO_PTHREAD_CANCEL + D_UNIMPLEMENTED(); +#else + pthread_cancel( thread->thread ); +#endif +} + +bool +direct_thread_is_canceled( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + + return thread->canceled; +} + +void +direct_thread_detach( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->thread != -1 ); + D_ASSERT( !pthread_equal( thread->thread, pthread_self() ) ); + + D_ASSUME( !thread->canceled ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); + + thread->detached = true; + + pthread_detach( thread->thread ); +} + +bool +direct_thread_is_detached( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + + return thread->detached; +} + +void +direct_thread_testcancel( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->thread != -1 ); + D_ASSERT( pthread_equal( thread->thread, pthread_self() ) ); + +#if DIRECT_BUILD_NO_PTHREAD_CANCEL + D_UNIMPLEMENTED(); +#else + /* Quick check before calling the pthread function. */ + if (thread->canceled) + pthread_testcancel(); +#endif +} + +void +direct_thread_join( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSERT( thread->thread != -1 ); + + D_ASSUME( !pthread_equal( thread->thread, pthread_self() ) ); + D_ASSUME( !thread->joining ); + D_ASSUME( !thread->joined ); + D_ASSUME( !thread->detached ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); + + if (thread->detached) { + D_DEBUG_AT( Direct_Thread, " -> DETACHED!\n" ); + return; + } + + if (!thread->joining && !pthread_equal( thread->thread, pthread_self() )) { + thread->joining = true; + + D_DEBUG_AT( Direct_Thread, " -> joining...\n" ); + + pthread_join( thread->thread, NULL ); + + thread->joined = true; + + D_DEBUG_AT( Direct_Thread, " -> joined.\n" ); + } +} + +bool +direct_thread_is_joined( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + + return thread->joined; +} + +void +direct_thread_destroy( DirectThread *thread ) +{ + D_MAGIC_ASSERT( thread, DirectThread ); + D_ASSUME( !pthread_equal( thread->thread, pthread_self() ) ); + D_ASSUME( !thread->detached ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); + + if (thread->detached) { + D_DEBUG_AT( Direct_Thread, " -> DETACHED!\n" ); + return; + } + + if (!thread->joined && !pthread_equal( thread->thread, pthread_self() )) { + if (thread->canceled) + D_DEBUG_AT( Direct_Thread, " -> cancled but not joined!\n" ); + else { + D_DEBUG_AT( Direct_Thread, " -> still running!\n" ); + + if (thread->name) + D_ERROR( "Direct/Thread: Canceling '%s' (%d)!\n", thread->name, thread->tid ); + else + D_ERROR( "Direct/Thread: Canceling %d!\n", thread->tid ); + + thread->detached = true; + + pthread_detach( thread->thread ); + + direct_thread_cancel( thread ); + + return; + } + } + + D_MAGIC_CLEAR( thread ); + + D_FREE( thread->name ); + D_FREE( thread ); +} + +/******************************************************************************/ + +#if DIRECT_BUILD_TEXT +const char * +direct_thread_type_name( DirectThreadType type ) +{ + switch (type) { + case DTT_DEFAULT: + return "DEFAULT"; + + case DTT_CLEANUP: + return "CLEANUP"; + + case DTT_INPUT: + return "INPUT"; + + case DTT_OUTPUT: + return "OUTPUT"; + + case DTT_MESSAGING: + return "MESSAGING"; + + case DTT_CRITICAL: + return "CRITICAL"; + } + + return ""; +} + +const char * +direct_thread_scheduler_name( DirectConfigThreadScheduler scheduler ) +{ + switch (scheduler) { + case DCTS_OTHER: + return "OTHER"; + + case DCTS_FIFO: + return "FIFO"; + + case DCTS_RR: + return "RR"; + } + + return ""; +} + +const char * +direct_thread_policy_name( int policy ) +{ + switch (policy) { + case SCHED_OTHER: + return "OTHER"; + + case SCHED_FIFO: + return "FIFO"; + + case SCHED_RR: + return "RR"; + } + + return ""; +} +#endif + +/******************************************************************************/ + +static void +direct_thread_cleanup( void *arg ) +{ + DirectThread *thread = arg; + + D_MAGIC_ASSERT( thread, DirectThread ); + + D_DEBUG_AT( Direct_Thread, "%s( %p, '%s' %d )\n", __FUNCTION__, thread->main, thread->name, thread->tid ); + + if (thread->detached) { + D_MAGIC_CLEAR( thread ); + + D_FREE( thread->name ); + D_FREE( thread ); + } +} + +/******************************************************************************/ + +static void * +direct_thread_main( void *arg ) +{ + void *ret; + DirectThread *thread = arg; + DirectThreadInitHandler *handler; + pid_t tid; + + tid = direct_gettid(); + + D_DEBUG_AT( Direct_ThreadInit, "%s( %p ) <- tid %d\n", __FUNCTION__, arg, tid ); + + D_DEBUG_AT( Direct_ThreadInit, " -> starting...\n" ); + + D_MAGIC_ASSERT( thread, DirectThread ); + + pthread_cleanup_push( direct_thread_cleanup, thread ); + + + pthread_setspecific( thread_key, thread ); + + thread->tid = tid; + + + /* Call all init handlers. */ + pthread_mutex_lock( &handler_lock ); + + direct_list_foreach (handler, handlers) + handler->func( thread, handler->arg ); + + pthread_mutex_unlock( &handler_lock ); + + + /* Have all signals handled by the main thread. */ + if (direct_config->thread_block_signals) + direct_signals_block_all(); + + /* Lock the thread mutex. */ + D_DEBUG_AT( Direct_ThreadInit, " -> locking...\n" ); + pthread_mutex_lock( &thread->lock ); + + /* Indicate that our initialization has completed. */ + thread->init = true; + +#ifdef DIRECT_THREAD_WAIT_INIT + D_DEBUG_AT( Direct_ThreadInit, " -> signalling...\n" ); + pthread_cond_signal( &thread->cond ); +#endif + + /* Unlock the thread mutex. */ + D_DEBUG_AT( Direct_ThreadInit, " -> unlocking...\n" ); + pthread_mutex_unlock( &thread->lock ); + + if (thread->joining) { + D_DEBUG_AT( Direct_Thread, " -> Being joined before entering main routine!\n" ); + return NULL; + } + + D_MAGIC_ASSERT( thread, DirectThread ); + + /* Call main routine. */ + D_DEBUG_AT( Direct_ThreadInit, " -> running...\n" ); + ret = thread->main( thread, thread->arg ); + + D_DEBUG_AT( Direct_Thread, " -> Returning %p from '%s' (%s, %d)...\n", + ret, thread->name, direct_thread_type_name(thread->type), thread->tid ); + + D_MAGIC_ASSERT( thread, DirectThread ); + + pthread_cleanup_pop( 1 ); + + return ret; +} + diff --git a/Source/DirectFB/lib/direct/thread.h b/Source/DirectFB/lib/direct/thread.h new file mode 100755 index 0000000..18205c4 --- /dev/null +++ b/Source/DirectFB/lib/direct/thread.h @@ -0,0 +1,168 @@ +/* + (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 __DIRECT__THREAD_H__ +#define __DIRECT__THREAD_H__ + +#include + +#include +#include + +typedef enum { + DTT_DEFAULT = 0, + DTT_CLEANUP = -5, + DTT_INPUT = -10, + DTT_OUTPUT = -12, + DTT_MESSAGING = -15, + DTT_CRITICAL = -20 +} DirectThreadType; + +typedef void * (*DirectThreadMainFunc)( DirectThread *thread, void *arg ); + +typedef void (*DirectThreadInitFunc)( DirectThread *thread, void *arg ); + + +/* + * Add a handler being called at the beginning of new threads. + */ +DirectThreadInitHandler *direct_thread_add_init_handler ( DirectThreadInitFunc func, + void *arg ); + +/* + * Remove the specified handler. + */ +void direct_thread_remove_init_handler( DirectThreadInitHandler *handler ); + +/* + * Create a new thread and start it. + * The thread type is relevant for the scheduling priority. + */ +DirectThread *direct_thread_create ( DirectThreadType thread_type, + DirectThreadMainFunc thread_main, + void *arg, + const char *name ); + +/* + * Returns the thread of the caller. + */ +DirectThread *direct_thread_self ( void ); + +/* + * Returns the name of the specified thread. + */ +const char *direct_thread_get_name ( DirectThread *thread ); + +/* + * Returns the thread ID of the specified thread. + */ +pid_t direct_thread_get_tid ( DirectThread *thread ); + +/* + * Returns the name of the calling thread. + */ +const char *direct_thread_self_name ( void ); + +/* + * Changes the name of the calling thread. + */ +void direct_thread_set_name ( const char *name ); + +/* + * Wait on the thread object to be notified via direct_thread_notify(). + */ +DirectResult direct_thread_wait ( DirectThread *thread, + int timeout_ms ); + +/* + * Notify the thread object waking up callers of direct_thread_wait(). + */ +void direct_thread_notify ( DirectThread *thread ); + +void direct_thread_lock ( DirectThread *thread ); +void direct_thread_unlock ( DirectThread *thread ); + +/* + * Kindly ask the thread to terminate (for joining without thread cancellation). + */ +void direct_thread_terminate ( DirectThread *thread ); + +/* + * Cancel a running thread. + */ +void direct_thread_cancel ( DirectThread *thread ); + +/* + * Returns true if the specified thread has been canceled. + */ +bool direct_thread_is_canceled( DirectThread *thread ); + +/* + * Detach a thread. + */ +void direct_thread_detach ( DirectThread *thread ); + +/* + * Returns true if the specified thread has been detached. + */ +bool direct_thread_is_detached( DirectThread *thread ); + +/* + * Check if the calling thread is canceled. + * Must not be called by other threads than 'thread'. + * This function won't return if the thread is canceled. + */ +void direct_thread_testcancel ( DirectThread *thread ); + +/* + * Wait until a running thread is terminated. + */ +void direct_thread_join ( DirectThread *thread ); + +/* + * Returns true if the specified thread has been join. + */ +bool direct_thread_is_joined ( DirectThread *thread ); + +/* + * Free resources allocated by direct_thread_create. + * If the thread is still running it will be killed. + */ +void direct_thread_destroy ( DirectThread *thread ); + +/* + * Utilities for stringification. + */ +#if DIRECT_BUILD_TEXT +const char *direct_thread_type_name ( DirectThreadType type ); +const char *direct_thread_scheduler_name( DirectConfigThreadScheduler scheduler ); +const char *direct_thread_policy_name ( int policy ); +#endif + +#endif + diff --git a/Source/DirectFB/lib/direct/trace.c b/Source/DirectFB/lib/direct/trace.c new file mode 100755 index 0000000..d895333 --- /dev/null +++ b/Source/DirectFB/lib/direct/trace.c @@ -0,0 +1,676 @@ +/* + (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 + + +#ifdef PIC +#define DYNAMIC_LINKING +#endif + + +#if DIRECT_BUILD_TRACE + +#ifdef DYNAMIC_LINKING +#include +#endif + +#define MAX_BUFFERS 200 +#define MAX_LEVEL 200 + +#define NAME_LEN 92 + + +typedef enum { + TF_NONE = 0x00000000, + + TF_DEBUG = 0x00000001 +} TraceFlags; + +typedef struct { + void *addr; + TraceFlags flags; +} Trace; + +struct __D_DirectTraceBuffer { + pid_t tid; + char *name; + int level; + bool in_trace; + Trace trace[MAX_LEVEL]; +}; + +/**************************************************************************************************/ + +static DirectTraceBuffer *buffers[MAX_BUFFERS]; +static int buffers_num = 0; +static pthread_mutex_t buffers_lock = PTHREAD_MUTEX_INITIALIZER; +static pthread_key_t trace_key = -1; + +/**************************************************************************************************/ + +__attribute__((no_instrument_function)) +static void +buffer_destroy( void *arg ) +{ + int i; + DirectTraceBuffer *buffer = arg; + + pthread_mutex_lock( &buffers_lock ); + + /* Remove from list. */ + for (i=0; itid = direct_gettid(); + buffer->name = name ? strdup( name ) : NULL; + + buffers[buffers_num++] = buffer; + + pthread_mutex_unlock( &buffers_lock ); + } + + return buffer; +} + +/**************************************************************************************************/ + +typedef struct { + long offset; + char name[NAME_LEN]; +} Symbol; + +typedef struct { + DirectLink link; + + char *filename; + Symbol *symbols; + int capacity; + int num_symbols; +} SymbolTable; + +static DirectLink *tables = NULL; +static pthread_mutex_t tables_lock = PTHREAD_MUTEX_INITIALIZER; + + +__attribute__((no_instrument_function)) +static void +add_symbol( SymbolTable *table, long offset, const char *name ) +{ + Symbol *symbol; + + if (table->num_symbols == table->capacity) { + Symbol *symbols; + int capacity = table->capacity * 2; + + if (!capacity) + capacity = 256; + + symbols = malloc( capacity * sizeof(Symbol) ); + if (!symbols) { + D_WARN( "out of memory" ); + return; + } + + direct_memcpy( symbols, table->symbols, table->num_symbols * sizeof(Symbol) ); + + free( table->symbols ); + + table->symbols = symbols; + table->capacity = capacity; + } + + symbol = &table->symbols[ table->num_symbols++ ]; + + symbol->offset = offset; + + direct_snputs( symbol->name, name, NAME_LEN ); +} + +__attribute__((no_instrument_function)) +static SymbolTable * +load_symbols( const char *filename ) +{ + SymbolTable *table; + FILE *fp = NULL; + bool is_pipe = false; + char file[1024]; + char line[1024]; + int command_len; + char *command; + const char *full_path = filename; + char *tmp; + + if (filename) { + if (access( filename, R_OK ) < 0 && errno == ENOENT) { + int len; + + if ((len = readlink( "/proc/self/exe", file, sizeof(file) - 1 )) < 0) { + D_PERROR( "Direct/Trace: readlink( \"/proc/self/exe\" ) failed!\n" ); + return NULL; + } + + file[len] = 0; + + + tmp = strrchr( file, '/' ); + if (!tmp) + return NULL; + + if (strcmp( filename, tmp + 1 )) + return NULL; + + full_path = file; + } + } + else { + int len; + + if ((len = readlink( "/proc/self/exe", file, sizeof(file) - 1 )) < 0) { + D_PERROR( "Direct/Trace: readlink( \"/proc/self/exe\" ) failed!\n" ); + return NULL; + } + + file[len] = 0; + + full_path = file; + } + + command_len = strlen( full_path ) + 32; + command = alloca( command_len ); + + /* First check if there's an "nm-n" file. */ + tmp = strrchr( full_path, '/' ); + if (!tmp) + return NULL; + + *tmp = 0; + snprintf( command, command_len, "%s/nm-n.%s", full_path, tmp + 1 ); + *tmp = '/'; + + if (access( command, R_OK ) == 0) { + fp = fopen( command, "r" ); + if (!fp) + D_PERROR( "Direct/Trace: fopen( \"%s\", \"r\" ) failed!\n", command ); + } + else { + snprintf( command, command_len, "%s.nm", full_path ); + if (access( command, R_OK ) == 0) { + fp = fopen( command, "r" ); + if (!fp) + D_PERROR( "Direct/Trace: fopen( \"%s\", \"r\" ) failed!\n", command ); + } + } + + /* Fallback to live mode. */ + if (!fp) { + snprintf( command, command_len, "nm -n %s", full_path ); + + fp = popen( command, "r" ); + if (!fp) { + D_PERROR( "Direct/Trace: popen( \"%s\", \"r\" ) failed!\n", command ); + return NULL; + } + + is_pipe = true; + } + + table = calloc( 1, sizeof(SymbolTable) ); + if (!table) { + D_OOM(); + goto out; + } + + if (filename) + table->filename = strdup( filename ); + + while (fgets( line, sizeof(line), fp )) { + int n; + int digits = sizeof(long) * 2; + long offset = 0; + int length = strlen(line); + + if (line[0] == ' ' || length < (digits + 5) || line[length-1] != '\n') + continue; + + if (line[digits + 1] != 't' && line[digits + 1] != 'T' && line[digits + 1] != 'W') + continue; + + if (line[digits] != ' ' || line[digits + 2] != ' ' || line[digits + 3] == '.') + continue; + + for (n=0; n= '0' && c <= '9') + offset |= c - '0'; + else + offset |= c - 'a' + 10; + } + + line[length-1] = 0; + + add_symbol( table, offset, line + digits + 3 ); + } + +out: + if (is_pipe) + pclose( fp ); + else + fclose( fp ); + + return table; +} + +__attribute__((no_instrument_function)) +static int +compare_symbols(const void *x, const void *y) +{ + return *((const long*) x) - *((const long*) y); +} + +__attribute__((no_instrument_function)) +static SymbolTable * +find_table( const char *filename ) +{ + SymbolTable *table; + + if (filename) { + direct_list_foreach (table, tables) { + if (table->filename && !strcmp( filename, table->filename )) + return table; + } + } + else { + direct_list_foreach (table, tables) { + if (!table->filename) + return table; + } + } + + return NULL; +} + +/**************************************************************************************************/ + +__attribute__((no_instrument_function)) +const char * +direct_trace_lookup_symbol( const char *filename, long offset ) +{ + Symbol *symbol; + SymbolTable *table; + + pthread_mutex_lock( &tables_lock ); + + table = find_table( filename ); + if (!table) { + table = load_symbols( filename ); + if (!table) { + pthread_mutex_unlock( &tables_lock ); + return false; + } + + direct_list_prepend( &tables, &table->link ); + } + + pthread_mutex_unlock( &tables_lock ); + + symbol = bsearch( &offset, table->symbols, table->num_symbols, + sizeof(Symbol), compare_symbols ); + + return symbol ? symbol->name : NULL; +} + +__attribute__((no_instrument_function)) +const char * +direct_trace_lookup_file( void *address, void **ret_base ) +{ +#ifdef DYNAMIC_LINKING + Dl_info info; + + if (dladdr( address, &info )) { + if (ret_base) + *ret_base = info.dli_fbase; + + return info.dli_fname; + } + else +#endif + { + if (ret_base) + *ret_base = NULL; + } + + return NULL; +} + +__attribute__((no_instrument_function)) +void +direct_trace_print_stack( DirectTraceBuffer *buffer ) +{ +#ifdef DYNAMIC_LINKING + Dl_info info; +#endif + int i; + int level; + + if (!direct_config->trace) + return; + + if (!buffer) + buffer = get_trace_buffer(); + + if (buffer->in_trace) + return; + + buffer->in_trace = true; + + + level = buffer->level; + if (level > MAX_LEVEL) { + D_WARN( "only showing %d of %d items", MAX_LEVEL, level ); + level = MAX_LEVEL; + } + else if (level == 0) { + buffer->in_trace = false; + return; + } + + direct_log_lock( NULL ); + + if (buffer->name) + direct_log_printf( NULL, "(-) [%5d: -STACK- '%s']\n", buffer->tid, buffer->name ); + else + direct_log_printf( NULL, "(-) [%5d: -STACK- ]\n", buffer->tid ); + + for (i=level-1; i>=0; i--) { + void *fn = buffer->trace[i].addr; + +#ifdef DYNAMIC_LINKING + if (dladdr( fn, &info )) { + if (info.dli_fname) { + const char *symbol = NULL;//info.dli_sname; + + if (!symbol) { + symbol = direct_trace_lookup_symbol(info.dli_fname, (long)(fn - info.dli_fbase)); + if (!symbol) { + symbol = direct_trace_lookup_symbol(info.dli_fname, (long)(fn)); + if (!symbol) { + if (info.dli_sname) + symbol = info.dli_sname; + else + symbol = "??"; + } + } + } + + direct_log_printf( NULL, " #%-2d 0x%08lx in %s () from %s [%p]\n", + level - i - 1, (unsigned long) fn, symbol, info.dli_fname, info.dli_fbase ); + } + else if (info.dli_sname) { + direct_log_printf( NULL, " #%-2d 0x%08lx in %s ()\n", + level - i - 1, (unsigned long) fn, info.dli_sname ); + } + else + direct_log_printf( NULL, " #%-2d 0x%08lx in ?? ()\n", + level - i - 1, (unsigned long) fn ); + } + else +#endif + { + const char *symbol = direct_trace_lookup_symbol(NULL, (long)(fn)); + direct_log_printf( NULL, " #%-2d 0x%08lx in %s ()\n", + level - i - 1, (unsigned long) fn, symbol ? symbol : "??" ); + } + } + + direct_log_printf( NULL, "\n" ); + direct_log_unlock( NULL ); + + buffer->in_trace = false; +} + +__attribute__((no_instrument_function)) +void +direct_trace_print_stacks( void ) +{ + int i; + DirectTraceBuffer *buffer = get_trace_buffer(); + + if (buffer->level) + direct_trace_print_stack( buffer ); + + pthread_mutex_lock( &buffers_lock ); + + for (i=0; ilevel) + direct_trace_print_stack( buffers[i] ); + } + + pthread_mutex_unlock( &buffers_lock ); +} + +__attribute__((no_instrument_function)) +int +direct_trace_debug_indent( void ) +{ + int in; + DirectTraceBuffer *buffer = get_trace_buffer(); + int level = buffer->level - 1; + + if (level < 0) + return 0; + + buffer->trace[level--].flags |= TF_DEBUG; + + for (in=0; level>=0; level--) { + if (buffer->trace[level].flags & TF_DEBUG) + in++; + } + + return in; +} + +__attribute__((no_instrument_function)) +DirectTraceBuffer * +direct_trace_copy_buffer( DirectTraceBuffer *buffer ) +{ + int level; + DirectTraceBuffer *copy; + + if (!buffer) + buffer = get_trace_buffer(); + + level = buffer->level; + if (level > MAX_LEVEL) { + D_WARN( "only copying %d of %d items", MAX_LEVEL, level ); + level = MAX_LEVEL; + } + + copy = calloc( 1, sizeof(*buffer) - sizeof(buffer->trace) + sizeof(buffer->trace[0]) * level ); + if (!copy) + return NULL; + + if (buffer->name) + copy->name = strdup( buffer->name ); + + copy->tid = buffer->tid; + copy->level = buffer->level; + + direct_memcpy( copy->trace, buffer->trace, level * sizeof(buffer->trace[0]) ); + + return copy; +} + +__attribute__((no_instrument_function)) +void +direct_trace_free_buffer( DirectTraceBuffer *buffer ) +{ + if (buffer->name) + free( buffer->name ); + + free( buffer ); +} + +/**************************************************************************************************/ + +__attribute__((no_instrument_function)) +void +__cyg_profile_func_enter (void *this_fn, + void *call_site) +{ + if (direct_config->trace) { + DirectTraceBuffer *buffer = get_trace_buffer(); + int level = buffer->level++; + Trace *trace = &buffer->trace[level]; + + if (level < MAX_LEVEL) { + trace->addr = this_fn; + trace->flags = TF_NONE; + } + } +} + +__attribute__((no_instrument_function)) +void +__cyg_profile_func_exit (void *this_fn, + void *call_site) +{ + if (direct_config->trace) { + DirectTraceBuffer *buffer = get_trace_buffer(); + + if (buffer->level > 0) + buffer->level--; + } +} + +#else + +const char * +direct_trace_lookup_symbol( const char *filename, long offset ) +{ + return NULL; +} + +const char * +direct_trace_lookup_file( void *address, void **ret_base ) +{ + if (ret_base) + *ret_base = NULL; + + return NULL; +} + +void +direct_trace_print_stack( DirectTraceBuffer *buffer ) +{ +} + +void +direct_trace_print_stacks( void ) +{ +} + +int +direct_trace_debug_indent( void ) +{ + return 0; +} + +DirectTraceBuffer * +direct_trace_copy_buffer( DirectTraceBuffer *buffer ) +{ + return NULL; +} + +void +direct_trace_free_buffer( DirectTraceBuffer *buffer ) +{ +} + +#endif + diff --git a/Source/DirectFB/lib/direct/trace.h b/Source/DirectFB/lib/direct/trace.h new file mode 100755 index 0000000..2975522 --- /dev/null +++ b/Source/DirectFB/lib/direct/trace.h @@ -0,0 +1,98 @@ +/* + (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 __DIRECT__TRACE_H__ +#define __DIRECT__TRACE_H__ + +#include + +/*********************************************************************************************************************** +** Symbols +*/ + +/* + * Returns filename on success or NULL. + * + * Stores load address of object in 'ret_base' on success. + */ +const char *direct_trace_lookup_file ( void *address, + void **ret_base ); + +/* + * Look up a symbol by filename and offset. + * + * Returns symbol name on success or NULL. + */ +const char *direct_trace_lookup_symbol( const char *filename, + long offset ); + +/* + * Convenience function combining direct_trace_lookup_file() and direct_trace_lookup_symbol(). + */ +static inline const char * +direct_trace_lookup_symbol_at( void *address ) +{ + void *base; + const char *filename; + + filename = direct_trace_lookup_file( address, &base ); + + return direct_trace_lookup_symbol( filename, (unsigned long) address - (unsigned long) base ); +} + +/*********************************************************************************************************************** +** Stacks +*/ + +/* + * Print stack in 'buffer' or current if NULL. + */ +void direct_trace_print_stack( DirectTraceBuffer *buffer ); + +/* + * Print stack of each known thread. + */ +void direct_trace_print_stacks( void ); + +/* + * Returns indent level for debug output. + */ +int direct_trace_debug_indent( void ); + +/* + * Create a copy of a stack in 'buffer' or of current if NULL. + */ +DirectTraceBuffer *direct_trace_copy_buffer( DirectTraceBuffer *buffer ); + +/* + * Free a (copied) stack buffer. + */ +void direct_trace_free_buffer( DirectTraceBuffer *buffer ); + +#endif + diff --git a/Source/DirectFB/lib/direct/tree.c b/Source/DirectFB/lib/direct/tree.c new file mode 100755 index 0000000..38aac17 --- /dev/null +++ b/Source/DirectFB/lib/direct/tree.c @@ -0,0 +1,307 @@ +/* + (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 . + + Balanced binary tree ported from glib-2.0. + + 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 + + +static DirectNode *tree_node_new ( DirectTree *tree, + void *key, + void *value ); + +static void tree_node_destroy ( DirectTree *tree, + DirectNode *node ); + +static DirectNode *tree_node_insert ( DirectTree *tree, + DirectNode *node, + void *key, + void *value, + int *inserted ); + +static DirectNode *tree_node_lookup ( DirectNode *node, + void *key ); + +static DirectNode *tree_node_balance ( DirectNode *node ); + +static DirectNode *tree_node_rotate_left ( DirectNode *node ); + +static DirectNode *tree_node_rotate_right( DirectNode *node ); + + +DirectTree * +direct_tree_new( void ) +{ + return D_CALLOC( 1, sizeof (DirectTree) ); +} + +void +direct_tree_destroy( DirectTree *tree ) +{ + unsigned int i; + + for (i = 0; i < 128; i++) { + if (tree->fast_keys[i]) + D_FREE( tree->fast_keys[i] ); + } + + tree_node_destroy( tree, tree->root ); + + D_FREE( tree ); +} + +void +direct_tree_insert( DirectTree *tree, + void *key, + void *value ) +{ + int inserted = 0; + unsigned long fast_key = (unsigned long) key; + + if (fast_key < 128) + tree->fast_keys[fast_key] = value; + else + tree->root = tree_node_insert( tree, tree->root, key, value, &inserted ); +} + +void * +direct_tree_lookup( DirectTree *tree, + void *key ) +{ + DirectNode *node; + unsigned long fast_key = (unsigned long) key; + + if (fast_key < 128) + return tree->fast_keys[fast_key]; + + node = tree_node_lookup( tree->root, key ); + + return node ? node->value : NULL; +} + +static DirectNode * +tree_node_new( DirectTree *tree, + void *key, + void *value ) +{ + DirectNode *node; + + node = D_MALLOC(sizeof (DirectNode)); + + node->balance = 0; + node->left = NULL; + node->right = NULL; + node->key = key; + node->value = value; + + return node; +} + +static void +tree_node_destroy (DirectTree *tree, + DirectNode *node) +{ + if (node) { + tree_node_destroy (tree, node->left); + tree_node_destroy (tree, node->right); + + if (node->value) + D_FREE(node->value); + + D_FREE(node); + } +} + +static DirectNode * +tree_node_insert (DirectTree *tree, + DirectNode *node, + void *key, + void *value, + int *inserted) +{ + int cmp; + int old_balance; + + if (!node) { + *inserted = 1; + return tree_node_new (tree, key, value); + } + + cmp = key - node->key; + if (cmp == 0) { + node->value = value; + return node; + } + + if (cmp < 0) { + if (node->left) { + old_balance = node->left->balance; + node->left = tree_node_insert (tree, node->left, + key, value, inserted); + + if ((old_balance != node->left->balance) && node->left->balance) + node->balance -= 1; + } + else { + *inserted = 1; + node->left = tree_node_new (tree, key, value); + node->balance -= 1; + } + } + else if (cmp > 0) { + if (node->right) { + old_balance = node->right->balance; + node->right = tree_node_insert (tree, node->right, + key, value, inserted); + + if ((old_balance != node->right->balance) && node->right->balance) + node->balance += 1; + } + else { + *inserted = 1; + node->right = tree_node_new (tree, key, value); + node->balance += 1; + } + } + + if (*inserted && (node->balance < -1 || node->balance > 1)) + node = tree_node_balance (node); + + return node; +} + +static DirectNode * +tree_node_lookup (DirectNode *node, + void *key) +{ + int cmp; + + if (!node) + return NULL; + + cmp = key - node->key; + if (cmp == 0) + return node; + + if (cmp < 0 && node->left) { + return tree_node_lookup (node->left, key); + } + else if (cmp > 0 && node->right) { + return tree_node_lookup (node->right, key); + } + + return NULL; +} + +static DirectNode * +tree_node_balance (DirectNode *node) +{ + if (node->balance < -1) { + if (node->left->balance > 0) + node->left = tree_node_rotate_left (node->left); + node = tree_node_rotate_right (node); + } + else if (node->balance > 1) { + if (node->right->balance < 0) + node->right = tree_node_rotate_right (node->right); + node = tree_node_rotate_left (node); + } + + return node; +} + +static DirectNode * +tree_node_rotate_left (DirectNode *node) +{ + DirectNode *right; + int a_bal; + int b_bal; + + right = node->right; + + node->right = right->left; + right->left = node; + + a_bal = node->balance; + b_bal = right->balance; + + if (b_bal <= 0) { + if (a_bal >= 1) + right->balance = b_bal - 1; + else + right->balance = a_bal + b_bal - 2; + node->balance = a_bal - 1; + } + else { + if (a_bal <= b_bal) + right->balance = a_bal - 2; + else + right->balance = b_bal - 1; + node->balance = a_bal - b_bal - 1; + } + + return right; +} + +static DirectNode * +tree_node_rotate_right (DirectNode *node) +{ + DirectNode *left; + int a_bal; + int b_bal; + + left = node->left; + + node->left = left->right; + left->right = node; + + a_bal = node->balance; + b_bal = left->balance; + + if (b_bal <= 0) { + if (b_bal > a_bal) + left->balance = b_bal + 1; + else + left->balance = a_bal + 2; + node->balance = a_bal - b_bal + 1; + } + else { + if (a_bal <= -1) + left->balance = b_bal + 1; + else + left->balance = a_bal + b_bal + 2; + node->balance = a_bal + 1; + } + + return left; +} diff --git a/Source/DirectFB/lib/direct/tree.h b/Source/DirectFB/lib/direct/tree.h new file mode 100755 index 0000000..165ed1c --- /dev/null +++ b/Source/DirectFB/lib/direct/tree.h @@ -0,0 +1,67 @@ +/* + (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 . + + Balanced binary tree ported from glib by Sven Neumann + . + + 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 __DIRECT__TREE_H__ +#define __DIRECT__TREE_H__ + +#include + + +typedef struct __D_DirectNode DirectNode; + +struct __D_DirectTree +{ + DirectNode *root; + void *fast_keys[128]; +}; + +struct __D_DirectNode +{ + int balance; + DirectNode *left; + DirectNode *right; + void *key; + void *value; +}; + + +DirectTree *direct_tree_new ( void ); + +void direct_tree_destroy( DirectTree *tree ); + +void direct_tree_insert ( DirectTree *tree, + void *key, + void *value ); + +void *direct_tree_lookup ( DirectTree *tree, + void *key ); + +#endif diff --git a/Source/DirectFB/lib/direct/types.h b/Source/DirectFB/lib/direct/types.h new file mode 100755 index 0000000..2677e00 --- /dev/null +++ b/Source/DirectFB/lib/direct/types.h @@ -0,0 +1,169 @@ +/* + (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 __DIRECT__TYPES_H__ +#define __DIRECT__TYPES_H__ + +#include + +/* + * Define the bool type by including stdbool.h (preferably)... + */ +#if DIRECT_BUILD_STDBOOL +# include +/* + * ...or defining it ourself, if not using C++ or another definition + */ +#elif !defined(__cplusplus) && !defined(__bool_true_false_are_defined) +# warning Fallback definition of bool using u8! Checking for 'flags & 0x100' or higher bits will be false :( + typedef u8 bool; +# ifndef false +# define false (0) +# endif +# ifndef true +# define true (!false) +# endif +#endif /* DIRECT_BUILD_STDBOOL */ + + +#ifdef USE_KOS + +#include + +typedef uint8 u8; +typedef uint16 u16; +typedef uint32 u32; +typedef uint64 u64; + +typedef sint8 s8; +typedef sint16 s16; +typedef sint32 s32; +typedef sint64 s64; + +#else + +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef uint32_t u32; +typedef uint64_t u64; + +typedef int8_t s8; +typedef int16_t s16; +typedef int32_t s32; +typedef int64_t s64; + +#endif + + +typedef enum { + DR_OK = 0x00000000, /* No error occured. */ + DR_FAILURE, /* A general or unknown error occured. */ + DR_INIT, /* A general initialization error occured. */ + DR_BUG, /* Internal bug or inconsistency has been detected. */ + DR_DEAD, /* Interface has a zero reference counter (available in debug mode). */ + DR_UNSUPPORTED, /* The requested operation or an argument is (currently) not supported. */ + DR_UNIMPLEMENTED, /* The requested operation is not implemented, yet. */ + DR_ACCESSDENIED, /* Access to the resource is denied. */ + DR_INVAREA, /* An invalid area has been specified or detected. */ + DR_INVARG, /* An invalid argument has been specified. */ + DR_NOLOCALMEMORY, /* There's not enough local system memory. */ + DR_NOSHAREDMEMORY, /* There's not enough shared system memory. */ + DR_LOCKED, /* The resource is (already) locked. */ + DR_BUFFEREMPTY, /* The buffer is empty. */ + DR_FILENOTFOUND, /* The specified file has not been found. */ + DR_IO, /* A general I/O error occured. */ + DR_BUSY, /* The resource or device is busy. */ + DR_NOIMPL, /* No implementation for this interface or content type has been found. */ + DR_TIMEOUT, /* The operation timed out. */ + DR_THIZNULL, /* 'thiz' pointer is NULL. */ + DR_IDNOTFOUND, /* No resource has been found by the specified id. */ + DR_DESTROYED, /* The requested object has been destroyed. */ + DR_FUSION, /* Internal fusion error detected, most likely related to IPC resources. */ + DR_BUFFERTOOLARGE, /* Buffer is too large. */ + DR_INTERRUPTED, /* The operation has been interrupted. */ + DR_NOCONTEXT, /* No context available. */ + DR_TEMPUNAVAIL, /* Temporarily unavailable. */ + DR_LIMITEXCEEDED, /* Attempted to exceed limit, i.e. any kind of maximum size, count etc. */ + DR_NOSUCHMETHOD, /* Requested method is not known. */ + DR_NOSUCHINSTANCE, /* Requested instance is not known. */ + DR_ITEMNOTFOUND, /* No such item found. */ + DR_VERSIONMISMATCH, /* Some versions didn't match. */ + DR_EOF, /* Reached end of file. */ + DR_SUSPENDED, /* The requested object is suspended. */ + DR_INCOMPLETE, /* The operation has been executed, but not completely. */ + DR_NOCORE /* Core part not available. */ +} DirectResult; + +/* + * Generate result code base for API 'A','B','C', e.g. 'D','F','B'. + */ +#define D_RESULT_TYPE_BASE( a,b,c ) ((((unsigned)(a)&0x7f) * 0x02000000) + \ + (((unsigned)(b)&0x7f) * 0x00040000) + \ + (((unsigned)(c)&0x7f) * 0x00000800)) + +/* + * Generate result code maximum for API 'A','B','C', e.g. 'D','F','B'. + */ +#define D_RESULT_TYPE_MAX( a,b,c ) (D_RESULT_TYPE_BASE(a,b,c) + 0x7ff) + +/* + * Check if given result code belongs to API 'A','B','C', e.g. 'D','F','B'. + */ +#define D_RESULT_TYPE_IS( code,a,b,c ) ((code) >= D_RESULT_TYPE_BASE(a,b,c) && (code) <= D_RESULT_TYPE_MAX(a,b,c)) + + +/* + * Return value of enumeration callbacks + */ +typedef enum { + DENUM_OK = 0x00000000, /* Proceed with enumeration */ + DENUM_CANCEL = 0x00000001 /* Cancel enumeration */ +} DirectEnumerationResult; + + +typedef u32 unichar; + +typedef struct __D_DirectCleanupHandler DirectCleanupHandler; +typedef struct __D_DirectConfig DirectConfig; +typedef struct __D_DirectHash DirectHash; +typedef struct __D_DirectLink DirectLink; +typedef struct __D_DirectLog DirectLog; +typedef struct __D_DirectModuleDir DirectModuleDir; +typedef struct __D_DirectModuleEntry DirectModuleEntry; +typedef struct __D_DirectSerial DirectSerial; +typedef struct __D_DirectSignalHandler DirectSignalHandler; +typedef struct __D_DirectStream DirectStream; +typedef struct __D_DirectTraceBuffer DirectTraceBuffer; +typedef struct __D_DirectTree DirectTree; +typedef struct __D_DirectThread DirectThread; +typedef struct __D_DirectThreadInitHandler DirectThreadInitHandler; + +#endif + diff --git a/Source/DirectFB/lib/direct/utf8.c b/Source/DirectFB/lib/direct/utf8.c new file mode 100755 index 0000000..75896da --- /dev/null +++ b/Source/DirectFB/lib/direct/utf8.c @@ -0,0 +1,36 @@ +/* + (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 . + + UTF8 routines ported from glib-2.0 and optimized + + 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 + + + diff --git a/Source/DirectFB/lib/direct/utf8.h b/Source/DirectFB/lib/direct/utf8.h new file mode 100755 index 0000000..a073c65 --- /dev/null +++ b/Source/DirectFB/lib/direct/utf8.h @@ -0,0 +1,80 @@ +/* + (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 . + + UTF8 routines ported from glib-2.0 and optimized + + 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 __DIRECT__UTF8_H__ +#define __DIRECT__UTF8_H__ + +#include + + +#define DIRECT_UTF8_SKIP(c) (((u8)(c) < 0xc0) ? 1 : __direct_utf8_skip[(u8)(c)&0x3f]) + +#define DIRECT_UTF8_GET_CHAR(p) (*(const u8*)(p) < 0xc0 ? \ + *(const u8*)(p) : __direct_utf8_get_char((const u8*)(p))) + + +/* + * Actually the last two fields used to be zero since they indicate an + * invalid UTF-8 string. Changed it to 1 to avoid endless looping on + * invalid input. + */ +static const char __direct_utf8_skip[64] = { + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1 +}; + +static __inline__ unichar __direct_utf8_get_char( const u8 *p ) +{ + int len; + register unichar result = p[0]; + + if (result < 0xc0) + return result; + + if (result > 0xfd) + return (unichar) -1; + + len = __direct_utf8_skip[result & 0x3f]; + + result &= 0x7c >> len; + + while (--len) { + int c = *(++p); + + if ((c & 0xc0) != 0x80) + return (unichar) -1; + + result = (result << 6) | (c & 0x3f); + } + + return result; +} + +#endif diff --git a/Source/DirectFB/lib/direct/util.c b/Source/DirectFB/lib/direct/util.c new file mode 100755 index 0000000..9e7a03a --- /dev/null +++ b/Source/DirectFB/lib/direct/util.c @@ -0,0 +1,519 @@ +/* + (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 + +#ifdef CLOCK_MONOTONIC +#include +#endif + +static int no_monotonic_pthread_clock; + +/* + * translates errno to DirectResult + */ +DirectResult +errno2result( int erno ) +{ + switch (erno) { + case 0: + return DR_OK; + case ENOENT: + return DR_FILENOTFOUND; + case EACCES: + case EPERM: + return DR_ACCESSDENIED; + case EBUSY: + case EAGAIN: + return DR_BUSY; + case ECONNREFUSED: + return DR_ACCESSDENIED; + case ENODEV: + case ENXIO: +#ifdef ENOTSUP + /* ENOTSUP is not defined on NetBSD */ + case ENOTSUP: +#endif + return DR_UNSUPPORTED; + } + + return DR_FAILURE; +} + +const char * +DirectResultString( DirectResult result ) +{ + if (!D_RESULT_TYPE_IS( result, 0, 0, 0 )) + return "UNKNOWN RESULT CODE TYPE!"; + + switch (result) { + case DR_OK: + return "OK"; + case DR_FAILURE: + return "General failure!"; + case DR_INIT: + return "Initialization error!"; + case DR_BUG: + return "Internal bug!"; + case DR_DEAD: + return "Interface was released!"; + case DR_UNSUPPORTED: + return "Not supported!"; + case DR_UNIMPLEMENTED: + return "Not implemented!"; + case DR_ACCESSDENIED: + return "Access denied!"; + case DR_INVARG: + return "Invalid argument!"; + case DR_NOLOCALMEMORY: + return "Out of memory!"; + case DR_LOCKED: + return "Resource is locked!"; + case DR_BUFFEREMPTY: + return "Buffer is empty!"; + case DR_FILENOTFOUND: + return "File not found!"; + case DR_IO: + return "General I/O error!"; + case DR_NOIMPL: + return "No (suitable) implementation found!"; + case DR_TIMEOUT: + return "Operation timed out!"; + case DR_BUSY: + return "Resource is busy!"; + case DR_THIZNULL: + return "'thiz' argument is NULL!"; + case DR_IDNOTFOUND: + return "Requested ID not found!"; + case DR_INVAREA: + return "Invalid area present!"; + case DR_DESTROYED: + return "Resource was destroyed!"; + case DR_FUSION: + return "Fusion IPC error detected!"; + case DR_BUFFERTOOLARGE: + return "Buffer is too large!"; + case DR_INTERRUPTED: + return "Operation has been interrupted!"; + case DR_NOCONTEXT: + return "No context available!"; + case DR_TEMPUNAVAIL: + return "Resource temporarily unavailable!"; + case DR_LIMITEXCEEDED: + return "Limit has been exceeded!"; + case DR_NOSUCHMETHOD: + return "No such (remote) method!"; + case DR_NOSUCHINSTANCE: + return "No such (remote) instance!"; + case DR_ITEMNOTFOUND: + return "Appropriate item not found!"; + case DR_VERSIONMISMATCH: + return "Some versions didn't match!"; + case DR_NOSHAREDMEMORY: + return "Out of shared memory!"; + case DR_EOF: + return "End of file!"; + case DR_SUSPENDED: + return "Object is suspended!"; + case DR_INCOMPLETE: + return "Operation incomplete!"; + case DR_NOCORE: + return "No core (loaded)!"; + default: + break; + } + + return "UNKNOWN RESULT CODE!"; +} + +int +direct_safe_dup( int fd ) +{ + int n = 0; + int fc[3]; + + while (fd >= 0 && fd <= 2) { + fc[n++] = fd; + fd = dup (fd); + } + + while (n) + close (fc[--n]); + + return fd; +} + +int +direct_try_open( const char *name1, const char *name2, int flags, bool error_msg ) +{ + int fd; + + fd = open (name1, flags); + if (fd >= 0) + return direct_safe_dup (fd); + + if (errno != ENOENT) { + if (error_msg) + D_PERROR( "Direct/Util: opening '%s' failed\n", name1 ); + return -1; + } + + fd = open (name2, flags); + if (fd >= 0) + return direct_safe_dup (fd); + + if (error_msg) { + if (errno == ENOENT) + D_PERROR( "Direct/Util: opening '%s' and '%s' failed\n", name1, name2 ); + else + D_PERROR( "Direct/Util: opening '%s' failed\n", name2 ); + } + + return -1; +} + +void +direct_trim( char **s ) +{ + int i; + int len = strlen( *s ); + + for (i = len-1; i >= 0; i--) + if ((*s)[i] <= ' ') + (*s)[i] = 0; + else + break; + + while (**s) + if (**s <= ' ') + (*s)++; + else + return; +} + +/* + * Utility function to initialize recursive mutexes. + */ +int +direct_util_recursive_pthread_mutex_init( pthread_mutex_t *mutex ) +{ + int ret; + pthread_mutexattr_t attr; + + pthread_mutexattr_init( &attr ); +#if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); +#endif + ret = pthread_mutex_init( mutex, &attr ); + if (ret) + D_PERROR( "Direct/Lock: Could not initialize recursive mutex!\n" ); + + pthread_mutexattr_destroy( &attr ); + + return ret; +} + +/* + * Utility function to initialize monotonic condition. + */ +int +direct_util_monotonic_pthread_cond_init( pthread_cond_t *cond ) +{ +#if defined(CLOCK_MONOTONIC) && !defined(DIRECT_BUILD_NO_PTHREAD_CONDATTR) + int ret; + pthread_condattr_t attr; + + struct timespec dummy; + pthread_condattr_init( &attr ); + + if(!no_monotonic_pthread_clock) { + if((syscall( __NR_clock_getres, CLOCK_MONOTONIC, &dummy ) == 0) && + (pthread_condattr_setclock( &attr, CLOCK_MONOTONIC ) == 0)) + ; + else + no_monotonic_pthread_clock = 1; + } + + ret = pthread_cond_init( cond, &attr ); + if (ret) + D_PERROR( "Direct/Lock: Could not initialize monotonic condition!\n" ); + + pthread_condattr_destroy( &attr ); + + return ret; +#else + pthread_cond_init( cond, NULL ); + + return 0; +#endif +} + +/* + * Utility function to calibrate timeout for monotonic condition. + */ +void +direct_util_get_monotonic_pthread_timeout( struct timespec *timeout, + int seconds, + int nano_seconds ) +{ + struct timeval now; + + if(no_monotonic_pthread_clock) + gettimeofday( &now, NULL ); + else + direct_monotonic_gettimeofday( &now ); + + timeout->tv_sec = now.tv_sec + seconds; + timeout->tv_nsec = (now.tv_usec * 1000) + nano_seconds; + + timeout->tv_sec += timeout->tv_nsec / 1000000000; + timeout->tv_nsec %= 1000000000; +} + +/* + * Encode/Decode Base-64. + */ +char* +direct_base64_encode( const void *data, int size ) +{ + static const char *enc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/="; + const unsigned char *src = (const unsigned char*)data; + char *ret; + char *buf; + + D_ASSERT( data != NULL ); + + buf = ret = D_MALLOC( (size + 2) / 3 * 4 + 1 ); + if (!ret) + return NULL; + + for (; size >= 3; size -= 3) { + buf[0] = enc[((src[0] & 0xfc) >> 2)]; + buf[1] = enc[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)]; + buf[2] = enc[((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)]; + buf[3] = enc[((src[2] & 0x3f))]; + buf += 4; + src += 3; + } + + if (size > 0) { + buf[0] = enc[(src[0] & 0xfc) >> 2]; + + if (size > 1) { + buf[1] = enc[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)]; + buf[2] = enc[((src[1] & 0x0f) << 2)]; + } else { + buf[1] = enc[(src[0] & 0x03) << 4]; + buf[2] = '='; + } + + buf[3] = '='; + buf += 4; + } + + *buf = '\0'; + + return ret; +} + +void* +direct_base64_decode( const char *string, int *ret_size ) +{ + unsigned char dec[256]; + unsigned char *ret; + unsigned char *buf; + int len; + int i, j; + + D_ASSERT( string != NULL ); + + len = strlen( string ); + buf = ret = D_MALLOC( len * 3 / 4 + 3 ); + if (!ret) + return NULL; + + /* generate decode table */ + for (i = 0; i < 255; i++) + dec[i] = 0x80; + for (i = 'A'; i <= 'Z'; i++) + dec[i] = 0 + (i - 'A'); + for (i = 'a'; i <= 'z'; i++) + dec[i] = 26 + (i - 'a'); + for (i = '0'; i <= '9'; i++) + dec[i] = 52 + (i - '0'); + dec['+'] = 62; + dec['/'] = 63; + dec['='] = 0; + + /* decode */ + for (j = 0; j < len; j += 4) { + unsigned char a[4], b[4]; + + for (i = 0; i < 4; i++) { + int c = string[i+j]; + a[i] = c; + b[i] = dec[c]; + } + + *buf++ = (b[0] << 2) | (b[1] >> 4); + *buf++ = (b[1] << 4) | (b[2] >> 2); + *buf++ = (b[2] << 6) | (b[3] ); + if (a[2] == '=' || a[3] == '=') + break; + } + + *buf = '\0'; + + if (ret_size) + *ret_size = buf - ret; + + return ret; +} + +/* + * Compute MD5 sum. + */ +static const u8 S[4][4] = { + { 7, 12, 17, 22 }, /* Round 1 */ + { 5, 9, 14, 20 }, /* Round 2 */ + { 4, 11, 16, 23 }, /* Round 3 */ + { 6, 10, 15, 21 } /* Round 4 */ +}; + +static const u32 T[64] = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, /* Round 1 */ + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, /* Round 2 */ + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, /* Round 3 */ + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, /* Round 4 */ + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, +}; + +static void +md5_hash( u32 ABCD[4], u32 X[16] ) +{ + u32 a = ABCD[3]; + u32 b = ABCD[2]; + u32 c = ABCD[1]; + u32 d = ABCD[0]; + int t; + int i; + +#ifdef WORDS_BIGENDIAN + for (i = 0; i < 16; i++) + X[i] = BSWAP32(X[i]); +#endif + + for (i = 0; i < 64; i++) { + t = S[i>>4][i&3]; + a += T[i]; + switch (i>>4) { + case 0: a += (d ^ (b&(c^d))) + X[ i &15]; break; + case 1: a += (c ^ (d&(c^b))) + X[(1+5*i)&15]; break; + case 2: a += (b^c^d) + X[(5+3*i)&15]; break; + case 3: a += (c^(b|~d)) + X[( 7*i)&15]; break; + } + a = b + ((a << t) | (a >> (32 - t))); + t = d; d = c; c = b; b = a; a = t; + } + + ABCD[0] += d; + ABCD[1] += c; + ABCD[2] += b; + ABCD[3] += a; +} + +void +direct_md5_sum( void *dst, const void *src, const int len ) +{ + u8 block[64]; + u32 ABCD[4]; + int i, j; + + D_ASSERT( dst != NULL ); + D_ASSERT( src != NULL ); + + ABCD[0] = 0x10325476; + ABCD[1] = 0x98badcfe; + ABCD[2] = 0xefcdab89; + ABCD[3] = 0x67452301; + + for (i = 0, j = 0; i < len; i++) { + block[j++] = ((const u8*)src)[i]; + if (j == 64) { + md5_hash( ABCD, (u32*)block ); + j = 0; + } + } + + block[j++] = 0x80; + memset( &block[j], 0, 64-j ); + + if (j > 56) { + md5_hash( ABCD, (u32*)block ); + memset( block, 0, 64 ); + } + + for (i = 0; i < 8; i++) + block[56+i] = ((u64)len << 3) >> (i << 3); + + md5_hash( ABCD, (u32*)block ); + + for (i = 0; i < 4; i++) +#ifdef WORDS_BIGENDIAN + ((u32*)dst)[i] = BSWAP32(ABCD[3-i]); +#else + ((u32*)dst)[i] = ABCD[3-i]; +#endif +} diff --git a/Source/DirectFB/lib/direct/util.h b/Source/DirectFB/lib/direct/util.h new file mode 100755 index 0000000..b93359e --- /dev/null +++ b/Source/DirectFB/lib/direct/util.h @@ -0,0 +1,330 @@ +/* + (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 __DIRECT__UTIL_H__ +#define __DIRECT__UTIL_H__ + +#include + +#ifdef _POSIX_PRIORITY_SCHEDULING +#include +#endif + +#include + +#include +#include + + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef SIGN +#define SIGN(x) (((x) < 0) ? -1 : (((x) > 0) ? 1 : 0)) +#endif + +#ifndef ABS +#define ABS(x) ((x) > 0 ? (x) : -(x)) +#endif + +#ifndef CLAMP +#define CLAMP(x,min,max) ((x) < (min) ? (min) : (x) > (max) ? (max) : (x)) +#endif + +#ifndef BSWAP16 +#define BSWAP16(x) (((u16)(x)>>8) | ((u16)(x)<<8)) +#endif + +#ifndef BSWAP32 +#define BSWAP32(x) ((((u32)(x)>>24) & 0x000000ff) | (((u32)(x)>> 8) & 0x0000ff00) | \ + (((u32)(x)<< 8) & 0x00ff0000) | (((u32)(x)<<24) & 0xff000000)) +#endif + + +#define D_FLAGS_SET(flags,f) do { (flags) |= (f); } while (0) +#define D_FLAGS_CLEAR(flags,f) do { (flags) &= ~(f); } while (0) +#define D_FLAGS_IS_SET(flags,f) (((flags) & (f)) != 0) +#define D_FLAGS_ARE_SET(flags,f) (((flags) & (f)) == (f)) +#define D_FLAGS_ARE_IN(flags,f) (((flags) & ~(f)) == 0) +#define D_FLAGS_INVALID(flags,f) (((flags) & ~(f)) != 0) + +#define D_FLAGS_ASSERT(flags,f) D_ASSERT( D_FLAGS_ARE_IN(flags,f) ) + +#define D_ARRAY_SIZE(array) ((int)(sizeof(array) / sizeof((array)[0]))) + +#define D_UTIL_SWAP(a,b) \ + do { \ + const typeof(a) x = (a); (a) = (b); (b) = x; \ + } while (0) + + +#if __GNUC__ >= 3 +#define D_CONST_FUNC __attribute__((const)) +#else +#define D_CONST_FUNC +#endif + + +#define D_BITn32(f) (((f) & 0x00000001) ? 0 : \ + ((f) & 0x00000002) ? 1 : \ + ((f) & 0x00000004) ? 2 : \ + ((f) & 0x00000008) ? 3 : \ + ((f) & 0x00000010) ? 4 : \ + ((f) & 0x00000020) ? 5 : \ + ((f) & 0x00000040) ? 6 : \ + ((f) & 0x00000080) ? 7 : \ + ((f) & 0x00000100) ? 8 : \ + ((f) & 0x00000200) ? 9 : \ + ((f) & 0x00000400) ? 10 : \ + ((f) & 0x00000800) ? 11 : \ + ((f) & 0x00001000) ? 12 : \ + ((f) & 0x00002000) ? 13 : \ + ((f) & 0x00004000) ? 14 : \ + ((f) & 0x00008000) ? 15 : \ + ((f) & 0x00010000) ? 16 : \ + ((f) & 0x00020000) ? 17 : \ + ((f) & 0x00040000) ? 18 : \ + ((f) & 0x00080000) ? 19 : \ + ((f) & 0x00100000) ? 20 : \ + ((f) & 0x00200000) ? 21 : \ + ((f) & 0x00400000) ? 22 : \ + ((f) & 0x00800000) ? 23 : \ + ((f) & 0x01000000) ? 24 : \ + ((f) & 0x02000000) ? 25 : \ + ((f) & 0x04000000) ? 26 : \ + ((f) & 0x08000000) ? 27 : \ + ((f) & 0x10000000) ? 28 : \ + ((f) & 0x20000000) ? 29 : \ + ((f) & 0x40000000) ? 30 : \ + ((f) & 0x80000000) ? 31 : -1) + + +/* + * portable sched_yield() implementation + */ +#ifdef _POSIX_PRIORITY_SCHEDULING +#define direct_sched_yield() sched_yield() +#else +#define direct_sched_yield() usleep(1) +#endif + +/* + * translates errno to DirectResult + */ +DirectResult errno2result( int erno ); + +const char *DirectResultString( DirectResult result ); + +/* + * duplicates a file descriptor as needed to ensure it's not stdin, stdout, or stderr + */ +int direct_safe_dup( int fd ); + +int direct_try_open( const char *name1, const char *name2, int flags, bool error_msg ); + +void direct_trim( char **s ); + +/* + * Set a string with a maximum size including the zero termination. + * + * This acts like a strncpy(d,s,n), but always terminates the string like snprintf(d,n,"%s",s). + * + * Returns dest or NULL if n is zero. + */ +static __inline__ char * +direct_snputs( char *dest, + const char *src, + size_t n ) +{ + char *start = dest; + + D_ASSERT( dest != NULL ); + D_ASSERT( src != NULL ); + + if (!n) + return NULL; + + for (; n>1 && *src; n--) + *dest++ = *src++; + + *dest = 0; + + return start; +} + +/* + * Encode/Decode Base-64 strings. + */ +char *direct_base64_encode( const void *data, int size ); +void *direct_base64_decode( const char *string, int *ret_size ); + +/* + * Compute MD5 sum (store 16-bytes long result in "dst"). + */ +void direct_md5_sum( void *dst, const void *src, const int len ); + +/* + * Slow implementation, but quite fast if only low bits are set. + */ +static __inline__ int +direct_util_count_bits( unsigned int mask ) +{ + register int ret = 0; + + while (mask) { + ret += mask & 1; + mask >>= 1; + } + + return ret; +} + +/* + * Generic alignment routine. + */ +static __inline__ int +direct_util_align( int value, + int alignment ) +{ + if (alignment > 1) { + int tail = value % alignment; + + if (tail) + value += alignment - tail; + } + + return value; +} + +/* + * Utility function to initialize recursive mutexes. + */ +int direct_util_recursive_pthread_mutex_init( pthread_mutex_t *mutex ); + +/* + * Utility function to calibrate timeout for monotonic condition. + */ +void direct_util_get_monotonic_pthread_timeout( struct timespec *timeout, + int seconds, + int nano_seconds ); + +/* + * Utility function to initialize monotonic condition. + */ +int direct_util_monotonic_pthread_cond_init( pthread_cond_t *cond ); + +/* floor and ceil implementation to get rid of libm */ + +/* + IEEE floor for computers that round to nearest or even. + + 'f' must be between -4194304 and 4194303. + + This floor operation is done by "(iround(f + .5) + iround(f - .5)) >> 1", + but uses some IEEE specific tricks for better speed. +*/ +static __inline__ int +D_IFLOOR(float f) +{ + int ai, bi; + double af, bf; + + af = (3 << 22) + 0.5 + (double)f; + bf = (3 << 22) + 0.5 - (double)f; + +#if defined(__GNUC__) && defined(__i386__) + /* + GCC generates an extra fstp/fld without this. + */ + __asm__ __volatile__ ("fstps %0" : "=m" (ai) : "t" (af) : "st"); + __asm__ __volatile__ ("fstps %0" : "=m" (bi) : "t" (bf) : "st"); +#else + { + union { int i; float f; } u; + u.f = af; ai = u.i; + u.f = bf; bi = u.i; + } +#endif + + return (ai - bi) >> 1; +} + + +/* + IEEE ceil for computers that round to nearest or even. + + 'f' must be between -4194304 and 4194303. + + This ceil operation is done by "(iround(f + .5) + iround(f - .5) + 1) >> 1", + but uses some IEEE specific tricks for better speed. +*/ +static __inline__ int +D_ICEIL(float f) +{ + int ai, bi; + double af, bf; + + af = (3 << 22) + 0.5 + (double)f; + bf = (3 << 22) + 0.5 - (double)f; + +#if defined(__GNUC__) && defined(__i386__) + /* + GCC generates an extra fstp/fld without this. + */ + __asm__ __volatile__ ("fstps %0" : "=m" (ai) : "t" (af) : "st"); + __asm__ __volatile__ ("fstps %0" : "=m" (bi) : "t" (bf) : "st"); +#else + { + union { int i; float f; } u; + u.f = af; ai = u.i; + u.f = bf; bi = u.i; + } +#endif + + return (ai - bi + 1) >> 1; +} + +static __inline__ int +direct_log2( int val ) +{ + register int ret = 0; + + while (val >> ++ret); + + if ((1 << --ret) < val) + ret++; + + return ret; +} + + +#endif 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 + diff --git a/Source/DirectFB/lib/voodoo/Makefile.am b/Source/DirectFB/lib/voodoo/Makefile.am new file mode 100755 index 0000000..bf3c143 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/Makefile.am @@ -0,0 +1,82 @@ +## Makefile.am for DirectFB/lib/voodoo + +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 = voodoo.pc + + +# If the old location isn't cleared, builds of external modules fail +install-exec-local: + rm -rf $(DESTDIR)$(INTERNALINCLUDEDIR)/voodoo + + +includedir = @INCLUDEDIR@/voodoo + +include_HEADERS = \ + build.h \ + client.h \ + conf.h \ + interface.h \ + manager.h \ + message.h \ + server.h \ + play.h \ + types.h + + +lib_LTLIBRARIES = libvoodoo.la + +libvoodoo_la_SOURCES = \ + client.c \ + conf.c \ + interface.c \ + internal.h \ + manager.c \ + play.c \ + server.c + +libvoodoo_la_LDFLAGS = \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ + -release $(LT_RELEASE) \ + $(DFB_LDFLAGS) + +libvoodoo_la_LIBADD = ../direct/libdirect.la + + +# +## and now rebuild the static version with the *correct* object files +# +if BUILD_STATIC + +clean-local: + rm -f libvoodoo_fixed.a + +all-local: libvoodoo_fixed.a + +libvoodoo_fixed.a: .libs/libvoodoo.a + rm -f libvoodoo_fixed.a + ${AR} cru libvoodoo_fixed.a `find . -name "*.o"` + ${RANLIB} libvoodoo_fixed.a + cp -pf libvoodoo_fixed.a .libs/libvoodoo.a + +.libs/libvoodoo.a: libvoodoo.la + +else + +clean-local: + +all-local: + +endif + + +include $(top_srcdir)/rules/nmfile.make diff --git a/Source/DirectFB/lib/voodoo/Makefile.in b/Source/DirectFB/lib/voodoo/Makefile.in new file mode 100755 index 0000000..4a4a5a2 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/Makefile.in @@ -0,0 +1,666 @@ +# 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)/voodoo.pc.in $(top_srcdir)/rules/nmfile.make +subdir = lib/voodoo +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 voodoo.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) +libvoodoo_la_DEPENDENCIES = ../direct/libdirect.la +am_libvoodoo_la_OBJECTS = client.lo conf.lo interface.lo play.lo manager.lo \ + server.lo +libvoodoo_la_OBJECTS = $(am_libvoodoo_la_OBJECTS) +libvoodoo_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libvoodoo_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 = $(libvoodoo_la_SOURCES) +DIST_SOURCES = $(libvoodoo_la_SOURCES) +pkgconfigDATA_INSTALL = $(INSTALL_DATA) +DATA = $(pkgconfig_DATA) +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@/voodoo +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=\"${RUNTIME_SYSROOT}@DATADIR@\" \ + -DMODULEDIR=\"${RUNTIME_SYSROOT}@MODULEDIR@\" + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = voodoo.pc +include_HEADERS = \ + build.h \ + client.h \ + conf.h \ + interface.h \ + manager.h \ + message.h \ + server.h \ + play.h \ + types.h + +lib_LTLIBRARIES = libvoodoo.la +libvoodoo_la_SOURCES = \ + client.c \ + conf.c \ + interface.c \ + internal.h \ + manager.c \ + play.c \ + server.c + +libvoodoo_la_LDFLAGS = \ + -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ + -release $(LT_RELEASE) \ + $(DFB_LDFLAGS) + +libvoodoo_la_LIBADD = ../direct/libdirect.la +@BUILD_SHARED_TRUE@@ENABLE_TRACE_TRUE@LIBTONM = $(LTLIBRARIES:.la=-$(LT_RELEASE).so.$(LT_BINARY)) +all: all-am + +.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/voodoo/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu lib/voodoo/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)/$@ +voodoo.pc: $(top_builddir)/config.status $(srcdir)/voodoo.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 +libvoodoo.la: $(libvoodoo_la_OBJECTS) $(libvoodoo_la_DEPENDENCIES) + $(libvoodoo_la_LINK) -rpath $(libdir) $(libvoodoo_la_OBJECTS) $(libvoodoo_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/client.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/manager.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/server.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/play.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 + +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) $(DATA) $(HEADERS) all-local +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgconfigdir)" "$(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." +@BUILD_SHARED_FALSE@install-data-local: +@ENABLE_TRACE_FALSE@install-data-local: +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ + 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-data-local install-includeHEADERS \ + install-pkgconfigDATA + +install-dvi: install-dvi-am + +install-exec-am: install-exec-local install-libLTLIBRARIES + +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 uninstall-libLTLIBRARIES \ + uninstall-pkgconfigDATA + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am all-local check check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ + 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-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 \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags 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)/voodoo + +# +# + +@BUILD_STATIC_TRUE@clean-local: +@BUILD_STATIC_TRUE@ rm -f libvoodoo_fixed.a + +@BUILD_STATIC_TRUE@all-local: libvoodoo_fixed.a + +@BUILD_STATIC_TRUE@libvoodoo_fixed.a: .libs/libvoodoo.a +@BUILD_STATIC_TRUE@ rm -f libvoodoo_fixed.a +@BUILD_STATIC_TRUE@ ${AR} cru libvoodoo_fixed.a `find . -name "*.o"` +@BUILD_STATIC_TRUE@ ${RANLIB} libvoodoo_fixed.a +@BUILD_STATIC_TRUE@ cp -pf libvoodoo_fixed.a .libs/libvoodoo.a + +@BUILD_STATIC_TRUE@.libs/libvoodoo.a: libvoodoo.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/voodoo/app.h b/Source/DirectFB/lib/voodoo/app.h new file mode 100755 index 0000000..163edc6 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/app.h @@ -0,0 +1,66 @@ +/* + (c) Copyright 2001-2010 The DirectFB Organization (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 __VOODOO__APP_H__ +#define __VOODOO__APP_H__ + +#include + + + +typedef enum { + VADESC_NONE = 0x00000000, + + VADESC_NAME = 0x00000001, + VADESC_TEXT = 0x00000002, + + VADESC_ALL = 0x00000003, +} VoodooAppDescriptionFlags; + + +#define VOODOO_APP_DESCRIPTION_NAME_LENGTH 128 +#define VOODOO_APP_DESCRIPTION_TEXT_LENGTH 1024 + +typedef struct { + u8 uuid[16]; + VoodooAppDescriptionFlags flags; + + char name[VOODOO_APP_DESCRIPTION_NAME_LENGTH]; + char text[VOODOO_APP_DESCRIPTION_TEXT_LENGTH]; +} VoodooAppDescription; + +typedef struct { + u8 uuid[16]; + + VoodooAppDescription app; + u8 player_uuid[16]; +} VoodooAppInstanceDescription; + + +#endif + diff --git a/Source/DirectFB/lib/voodoo/build.h.in b/Source/DirectFB/lib/voodoo/build.h.in new file mode 100755 index 0000000..c5553e2 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/build.h.in @@ -0,0 +1,34 @@ +/* + (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 __VOODOO__BUILD_H__ +#define __VOODOO__BUILD_H__ + +/* nothing yet */ + +#endif + diff --git a/Source/DirectFB/lib/voodoo/client.c b/Source/DirectFB/lib/voodoo/client.c new file mode 100755 index 0000000..66844e2 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/client.c @@ -0,0 +1,208 @@ +/* + (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 + +/**********************************************************************************************************************/ + +struct __V_VoodooClient { + DirectLink link; + + int refs; + + VoodooLink vl; + VoodooManager *manager; + + char *host; + int port; +}; + +static DirectLink *m_clients; // FIXME: add lock + +/**********************************************************************************************************************/ + +DirectResult +voodoo_client_create( const char *host, + int port, + VoodooClient **ret_client ) +{ + DirectResult ret; + VoodooClient *client; + VoodooPlayer *player; + int bc_num = 10; + int bc_wait = 4000; + char buf[100] = { 0 }; + const char *hostname = host; + bool raw = true; + + D_ASSERT( ret_client != NULL ); + + if (!port) + port = 2323; + + direct_list_foreach (client, m_clients) { + if (!strcmp( client->host, host ) && client->port == port) { + D_INFO( "Voodoo/Client: Reconnecting to '%s', increasing ref count of existing connection!\n", host ); + + client->refs++; + + *ret_client = client; + + return DR_OK; + } + } + + + ret = voodoo_player_create( NULL, &player ); + if (ret) { + D_DERROR( ret, "Voodoo/Client: Could not create the player!\n" ); + return ret; + } + + while (bc_num--) { + VoodooPlayInfo info; + + // FIXME: resolve first, not late in voodoo_link_init_connect + if (hostname && hostname[0]) { + ret = voodoo_player_lookup_by_address( player, hostname, &info ); + if (ret == DR_OK) { + if (info.flags & VPIF_LINK) + raw = false; + + break; + } + } + else { + ret = voodoo_player_lookup( player, NULL, &info, buf, sizeof(buf) ); + if (ret == DR_OK) { + if (info.flags & VPIF_LINK) + raw = false; + + hostname = buf; + + break; + } + } + + voodoo_player_broadcast( player ); + + direct_thread_sleep( bc_wait ); + + bc_wait += bc_wait; + } + + voodoo_player_destroy( player ); + + if (!hostname || !hostname[0]) { + D_ERROR( "Voodoo/Play: Did not find any other player!\n" ); + return DR_ITEMNOTFOUND; + } + + + /* Allocate client structure. */ + client = D_CALLOC( 1, sizeof(VoodooClient) ); + if (!client) + return D_OOM(); + + + /* Initialize client structure. */ + ret = voodoo_link_init_connect( &client->vl, hostname, port, + !voodoo_config->link_packet && (voodoo_config->link_raw || raw) ); + if (ret) { + D_DERROR( ret, "Voodoo/Client: Failed to initialize Voodoo Link!\n" ); + D_FREE( client ); + return ret; + } + + /* Create the manager. */ + ret = voodoo_manager_create( &client->vl, client, NULL, &client->manager ); + if (ret) { + client->vl.Close( &client->vl ); + D_FREE( client ); + return ret; + } + + client->refs = 1; + client->host = D_STRDUP( host ); + client->port = port; + + direct_list_prepend( &m_clients, &client->link ); + + /* Return the new client. */ + *ret_client = client; + + return DR_OK; +} + +DirectResult +voodoo_client_destroy( VoodooClient *client ) +{ + D_ASSERT( client != NULL ); + + D_INFO( "Voodoo/Client: Decreasing ref count of connection...\n" ); + + if (! --(client->refs)) { + voodoo_manager_destroy( client->manager ); + + //client->vl.Close( &client->vl ); + + direct_list_remove( &m_clients, &client->link ); + + D_FREE( client->host ); + D_FREE( client ); + } + + return DR_OK; +} + +VoodooManager * +voodoo_client_manager( const VoodooClient *client ) +{ + D_ASSERT( client != NULL ); + + return client->manager; +} + diff --git a/Source/DirectFB/lib/voodoo/client.h b/Source/DirectFB/lib/voodoo/client.h new file mode 100755 index 0000000..5905ef8 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/client.h @@ -0,0 +1,44 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 __VOODOO__CLIENT_H__ +#define __VOODOO__CLIENT_H__ + +#include + + +DirectResult voodoo_client_create ( const char *host, + int session, + VoodooClient **ret_client ); + +DirectResult voodoo_client_destroy( VoodooClient *client ); + + +VoodooManager *voodoo_client_manager( const VoodooClient *client ); + +#endif diff --git a/Source/DirectFB/lib/voodoo/compat.h b/Source/DirectFB/lib/voodoo/compat.h new file mode 100755 index 0000000..e7b5a75 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/compat.h @@ -0,0 +1,8 @@ +#include "mutex.h" +#include "waitqueue.h" + +#define direct_thread_sleep usleep +#define direct_snprintf snprintf +#define direct_sscanf sscanf +#define direct_getpid getpid + diff --git a/Source/DirectFB/lib/voodoo/conf.c b/Source/DirectFB/lib/voodoo/conf.c new file mode 100755 index 0000000..456643d --- /dev/null +++ b/Source/DirectFB/lib/voodoo/conf.c @@ -0,0 +1,253 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 VoodooConfig config = { + .compression_min = 1 +}; + +VoodooConfig *voodoo_config = &config; +const char *voodoo_config_usage = + "libvoodoo options:\n" + " player-name= Set player name\n" + " player-vendor= Set player vendor\n" + " player-model= Set player model\n" + " player-uuid= Set player uuid\n" + " proxy-memory-max= Set maximum amount of memory per connection\n" + " proxy-surface-max= Set maximum amount of memory per surface\n" + " [no-]server-fork Fork a new process for each connection (default: no)\n" + " server-single= Enable single client mode for super interface, e.g. IDirectFB\n" + " compression-min= Enable compression (if != 0) for packets with at least num bytes\n" + " [no-]link-raw Set link mode to 'raw'\n" + " [no-]link-packet Set link mode to 'packet'\n" + "\n"; + +/**********************************************************************************************************************/ + +DirectResult +voodoo_config_set( const char *name, const char *value ) +{ + if (strcmp (name, "player-name" ) == 0) { + if (value) { + direct_snputs( voodoo_config->play_info.name, value, VOODOO_PLAYER_NAME_LENGTH ); + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "player-vendor" ) == 0) { + if (value) { + direct_snputs( voodoo_config->play_info.vendor, value, VOODOO_PLAYER_VENDOR_LENGTH ); + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "player-model" ) == 0) { + if (value) { + direct_snputs( voodoo_config->play_info.model, value, VOODOO_PLAYER_MODEL_LENGTH ); + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "player-uuid" ) == 0) { + if (value) { + sscanf( value, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + (unsigned int*)&voodoo_config->play_info.uuid[0], (unsigned int*)&voodoo_config->play_info.uuid[1], (unsigned int*)&voodoo_config->play_info.uuid[2], (unsigned int*)&voodoo_config->play_info.uuid[3], (unsigned int*)&voodoo_config->play_info.uuid[4], + (unsigned int*)&voodoo_config->play_info.uuid[5], (unsigned int*)&voodoo_config->play_info.uuid[6], (unsigned int*)&voodoo_config->play_info.uuid[7], (unsigned int*)&voodoo_config->play_info.uuid[8], (unsigned int*)&voodoo_config->play_info.uuid[9], + (unsigned int*)&voodoo_config->play_info.uuid[10], (unsigned int*)&voodoo_config->play_info.uuid[11], (unsigned int*)&voodoo_config->play_info.uuid[12], (unsigned int*)&voodoo_config->play_info.uuid[13], (unsigned int*)&voodoo_config->play_info.uuid[14], + (unsigned int*)&voodoo_config->play_info.uuid[15] ); + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "proxy-memory-max" ) == 0) { + if (value) { + unsigned int max; + + if (sscanf( value, "%u", &max ) != 1) { + D_ERROR( "Voodoo/Config '%s': Invalid value specified!\n", name ); + return DR_INVARG; + } + + voodoo_config->memory_max = max * 1024; + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "proxy-surface-max" ) == 0) { + if (value) { + unsigned int max; + + if (sscanf( value, "%u", &max ) != 1) { + D_ERROR( "Voodoo/Config '%s': Invalid value specified!\n", name ); + return DR_INVARG; + } + + voodoo_config->surface_max = max * 1024; + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "proxy-layer-mask" ) == 0) { + if (value) { + unsigned int mask; + + if (sscanf( value, "%u", &mask ) != 1) { + D_ERROR( "Voodoo/Config '%s': Invalid value specified!\n", name ); + return DR_INVARG; + } + + voodoo_config->layer_mask = mask; + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "proxy-stacking-mask" ) == 0) { + if (value) { + unsigned int mask; + + if (sscanf( value, "%u", &mask ) != 1) { + D_ERROR( "Voodoo/Config '%s': Invalid value specified!\n", name ); + return DR_INVARG; + } + + voodoo_config->stacking_mask = mask; + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "proxy-resource-id" ) == 0) { + if (value) { + unsigned int resource_id; + + if (sscanf( value, "%u", &resource_id ) != 1) { + D_ERROR( "Voodoo/Config '%s': Invalid value specified!\n", name ); + return DR_INVARG; + } + + voodoo_config->resource_id = resource_id; + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "server-fork" ) == 0) { + voodoo_config->server_fork = true; + } else + if (strcmp (name, "no-server-fork" ) == 0) { + voodoo_config->server_fork = false; + } else + if (strcmp (name, "server-single" ) == 0) { + if (value) { + if (voodoo_config->server_single) + D_FREE( voodoo_config->server_single ); + + voodoo_config->server_single = D_STRDUP( value ); + if (!voodoo_config->server_single) + D_OOM(); + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "play-broadcast" ) == 0) { + if (value) { + if (voodoo_config->play_broadcast) + D_FREE( voodoo_config->play_broadcast ); + + voodoo_config->play_broadcast = D_STRDUP( value ); + if (!voodoo_config->play_broadcast) + D_OOM(); + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "compression-min" ) == 0) { + if (value) { + unsigned int min; + + if (sscanf( value, "%u", &min ) != 1) { + D_ERROR( "Voodoo/Config '%s': Invalid value specified!\n", name ); + return DR_INVARG; + } + + voodoo_config->compression_min = min; + } + else { + D_ERROR( "Voodoo/Config '%s': No value specified!\n", name ); + return DR_INVARG; + } + } else + if (strcmp (name, "link-raw" ) == 0) { + voodoo_config->link_raw = true; + } else + if (strcmp (name, "no-link-raw" ) == 0) { + voodoo_config->link_raw = false; + } else + if (strcmp (name, "link-packet" ) == 0) { + voodoo_config->link_packet = true; + } else + if (strcmp (name, "no-link-packet" ) == 0) { + voodoo_config->link_packet = false; + } else + if (direct_config_set( name, value )) + return DR_UNSUPPORTED; + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/conf.h b/Source/DirectFB/lib/voodoo/conf.h new file mode 100755 index 0000000..57dac9a --- /dev/null +++ b/Source/DirectFB/lib/voodoo/conf.h @@ -0,0 +1,58 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 __VOODOO__CONF_H__ +#define __VOODOO__CONF_H__ + +#include + + +struct __V_VoodooConfig { + VoodooPlayInfo play_info; + bool forward_nodes; + unsigned int memory_max; + unsigned int surface_max; + unsigned int layer_mask; + unsigned int stacking_mask; + unsigned int resource_id; + bool server_fork; + char *server_single; + char *play_broadcast; + unsigned int compression_min; + bool link_raw; + bool link_packet; +}; + +extern VoodooConfig *voodoo_config; + + +DirectResult voodoo_config_set( const char *name, const char *value ); + + +#endif + diff --git a/Source/DirectFB/lib/voodoo/connection.cpp b/Source/DirectFB/lib/voodoo/connection.cpp new file mode 100755 index 0000000..3bde3e1 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection.cpp @@ -0,0 +1,70 @@ +/* + (c) Copyright 2001-2011 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +extern "C" { +#include +#include +#include + +#include +} + +#include + + +D_DEBUG_DOMAIN( Voodoo_Connection, "Voodoo/Connection", "Voodoo Connection" ); + +/**********************************************************************************************************************/ + +VoodooConnection::VoodooConnection( VoodooManager *manager, + VoodooLink *link ) + : + magic(0), + manager(manager), + link(link) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnection::%s( %p )\n", __func__, this ); + + D_MAGIC_SET( this, VoodooConnection ); +} + +VoodooConnection::~VoodooConnection() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnection::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + link->Close( link ); + + D_MAGIC_CLEAR( this ); +} + diff --git a/Source/DirectFB/lib/voodoo/connection.h b/Source/DirectFB/lib/voodoo/connection.h new file mode 100755 index 0000000..0e6521b --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection.h @@ -0,0 +1,60 @@ +/* + (c) Copyright 2001-2011 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 __VOODOO__CONNECTION_H__ +#define __VOODOO__CONNECTION_H__ + +extern "C" { +#include +} + + +class VoodooConnection { +protected: + int magic; + + VoodooManager *manager; + VoodooLink *link; + +public: + VoodooConnection( VoodooManager *manager, + VoodooLink *link ); + + virtual ~VoodooConnection(); + + virtual void Start() = 0; + virtual void Stop() = 0; + + + virtual VoodooPacket *GetPacket( size_t length ) = 0; + virtual void PutPacket( VoodooPacket *packet, + bool flush ) = 0; +}; + + +#endif diff --git a/Source/DirectFB/lib/voodoo/connection_link.cpp b/Source/DirectFB/lib/voodoo/connection_link.cpp new file mode 100755 index 0000000..b0ae138 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection_link.cpp @@ -0,0 +1,331 @@ +/* + (c) Copyright 2001-2011 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +} + +#include +#include +#include + + +#include + + +//namespace Voodoo { + +D_DEBUG_DOMAIN( Voodoo_Connection, "Voodoo/Connection", "Voodoo Connection" ); +D_DEBUG_DOMAIN( Voodoo_Input, "Voodoo/Input", "Voodoo Input" ); +D_DEBUG_DOMAIN( Voodoo_Output, "Voodoo/Output", "Voodoo Output" ); + +/**********************************************************************************************************************/ + +VoodooConnectionLink::VoodooConnectionLink( VoodooManager *manager, + VoodooLink *link ) + : + VoodooConnection( manager, link ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p )\n", __func__, this ); + + input.start = 0; + input.last = 0; + input.end = 0; + input.max = 0; + + output.packets = NULL; + output.sending = NULL; + + /* Initialize all locks. */ + direct_mutex_init( &output.lock ); + + /* Initialize all wait conditions. */ + direct_waitqueue_init( &output.wait ); + + /* Set default buffer limit. */ + input.max = VOODOO_CONNECTION_LINK_INPUT_BUF_MAX; + + /* Allocate buffers. */ + size_t input_buffer_size = VOODOO_CONNECTION_LINK_INPUT_BUF_MAX + VOODOO_PACKET_MAX + sizeof(VoodooPacketHeader); + + input.buffer = (u8*) D_MALLOC( input_buffer_size ); + + D_INFO( "VoodooConnection/Link: Allocated "_ZU" kB input buffer at %p\n", input_buffer_size/1024, input.buffer ); + + direct_tls_register( &output.tls, OutputTLS_Destructor ); +} + +VoodooConnectionLink::~VoodooConnectionLink() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + /* Acquire locks and wake up waiters. */ + direct_mutex_lock( &output.lock ); + direct_waitqueue_broadcast( &output.wait ); + direct_mutex_unlock( &output.lock ); + + /* Destroy conditions. */ + direct_waitqueue_deinit( &output.wait ); + + /* Destroy locks. */ + direct_mutex_deinit( &output.lock ); + + /* Deallocate buffers. */ + D_FREE( input.buffer ); + + direct_tls_unregister( &output.tls ); +} + +/**********************************************************************************************************************/ + +VoodooPacket * +VoodooConnectionLink::GetPacket( size_t length ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p, length "_ZU" )\n", __func__, this, length ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + D_ASSERT( length >= (int) sizeof(VoodooMessageHeader) ); + D_ASSUME( length <= MAX_MSG_SIZE ); + + if (length > MAX_MSG_SIZE) { + D_WARN( _ZU" exceeds maximum message size of %d", length, MAX_MSG_SIZE ); + return NULL; + } + + size_t aligned = VOODOO_MSG_ALIGN( length ); + + + Packets *packets = (Packets*) direct_tls_get( output.tls ); + + if (!packets) { + packets = new Packets( this ); + + direct_tls_set( output.tls, packets ); + } + + VoodooPacket *packet = packets->active; + + if (packet) { + if (packet->append( aligned )) + return packet; + + Flush( packet ); + } + + packet = packets->Get(); + if (packet) { + if (packet->sending) { + direct_mutex_lock( &output.lock ); + + while (packet->sending) + direct_waitqueue_wait( &output.wait, &output.lock ); + + direct_mutex_unlock( &output.lock ); + } + packet->reset( aligned ); + } + + return packet; +} + +void +VoodooConnectionLink::PutPacket( VoodooPacket *packet, bool flush ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p, %sflush )\n", __func__, this, flush ? "" : "NO " ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + Packets *packets = (Packets*) direct_tls_get( output.tls ); + + D_ASSERT( packets != NULL ); + D_ASSERT( packet == packets->active ); + + if (flush) { + Flush( packet ); + + packets->active = NULL; + } +} + +void +VoodooConnectionLink::Stop() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + direct_mutex_lock( &output.lock ); + + while (output.packets) { + VoodooPacket *packet = (VoodooPacket*) output.packets; + + D_DEBUG_AT( Voodoo_Connection, " -> discarding output packet %p\n", packet ); + + D_ASSUME( packet->sending ); + + packet->sending = false; + + direct_list_remove( &output.packets, &packet->link ); + } + + direct_mutex_unlock( &output.lock ); + + direct_waitqueue_broadcast( &output.wait ); +} + +void +VoodooConnectionLink::Flush( VoodooPacket *packet ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p, packet %p )\n", __func__, this, packet ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + direct_mutex_lock( &output.lock ); + + D_ASSERT( !direct_list_contains_element_EXPENSIVE( output.packets, &packet->link ) ); + + D_ASSERT( !packet->sending ); + + packet->sending = true; + + direct_list_append( &output.packets, &packet->link ); + + direct_mutex_unlock( &output.lock ); + + link->WakeUp( link ); +} + +void +VoodooConnectionLink::OutputTLS_Destructor( void *ptr ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( ptr %p )\n", __func__, ptr ); + + Packets *packets = (Packets*) ptr; + + delete packets; + + D_DEBUG_AT( Voodoo_Connection, " -> OutputTLS_Destructor done\n" ); +} + +VoodooConnectionLink::Packets::Packets( VoodooConnectionLink* connection ) + : + magic(0), + connection(connection), + next(0), + num(0), + active(NULL) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::Packets::%s( %p )\n", __func__, this ); + + memset( packets, 0, sizeof(packets) ); + + D_MAGIC_SET( this, Packets ); +} + +VoodooConnectionLink::Packets::~Packets() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::Packets::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, Packets ); + + for (size_t i=0; i destroying output packet "_ZU" (%p)\n", i, packets[i] ); + + if (packets[i]->sending) { + direct_mutex_lock( &connection->output.lock ); + + while (packets[i]->sending) { + D_DEBUG_AT( Voodoo_Connection, " -> packet sending, waiting...\n" ); + + direct_waitqueue_wait( &connection->output.wait, &connection->output.lock ); + } + + direct_mutex_unlock( &connection->output.lock ); + } + + D_FREE( packets[i] ); + } + } +} + +VoodooPacket * +VoodooConnectionLink::Packets::Get() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::Packets::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, Packets ); + + VoodooPacket *packet; + + if (num < VOODOO_CONNECTION_PACKET_NUM_OUTPUT) { + packet = packets[num] = VoodooPacket::New( 0 ); + + D_DEBUG_AT( Voodoo_Connection, " -> new ["_ZU"] %p\n", num, packet ); + + num++; + } + else { + packet = packets[next]; + + next = (next+1) % VOODOO_CONNECTION_PACKET_NUM_OUTPUT; + + D_DEBUG_AT( Voodoo_Connection, " -> reusing %p\n", packet ); + } + + active = packet; + + return packet; +} + diff --git a/Source/DirectFB/lib/voodoo/connection_link.h b/Source/DirectFB/lib/voodoo/connection_link.h new file mode 100755 index 0000000..328151c --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection_link.h @@ -0,0 +1,106 @@ +/* + (c) Copyright 2001-2011 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 __VOODOO__CONNECTION_LINK_H__ +#define __VOODOO__CONNECTION_LINK_H__ + +#include + +extern "C" { +#include +} + +#define VOODOO_CONNECTION_PACKET_NUM_OUTPUT 2 +#define VOODOO_CONNECTION_LINK_INPUT_BUF_MAX ((VOODOO_PACKET_MAX + sizeof(VoodooPacketHeader)) * 1) + + +class VoodooConnectionLink : public VoodooConnection { +protected: + struct { + u8 *buffer; + size_t start; + size_t last; + size_t end; + size_t max; + } input; + + struct { + DirectMutex lock; + DirectWaitQueue wait; + DirectTLS tls; + DirectLink *packets; + + VoodooPacket *sending; + size_t sent; + } output; + +public: + VoodooConnectionLink( VoodooManager *manager, + VoodooLink *link ); + + virtual ~VoodooConnectionLink(); + + + virtual VoodooPacket *GetPacket( size_t length ); + virtual void PutPacket( VoodooPacket *packet, + bool flush ); + + virtual void Stop (); + + +private: + void Flush ( VoodooPacket *packet ); + + static void OutputTLS_Destructor( void *ptr ); + + +private: + friend class Packets; + + class Packets { + private: + int magic; + VoodooConnectionLink *connection; + VoodooPacket *packets[VOODOO_CONNECTION_PACKET_NUM_OUTPUT]; + size_t next; + size_t num; + + public: + VoodooPacket *active; + + public: + Packets( VoodooConnectionLink *connection ); + + ~Packets(); + + VoodooPacket *Get(); + }; +}; + + +#endif diff --git a/Source/DirectFB/lib/voodoo/connection_packet.cpp b/Source/DirectFB/lib/voodoo/connection_packet.cpp new file mode 100755 index 0000000..1e8a77f --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection_packet.cpp @@ -0,0 +1,368 @@ +/* + (c) Copyright 2001-2011 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include + +#include +#include +} + +#include +#include +#include + + +#include + + +//namespace Voodoo { + +D_DEBUG_DOMAIN( Voodoo_Connection, "Voodoo/Connection", "Voodoo Connection" ); +D_DEBUG_DOMAIN( Voodoo_Input, "Voodoo/Input", "Voodoo Input" ); +D_DEBUG_DOMAIN( Voodoo_Output, "Voodoo/Output", "Voodoo Output" ); + +/**********************************************************************************************************************/ + +VoodooConnectionPacket::VoodooConnectionPacket( VoodooManager *manager, + VoodooLink *link ) + : + VoodooConnectionLink( manager, link ), + stop( false ), + closed( false ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p )\n", __func__, this ); +} + +VoodooConnectionPacket::~VoodooConnectionPacket() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); +} + +void +VoodooConnectionPacket::Start() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + io = direct_thread_create( DTT_DEFAULT, io_loop_main, this, "Voodoo IO" ); +} + +void +VoodooConnectionPacket::Stop() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + direct_mutex_lock( &output.lock ); + + while (!closed && output.packets) { + D_DEBUG_AT( Voodoo_Connection, " -> waiting for output packets to be sent...\n" ); + + direct_waitqueue_wait( &output.wait, &output.lock ); + } + + direct_mutex_unlock( &output.lock ); + + stop = true; + + link->WakeUp( link ); + + /* Wait for manager threads exiting. */ + direct_thread_join( io ); + direct_thread_destroy( io ); + + VoodooConnectionLink::Stop(); +} + +/**********************************************************************************************************************/ + +void * +VoodooConnectionPacket::io_loop() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p )\n", __func__, this ); + + while (!stop) { + D_MAGIC_ASSERT( this, VoodooConnection ); + + if (input.start == input.max) { + input.start = 0; + input.end = 0; + input.last = 0; + input.max = VOODOO_CONNECTION_LINK_INPUT_BUF_MAX; + } + + if (!stop) { + DirectResult ret; + VoodooChunk chunks[2]; + VoodooChunk *chunk_read = NULL; + VoodooChunk *chunk_write = NULL; + size_t last = input.last; + VoodooPacket *packet = NULL; + + std::vector chunks_write; + std::vector chunks_read; + + if (!output.sending) { + direct_mutex_lock( &output.lock ); + + if (output.packets) { + VoodooPacket *packet = (VoodooPacket*) output.packets; + + D_ASSERT( packet->sending ); + + if (voodoo_config->compression_min && packet->size() >= voodoo_config->compression_min) { + output.sending = VoodooPacket::Compressed( packet ); + + if (output.sending->flags() & VPHF_COMPRESSED) { + D_DEBUG_AT( Voodoo_Output, " -> Compressed %u to %u bytes... (packet %p)\n", + output.sending->uncompressed(), output.sending->size(), packet ); + + output.sending->sending = true; + + packet->sending = false; + + direct_list_remove( &output.packets, &packet->link ); + + direct_waitqueue_broadcast( &output.wait ); + } + } + else + output.sending = packet; + + output.sent = 0; + } + + direct_mutex_unlock( &output.lock ); + } + + if (output.sending) { + packet = output.sending; + + D_ASSERT( packet->sending ); + + chunk_write = &chunks[1]; + + chunk_write->ptr = (char*) packet->data_header() + output.sent; + chunk_write->length = VOODOO_MSG_ALIGN(packet->size() + sizeof(VoodooPacketHeader)) - output.sent; + chunk_write->done = 0; + + chunks_write.push_back( chunks[1] ); + + chunk_write = chunks_write.data(); + } + + if (input.end < input.max && manager->DispatchReady()) { + chunk_read = &chunks[0]; + + chunk_read->ptr = input.buffer + input.end; + chunk_read->length = input.max - input.end; + chunk_read->done = 0; + + chunks_read.push_back( chunks[0] ); + + chunk_read = chunks_read.data(); + } + + + ret = link->SendReceive( link, + chunks_write.data(), chunks_write.size(), + chunks_read.data(), chunks_read.size() ); + switch (ret) { + case DR_OK: + if (chunk_write && chunk_write->done) { + D_DEBUG_AT( Voodoo_Output, " -> Sent "_ZD"/"_ZD" bytes... (packet %p)\n", chunk_write->done, chunk_write->length, packet ); + + output.sent += chunk_write->done; + + if (output.sent == VOODOO_MSG_ALIGN(packet->size() + sizeof(VoodooPacketHeader))) { + output.sending = NULL; + + if (packet->flags() & VPHF_COMPRESSED) { + packet->sending = false; + + D_FREE( packet ); + } + else { + direct_mutex_lock( &output.lock ); + + packet->sending = false; + + direct_list_remove( &output.packets, &packet->link ); + + direct_mutex_unlock( &output.lock ); + + direct_waitqueue_broadcast( &output.wait ); + } + } + } + break; + + case DR_TIMEOUT: + //D_DEBUG_AT( Voodoo_Connection, " -> timeout\n" ); + break; + + case DR_INTERRUPTED: + D_DEBUG_AT( Voodoo_Connection, " -> interrupted\n" ); + break; + + default: + if (ret == DR_IO) + D_DEBUG_AT( Voodoo_Connection, " -> Connection closed!\n" ); + else + { + D_DERROR( ret, "Voodoo/ConnectionPacket: Could not receive data!\n" ); + exit(0); + } + + goto disconnect; + } + + + if (chunk_read && chunk_read->done) { + D_DEBUG_AT( Voodoo_Input, " -> Received "_ZD" bytes...\n", chunk_read->done ); + + input.end += (size_t) chunk_read->done; + + do { + VoodooPacketHeader *header; + size_t aligned; + + /* Get the packet header. */ + header = (VoodooPacketHeader *)(input.buffer + last); + aligned = VOODOO_MSG_ALIGN( header->size ); + + D_DEBUG_AT( Voodoo_Input, " -> Next packet has %u ("_ZU") -> %u bytes (flags 0x%04x)...\n", + header->size, aligned, header->uncompressed, header->flags ); + + if (input.end - last >= sizeof(VoodooPacketHeader)) { + if (header->uncompressed < (int) sizeof(VoodooMessageHeader)) { + D_DERROR( ret, "Voodoo/ConnectionPacket: Data error, uncompressed %d < min %zu!\n", header->uncompressed, sizeof(VoodooPacketHeader) ); + + goto disconnect; + } + + if (header->uncompressed > VOODOO_PACKET_MAX) { + D_DERROR( ret, "Voodoo/ConnectionPacket: Data error, uncompressed %d > max %d!\n", header->uncompressed, VOODOO_PACKET_MAX ); + + goto disconnect; + } + } + + if (sizeof(VoodooPacketHeader) + aligned > input.end - last) { + D_DEBUG_AT( Voodoo_Input, " -> ...fetching tail of message.\n" ); + + /* Extend the buffer if the message doesn't fit into the default boundary. */ + if (sizeof(VoodooPacketHeader) + aligned > input.max - last) + input.max = last + sizeof(VoodooPacketHeader) + aligned; + + break; + } + + last += sizeof(VoodooPacketHeader) + aligned; + } while (last < input.end); + + if (last != input.last) { + input.last = last; + + D_DEBUG_AT( Voodoo_Input, " { START "_ZD", LAST "_ZD", END "_ZD", MAX "_ZD" }\n", + input.start, input.last, input.end, input.max ); + + while (input.start < input.last) { + /* Get the packet header. */ + VoodooPacketHeader *header = (VoodooPacketHeader *)(input.buffer + input.start); + + VoodooPacket *p; + + D_ASSERT( header->uncompressed <= VOODOO_PACKET_MAX ); + + if (header->flags & VPHF_COMPRESSED) { + size_t uncompressed = direct_fastlz_decompress( header + 1, header->size, tmp, header->uncompressed ); + + D_DEBUG_AT( Voodoo_Input, " -> Uncompressed "_ZU" bytes (%u compressed)\n", uncompressed, header->size ); + + (void) uncompressed; + + D_ASSERT( uncompressed == header->uncompressed ); + + // FIXME: don't copy, but read into packet directly, maybe call manager->GetPacket() at the top of this loop + p = VoodooPacket::Copy( header->uncompressed, VPHF_NONE, + header->uncompressed, tmp ); + } + else { + // FIXME: don't copy, but read into packet directly, maybe call manager->GetPacket() at the top of this loop + p = VoodooPacket::Copy( header->uncompressed, VPHF_NONE, + header->uncompressed, header + 1 ); + } + + manager->DispatchPacket( p ); + + input.start += VOODOO_MSG_ALIGN(header->size) + sizeof(VoodooPacketHeader); + } + } + } + } + } + + return NULL; + + +disconnect: + closed = true; + + manager->handle_disconnect(); + + return NULL; +} + +/**********************************************************************************************************************/ + +void * +VoodooConnectionPacket::io_loop_main( DirectThread *thread, void *arg ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p, thread %p )\n", __func__, arg, thread ); + + VoodooConnectionPacket *connection = (VoodooConnectionPacket*) arg; + + return connection->io_loop(); +} + diff --git a/Source/DirectFB/lib/voodoo/connection_packet.h b/Source/DirectFB/lib/voodoo/connection_packet.h new file mode 100755 index 0000000..ec53e27 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection_packet.h @@ -0,0 +1,61 @@ +/* + (c) Copyright 2001-2011 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 __VOODOO__CONNECTION_PACKET_H__ +#define __VOODOO__CONNECTION_PACKET_H__ + +#include + + +class VoodooConnectionPacket : public VoodooConnectionLink { +private: + char tmp[VOODOO_PACKET_MAX]; + DirectThread *io; + bool stop; + bool closed; + +public: + VoodooConnectionPacket( VoodooManager *manager, + VoodooLink *link ); + + virtual ~VoodooConnectionPacket(); + + virtual void Start(); + virtual void Stop(); + + +private: + void *io_loop(); + + + static void *io_loop_main( DirectThread *thread, + void *arg ); +}; + + +#endif diff --git a/Source/DirectFB/lib/voodoo/connection_packet_old.cpp b/Source/DirectFB/lib/voodoo/connection_packet_old.cpp new file mode 100755 index 0000000..0efec4d --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection_packet_old.cpp @@ -0,0 +1,433 @@ +/* + (c) Copyright 2001-2011 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +#include +#include +#include +#include +#include + +extern "C" { +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +} + +#include +#include +#include + + +#include + + +#define IN_BUF_MAX (640 * 1024) +#define OUT_BUF_MAX (640 * 1024) + + +//namespace Voodoo { + +D_DEBUG_DOMAIN( Voodoo_Connection, "Voodoo/Connection", "Voodoo Connection" ); +D_DEBUG_DOMAIN( Voodoo_Input, "Voodoo/Input", "Voodoo Input" ); +D_DEBUG_DOMAIN( Voodoo_Output, "Voodoo/Output", "Voodoo Output" ); + +/**********************************************************************************************************************/ + +VoodooConnectionPacket::VoodooConnectionPacket( VoodooManager *manager, + VoodooLink *link ) + : + VoodooConnection( manager, link ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p )\n", __func__, this ); + + input.start = 0; + input.last = 0; + input.end = 0; + input.max = 0; + + output.start = 0; + output.end = 0; + + /* Initialize all locks. */ + direct_recursive_mutex_init( &input.lock ); + direct_recursive_mutex_init( &output.lock ); + + /* Initialize all wait conditions. */ + direct_waitqueue_init( &input.wait ); + direct_waitqueue_init( &output.wait ); + + /* Set default buffer limit. */ + input.max = IN_BUF_MAX; + + /* Allocate buffers. */ + input.buffer = (u8*) D_MALLOC( IN_BUF_MAX + VOODOO_PACKET_MAX + sizeof(VoodooPacketHeader) ); + output.buffer = (u8*) D_MALLOC( OUT_BUF_MAX ); + + io = direct_thread_create( DTT_DEFAULT, io_loop_main, this, "Voodoo IO" ); +} + +VoodooConnectionPacket::~VoodooConnectionPacket() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + link->WakeUp( link ); + + /* Acquire locks and wake up waiters. */ + direct_mutex_lock( &input.lock ); + direct_waitqueue_broadcast( &input.wait ); + direct_mutex_unlock( &input.lock ); + + direct_mutex_lock( &output.lock ); + direct_waitqueue_broadcast( &output.wait ); + direct_mutex_unlock( &output.lock ); + + /* Wait for manager threads exiting. */ + direct_thread_join( io ); + direct_thread_destroy( io ); + + /* Destroy conditions. */ + direct_waitqueue_deinit( &input.wait ); + direct_waitqueue_deinit( &output.wait ); + + /* Destroy locks. */ + direct_mutex_deinit( &input.lock ); + direct_mutex_deinit( &output.lock ); + + /* Deallocate buffers. */ + D_FREE( output.buffer ); + D_FREE( input.buffer ); +} + +/**********************************************************************************************************************/ + +void * +VoodooConnectionPacket::io_loop_main( DirectThread *thread, void *arg ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p, thread %p )\n", __func__, arg, thread ); + + VoodooConnectionPacket *connection = (VoodooConnectionPacket*) arg; + + return connection->io_loop(); +} + +void * +VoodooConnectionPacket::io_loop() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p )\n", __func__, this ); + + while (!manager->is_quit) { + D_MAGIC_ASSERT( this, VoodooConnection ); + +// direct_mutex_lock( &manager->input.lock ); + + if (input.start == input.max) { + input.start = 0; + input.end = 0; + input.last = 0; + input.max = IN_BUF_MAX; + } + +// direct_mutex_unlock( &input.lock ); + + if (!manager->is_quit) { + DirectResult ret; + VoodooChunk chunks[2]; + VoodooChunk *chunk_read = NULL; + VoodooChunk *chunk_write = NULL; + size_t last = input.last; + + std::vector chunks_write; + std::vector chunks_read; + + direct_mutex_lock( &output.lock ); + + if (input.end < input.max) { + chunk_read = &chunks[0]; + + chunk_read->ptr = input.buffer + input.end; + chunk_read->length = input.max - input.end; + chunk_read->done = 0; + + chunks_read.push_back( chunks[0] ); + + chunk_read = chunks_read.data(); + } + + if (output.end > output.start) { + chunk_write = &chunks[1]; + + chunk_write->ptr = output.buffer + output.start; + chunk_write->length = output.end - output.start; + chunk_write->done = 0; + + if (chunk_write->length > 65536) { + chunk_write->length = 65536; + } + + chunks_write.push_back( chunks[1] ); + + chunk_write = chunks_write.data(); + } + + if (!chunk_write) + direct_mutex_unlock( &output.lock ); + +#if 0 + if (chunk_write) { + char buf[chunk_write->length*4/3]; + + size_t comp = direct_fastlz_compress( chunk_write->ptr, chunk_write->length, buf ); + + D_DEBUG_AT( Voodoo_Output, " -> Compressed "_ZU"%% ("_ZU" -> "_ZU")\n", + comp * 100 / chunk_write->length, chunk_write->length, comp ); + } +#endif + + ret = link->SendReceive( link, + chunks_write.data(), chunks_write.size(), + chunks_read.data(), chunks_read.size() ); + switch (ret) { + case DR_OK: + if (chunk_write && chunk_write->done) { + D_DEBUG_AT( Voodoo_Output, " -> Sent "_ZD"/"_ZD" bytes...\n", chunk_write->done, chunk_write->length ); + + output.start += (size_t) chunk_write->done; + + //direct_mutex_lock( &output.lock ); + + if (output.start == output.end) { + output.start = output.end = 0; + + direct_waitqueue_broadcast( &output.wait ); + } + + //direct_mutex_unlock( &output.lock ); + } + break; + + case DR_TIMEOUT: + //D_WARN("timeout"); + break; + + case DR_INTERRUPTED: + //D_WARN("interrupted"); + break; + + default: + D_DERROR( ret, "Voodoo/Manager: Could not receive data!\n" ); + manager->handle_disconnect(); + break; + } + + if (chunk_write) + direct_mutex_unlock( &output.lock ); + + + + if (chunk_read && chunk_read->done) { + D_DEBUG_AT( Voodoo_Input, " -> Received "_ZD" bytes...\n", chunk_read->done ); + + input.end += (size_t) chunk_read->done; + + do { + VoodooPacketHeader *header; + + /* Get the packet header. */ + header = (VoodooPacketHeader *)(input.buffer + last); + + D_DEBUG_AT( Voodoo_Input, " -> Next packet has %u bytes...\n", header->size ); + + D_ASSERT( header->size >= (int) sizeof(VoodooMessageHeader) ); + D_ASSERT( header->size <= MAX_MSG_SIZE ); + + if (sizeof(VoodooPacketHeader) + header->size > input.end - last) { + D_DEBUG_AT( Voodoo_Input, " -> ...fetching tail of message.\n" ); + + /* Extend the buffer if the message doesn't fit into the default boundary. */ + if (sizeof(VoodooPacketHeader) + header->size > input.max - last) { + D_ASSERT( input.max == IN_BUF_MAX ); + + + input.max = last + sizeof(VoodooPacketHeader) + header->size; + } + + break; + } + + last += sizeof(VoodooPacketHeader) + header->size; + } while (last < input.end); + + if (last != input.last) { + + input.last = last; + + D_DEBUG_AT( Voodoo_Input, " { START "_ZD", LAST "_ZD", END "_ZD", MAX "_ZD" }\n", + input.start, input.last, input.end, input.max ); + + while (input.start < input.last) { + /* Get the packet header. */ + VoodooPacketHeader *header = (VoodooPacketHeader *)(input.buffer + input.start); + + ProcessMessages( (VoodooMessageHeader *)(header + 1), header->uncompressed ); + + input.start += header->size + sizeof(VoodooPacketHeader); + } + } + } + } + } + + return NULL; +} + +/**********************************************************************************************************************/ + +DirectResult +VoodooConnectionPacket::lock_output( int length, + void **ret_ptr ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p, length %d )\n", __func__, this, length ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + D_ASSERT( length >= (int) sizeof(VoodooMessageHeader) ); + D_ASSUME( length <= MAX_MSG_SIZE ); + D_ASSERT( ret_ptr != NULL ); + + if (length > MAX_MSG_SIZE) { + D_WARN( "%d exceeds maximum message size of %d", length, MAX_MSG_SIZE ); + return DR_LIMITEXCEEDED; + } + + int aligned = VOODOO_MSG_ALIGN( length ); + + direct_mutex_lock( &output.lock ); + + while (output.end + aligned > OUT_BUF_MAX) { + link->WakeUp( link ); + + direct_waitqueue_wait( &output.wait, &output.lock ); + + if (manager->is_quit) { + direct_mutex_lock( &output.lock ); + return DR_DESTROYED; + } + } + + *ret_ptr = output.buffer + output.end; + + D_DEBUG_AT( Voodoo_Output, " -> offset "_ZD", aligned length %d\n", output.end, aligned ); + + output.end += aligned; + + return DR_OK; +} + +DirectResult +VoodooConnectionPacket::unlock_output( bool flush ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p, %sflush )\n", __func__, this, flush ? "" : "NO " ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + direct_mutex_unlock( &output.lock ); + + if (flush) + link->WakeUp( link ); + + return DR_OK; +} + +VoodooPacket * +VoodooConnectionPacket::GetPacket( size_t length ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p, length "_ZU" )\n", __func__, this, length ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + D_ASSERT( length >= (int) sizeof(VoodooMessageHeader) ); + D_ASSUME( length <= MAX_MSG_SIZE ); + + if (length > MAX_MSG_SIZE) { + D_WARN( _ZU" exceeds maximum message size of %d", length, MAX_MSG_SIZE ); + return NULL; + } + + int aligned = sizeof(VoodooPacketHeader) + VOODOO_MSG_ALIGN( length ); + + direct_mutex_lock( &output.lock ); + + while (output.end + aligned > OUT_BUF_MAX) { + link->WakeUp( link ); + + direct_waitqueue_wait( &output.wait, &output.lock ); + + if (manager->is_quit) { + direct_mutex_lock( &output.lock ); + return NULL; + } + } + + D_DEBUG_AT( Voodoo_Output, " -> offset "_ZD", aligned length %d\n", output.end, aligned ); + + output.end += aligned; + + return VoodooPacket::New( output.buffer + output.end - aligned, aligned - sizeof(VoodooPacketHeader) ); +} + +void +VoodooConnectionPacket::PutPacket( VoodooPacket *packet, bool flush ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p, %sflush )\n", __func__, this, flush ? "" : "NO " ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + direct_mutex_unlock( &output.lock ); + + if (flush) + link->WakeUp( link ); + +// delete packet; +} + diff --git a/Source/DirectFB/lib/voodoo/connection_packet_old.h b/Source/DirectFB/lib/voodoo/connection_packet_old.h new file mode 100755 index 0000000..cfb10bf --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection_packet_old.h @@ -0,0 +1,87 @@ +/* + (c) Copyright 2001-2011 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 __VOODOO__CONNECTION_PACKET_H__ +#define __VOODOO__CONNECTION_PACKET_H__ + +#include + +extern "C" { +#include +} + + +class VoodooConnectionPacket : public VoodooConnection { +private: + DirectThread *io; + + struct { + DirectMutex lock; + DirectWaitQueue wait; + u8 *buffer; + size_t start; + size_t last; + size_t end; + size_t max; + } input; + + struct { + DirectMutex lock; + DirectWaitQueue wait; + u8 *buffer; + size_t start; + size_t end; + } output; + +public: + VoodooConnectionPacket( VoodooManager *manager, + VoodooLink *link ); + + virtual ~VoodooConnectionPacket(); + + + virtual DirectResult lock_output ( int length, + void **ret_ptr ); + + virtual DirectResult unlock_output( bool flush ); + + + virtual VoodooPacket *GetPacket( size_t length ); + virtual void PutPacket( VoodooPacket *packet, + bool flush ); + + +private: + static void *io_loop_main ( DirectThread *thread, + void *arg ); + + void *io_loop (); +}; + + +#endif diff --git a/Source/DirectFB/lib/voodoo/connection_raw.cpp b/Source/DirectFB/lib/voodoo/connection_raw.cpp new file mode 100755 index 0000000..c6ba56a --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection_raw.cpp @@ -0,0 +1,341 @@ +/* + (c) Copyright 2001-2011 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +#ifdef VOODOO_CONNECTION_RAW_DUMP +#include +#include +#include +#include +#include + +#include +#include +#endif + +extern "C" { +#include +#include +#include +#include +#include +#include + +#include +#include +#include +} + +#include +#include +#include + + +#include + + +//namespace Voodoo { + +D_DEBUG_DOMAIN( Voodoo_Connection, "Voodoo/Connection", "Voodoo Connection" ); +D_DEBUG_DOMAIN( Voodoo_Input, "Voodoo/Input", "Voodoo Input" ); +D_DEBUG_DOMAIN( Voodoo_Output, "Voodoo/Output", "Voodoo Output" ); + +/**********************************************************************************************************************/ + +VoodooConnectionRaw::VoodooConnectionRaw( VoodooManager *manager, + VoodooLink *link ) + : + VoodooConnectionLink( manager, link ), + stop( false ), + closed( false ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this ); + + if (link->code) { + input.end = 4; + + memcpy( input.buffer, &link->code, sizeof(u32) ); + } +} + +VoodooConnectionRaw::~VoodooConnectionRaw() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); +} + +void +VoodooConnectionRaw::Start() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + io = direct_thread_create( DTT_DEFAULT, io_loop_main, this, "Voodoo IO" ); +} + +void +VoodooConnectionRaw::Stop() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooConnection ); + + direct_mutex_lock( &output.lock ); + + while (!closed && output.packets) { + D_DEBUG_AT( Voodoo_Connection, " -> waiting for output packets to be sent...\n" ); + + direct_waitqueue_wait( &output.wait, &output.lock ); + } + + direct_mutex_unlock( &output.lock ); + + stop = true; + + link->WakeUp( link ); + + /* Wait for manager threads exiting. */ + direct_thread_join( io ); + direct_thread_destroy( io ); + + VoodooConnectionLink::Stop(); +} + +/**********************************************************************************************************************/ + +void * +VoodooConnectionRaw::io_loop() +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p )\n", __func__, this ); + +#ifdef VOODOO_CONNECTION_RAW_DUMP + int dump_fd = open("voodoo_write.raw", O_TRUNC|O_CREAT|O_WRONLY, 0660 ); + int dump_read_fd = open("voodoo_read.raw", O_TRUNC|O_CREAT|O_WRONLY, 0660 ); +#endif + + while (!stop) { + D_MAGIC_ASSERT( this, VoodooConnection ); + + if (input.start == input.max) { + input.start = 0; + input.end = 0; + input.last = 0; + input.max = VOODOO_CONNECTION_LINK_INPUT_BUF_MAX; + } + + if (!stop) { + DirectResult ret; + VoodooChunk chunks[2]; + VoodooChunk *chunk_read = NULL; + VoodooChunk *chunk_write = NULL; + size_t last = input.last; + VoodooPacket *packet = NULL; + + std::vector chunks_write; + std::vector chunks_read; + + if (!output.sending) { + direct_mutex_lock( &output.lock ); + + if (output.packets) { + VoodooPacket *packet = (VoodooPacket*) output.packets; + + D_ASSERT( packet->sending ); + + output.sending = packet; + output.sent = 0; + } + + direct_mutex_unlock( &output.lock ); + } + + if (output.sending) { + packet = output.sending; + + D_ASSERT( packet->sending ); + + chunk_write = &chunks[1]; + + chunk_write->ptr = (char*) packet->data_start() + output.sent; + chunk_write->length = VOODOO_MSG_ALIGN(packet->size()) - output.sent; + chunk_write->done = 0; + + chunks_write.push_back( chunks[1] ); + + chunk_write = chunks_write.data(); + } + + if (input.end < input.max && manager->DispatchReady()) { + chunk_read = &chunks[0]; + + chunk_read->ptr = input.buffer + input.end; + chunk_read->length = input.max - input.end; + chunk_read->done = 0; + + chunks_read.push_back( chunks[0] ); + + chunk_read = chunks_read.data(); + } + + + ret = link->SendReceive( link, + chunks_write.data(), chunks_write.size(), + chunks_read.data(), chunks_read.size() ); + switch (ret) { + case DR_OK: + if (chunk_write && chunk_write->done) { + D_DEBUG_AT( Voodoo_Output, " -> Sent "_ZD"/"_ZD" bytes...\n", chunk_write->done, chunk_write->length ); + +#ifdef VOODOO_CONNECTION_RAW_DUMP + write( dump_fd, chunk_write->ptr, chunk_write->done ); +#endif + + output.sent += chunk_write->done; + + if (output.sent == VOODOO_MSG_ALIGN(packet->size())) { + output.sending = NULL; + + direct_mutex_lock( &output.lock ); + + packet->sending = false; + + direct_list_remove( &output.packets, &packet->link ); + + direct_mutex_unlock( &output.lock ); + + direct_waitqueue_broadcast( &output.wait ); + } + } + break; + + case DR_TIMEOUT: + //D_DEBUG_AT( Voodoo_Connection, " -> timeout\n" ); + break; + + case DR_INTERRUPTED: + D_DEBUG_AT( Voodoo_Connection, " -> interrupted\n" ); + break; + + default: + if (ret == DR_IO) + D_DEBUG_AT( Voodoo_Connection, " -> Connection closed!\n" ); + else + { + D_DERROR( ret, "Voodoo/ConnectionRaw: Could not receive data!\n" ); + exit(0); + } + + closed = true; + + manager->handle_disconnect(); + + return NULL; + } + + + if (chunk_read && chunk_read->done) { + D_DEBUG_AT( Voodoo_Input, " -> Received "_ZD" bytes...\n", chunk_read->done ); + +#ifdef VOODOO_CONNECTION_RAW_DUMP + write( dump_read_fd, chunk_read->ptr, chunk_read->done ); +#endif + + input.end += (size_t) chunk_read->done; + + do { + VoodooMessageHeader *header; + size_t aligned; + + D_DEBUG_AT( Voodoo_Input, " { LAST "_ZD", INPUT LAST "_ZD" }\n", last, input.last ); + + if (input.end - last < 4) { + D_DEBUG_AT( Voodoo_Input, " -> ...only "_ZU" bytes left\n", input.end - last ); + break; + } + + /* Get the message header. */ + header = (VoodooMessageHeader *)(input.buffer + last); + aligned = VOODOO_MSG_ALIGN( header->size ); + + D_DEBUG_AT( Voodoo_Input, " -> Next message has %d ("_ZD") bytes and is of type %d...\n", + header->size, aligned, header->type ); + + D_ASSERT( header->size >= (int) sizeof(VoodooMessageHeader) ); + D_ASSERT( header->size <= MAX_MSG_SIZE ); + + if (aligned > input.end - last) { + D_DEBUG_AT( Voodoo_Input, " -> ...fetching tail of message.\n" ); + + /* Extend the buffer if the message doesn't fit into the default boundary. */ + if (aligned > input.max - last) + input.max = last + aligned; + + break; + } + + last += aligned; + } while (last < input.end); + + if (last != input.last) { + input.last = last; + + D_DEBUG_AT( Voodoo_Input, " { START "_ZD", LAST "_ZD", END "_ZD", MAX "_ZD" }\n", + input.start, input.last, input.end, input.max ); + + // FIXME: don't copy, but read into packet directly, maybe call manager->GetPacket() at the top of this loop + VoodooPacket *p = VoodooPacket::Copy( input.last - input.start, VPHF_NONE, + input.last - input.start, input.buffer + input.start ); + + manager->DispatchPacket( p ); + + input.start = input.last; + } + } + } + } + + return NULL; +} + +/**********************************************************************************************************************/ + +void * +VoodooConnectionRaw::io_loop_main( DirectThread *thread, void *arg ) +{ + D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionRaw::%s( %p, thread %p )\n", __func__, arg, thread ); + + VoodooConnectionRaw *connection = (VoodooConnectionRaw*) arg; + + return connection->io_loop(); +} + diff --git a/Source/DirectFB/lib/voodoo/connection_raw.h b/Source/DirectFB/lib/voodoo/connection_raw.h new file mode 100755 index 0000000..45ce4c5 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/connection_raw.h @@ -0,0 +1,60 @@ +/* + (c) Copyright 2001-2011 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 __VOODOO__CONNECTION_RAW_H__ +#define __VOODOO__CONNECTION_RAW_H__ + +#include + + +class VoodooConnectionRaw : public VoodooConnectionLink { +private: + DirectThread *io; + bool stop; + bool closed; + +public: + VoodooConnectionRaw( VoodooManager *manager, + VoodooLink *link ); + + virtual ~VoodooConnectionRaw(); + + virtual void Start(); + virtual void Stop(); + + +private: + void *io_loop(); + + + static void *io_loop_main( DirectThread *thread, + void *arg ); +}; + + +#endif diff --git a/Source/DirectFB/lib/voodoo/dispatcher.cpp b/Source/DirectFB/lib/voodoo/dispatcher.cpp new file mode 100755 index 0000000..af98c0a --- /dev/null +++ b/Source/DirectFB/lib/voodoo/dispatcher.cpp @@ -0,0 +1,231 @@ +/* + (c) Copyright 2001-2011 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +extern "C" { +#include +#include +#include +#include +#include +#include + +#include +#include +} + +#include +#include +#include + + +D_DEBUG_DOMAIN( Voodoo_Dispatcher, "Voodoo/Dispatcher", "Voodoo Dispatcher" ); + +/**********************************************************************************************************************/ + +VoodooDispatcher::VoodooDispatcher( VoodooManager *manager ) + : + magic(0), + manager(manager), + packets(NULL) +{ + D_DEBUG_AT( Voodoo_Dispatcher, "VoodooDispatcher::%s( %p )\n", __func__, this ); + + /* Initialize lock. */ + direct_mutex_init( &lock ); + + /* Initialize wait queue. */ + direct_waitqueue_init( &queue ); + + D_MAGIC_SET( this, VoodooDispatcher ); + + + dispatch_loop = direct_thread_create( DTT_MESSAGING, DispatchLoopMain, this, "Voodoo Dispatch" ); +} + +VoodooDispatcher::~VoodooDispatcher() +{ + D_DEBUG_AT( Voodoo_Dispatcher, "VoodooDispatcher::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooDispatcher ); + + /* Acquire lock and wake up waiters. */ + direct_mutex_lock( &lock ); + direct_waitqueue_broadcast( &queue ); + direct_mutex_unlock( &lock ); + + /* Wait for dispatcher loop exiting. */ + direct_thread_join( dispatch_loop ); + direct_thread_destroy( dispatch_loop ); + + /* Destroy queue. */ + direct_waitqueue_deinit( &queue ); + + /* Destroy lock. */ + direct_mutex_deinit( &lock ); + + D_MAGIC_CLEAR( this ); +} + +bool +VoodooDispatcher::Ready() +{ + D_DEBUG_AT( Voodoo_Dispatcher, "VoodooDispatcher::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooDispatcher ); + + direct_mutex_lock( &lock ); + + bool ready = direct_list_count_elements_EXPENSIVE( packets ) < 3; + + direct_mutex_unlock( &lock ); + + return ready; +} + +void +VoodooDispatcher::PutPacket( VoodooPacket *packet ) +{ + D_DEBUG_AT( Voodoo_Dispatcher, "VoodooDispatcher::%s( %p, packet %p )\n", __func__, this, packet ); + + D_MAGIC_ASSERT( this, VoodooDispatcher ); + + direct_mutex_lock( &lock ); + + direct_list_append( &packets, &packet->link ); + + direct_waitqueue_broadcast( &queue ); + + direct_mutex_unlock( &lock ); +} + +void +VoodooDispatcher::ProcessMessages( VoodooMessageHeader *first, + size_t total_length ) +{ + D_DEBUG_AT( Voodoo_Dispatcher, "VoodooDispatcher::%s( %p, first %p, total_length "_ZU" )\n", + __func__, this, first, total_length ); + + D_MAGIC_ASSERT( this, VoodooDispatcher ); + + VoodooMessageHeader *header = first; + size_t offset = 0; + size_t aligned; + + while (offset < total_length) { + /* Get the message header. */ + header = (VoodooMessageHeader *)((char*) first + offset); + aligned = VOODOO_MSG_ALIGN( header->size ); + + D_DEBUG_AT( Voodoo_Dispatcher, " -> Next message has %d ("_ZU") bytes and is of type %d... (offset "_ZU"/"_ZU")\n", + header->size, aligned, header->type, offset, total_length ); + + D_ASSERT( header->size >= (int) sizeof(VoodooMessageHeader) ); + D_ASSERT( header->size <= MAX_MSG_SIZE ); + + D_ASSERT( offset + aligned <= total_length ); + + switch (header->type) { + case VMSG_SUPER: + manager->handle_super( (VoodooSuperMessage*) header ); + break; + + case VMSG_REQUEST: + manager->handle_request( (VoodooRequestMessage*) header ); + break; + + case VMSG_RESPONSE: + manager->handle_response( (VoodooResponseMessage*) header ); + break; + + default: + D_BUG( "invalid message type %d", header->type ); + break; + } + + offset += aligned; + } + + D_ASSERT( offset == total_length ); +} + +/**********************************************************************************************************************/ + +void * +VoodooDispatcher::DispatchLoop() +{ + D_DEBUG_AT( Voodoo_Dispatcher, "VoodooDispatcher::%s( %p )\n", __func__, this ); + + direct_mutex_lock( &lock ); + + while (!manager->is_quit) { + VoodooPacket *packet; + + D_MAGIC_ASSERT( this, VoodooDispatcher ); + + if (packets) { + packet = (VoodooPacket*) packets; + + direct_list_remove( &packets, &packet->link ); + + manager->link->WakeUp( manager->link ); + } + else { + direct_waitqueue_wait( &queue, &lock ); + + continue; + } + + + direct_mutex_unlock( &lock ); + + ProcessMessages( (VoodooMessageHeader*) packet->data_start(), packet->size() ); + + D_FREE( packet ); + + direct_mutex_lock( &lock ); + } + + direct_mutex_unlock( &lock ); + + return NULL; +} + +void * +VoodooDispatcher::DispatchLoopMain( DirectThread *thread, void *arg ) +{ + D_DEBUG_AT( Voodoo_Dispatcher, "VoodooDispatcher::%s( %p, thread %p )\n", __func__, arg, thread ); + + VoodooDispatcher *dispatcher = (VoodooDispatcher*) arg; + + return dispatcher->DispatchLoop(); +} + diff --git a/Source/DirectFB/lib/voodoo/dispatcher.h b/Source/DirectFB/lib/voodoo/dispatcher.h new file mode 100755 index 0000000..f0518db --- /dev/null +++ b/Source/DirectFB/lib/voodoo/dispatcher.h @@ -0,0 +1,71 @@ +/* + (c) Copyright 2001-2011 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 __VOODOO__DISPATCHER_H__ +#define __VOODOO__DISPATCHER_H__ + +extern "C" { +#include +} + + +class VoodooDispatcher { +private: + int magic; + + VoodooManager *manager; + + DirectMutex lock; + DirectWaitQueue queue; + + DirectThread *dispatch_loop; + + DirectLink *packets; + + +public: + VoodooDispatcher( VoodooManager *manager ); + + ~VoodooDispatcher(); + + bool Ready (); + void PutPacket( VoodooPacket *packet ); + + +private: + void *DispatchLoop(); + + static void *DispatchLoopMain( DirectThread *thread, + void *arg ); + + void ProcessMessages ( VoodooMessageHeader *first, + size_t total_length ); +}; + + +#endif diff --git a/Source/DirectFB/lib/voodoo/instance.cpp b/Source/DirectFB/lib/voodoo/instance.cpp new file mode 100755 index 0000000..61bd20f --- /dev/null +++ b/Source/DirectFB/lib/voodoo/instance.cpp @@ -0,0 +1,107 @@ +/* + (c) Copyright 2001-2011 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +extern "C" { +#include +#include +#include + +#include +} + +#include +#include + + +D_DEBUG_DOMAIN( Voodoo_Instance, "Voodoo/Instance", "Voodoo Instance" ); + +/**********************************************************************************************************************/ + +VoodooInstance::VoodooInstance() + : + magic(0), + refs(1) +{ + D_DEBUG_AT( Voodoo_Instance, "VoodooInstance::%s( %p )\n", __func__, this ); + + D_MAGIC_SET( this, VoodooInstance ); +} + +VoodooInstance::~VoodooInstance() +{ + D_DEBUG_AT( Voodoo_Instance, "VoodooInstance::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooInstance ); + + + D_MAGIC_CLEAR( this ); +} + +void +VoodooInstance::AddRef() +{ + D_DEBUG_AT( Voodoo_Instance, "VoodooInstance::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooInstance ); + + D_ASSERT( refs > 0 ); + + refs++; +} + +void +VoodooInstance::Release() +{ + D_DEBUG_AT( Voodoo_Instance, "VoodooInstance::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooInstance ); + + D_ASSERT( refs > 0 ); + + if (!--refs) { + D_DEBUG_AT( Voodoo_Instance, " -> zero refs, deleting instance...\n" ); + + delete this; + } +} + +DirectResult +VoodooInstance::Dispatch( VoodooManager *manager, + VoodooRequestMessage *msg ) +{ + D_DEBUG_AT( Voodoo_Instance, "VoodooInstance::%s( %p, manager %p, msg %p )\n", __func__, this, manager, msg ); + + D_MAGIC_ASSERT( this, VoodooInstance ); + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/instance.h b/Source/DirectFB/lib/voodoo/instance.h new file mode 100755 index 0000000..a8b434c --- /dev/null +++ b/Source/DirectFB/lib/voodoo/instance.h @@ -0,0 +1,61 @@ +/* + (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 __VOODOO__INSTANCE_H__ +#define __VOODOO__INSTANCE_H__ + +extern "C" { +#include +} + + +class VoodooInstance { +protected: + int magic; + +private: + unsigned int refs; + +public: + VoodooInstance(); + +protected: + virtual ~VoodooInstance(); + +public: + void AddRef(); + void Release(); + + +public: + virtual DirectResult Dispatch( VoodooManager *manager, + VoodooRequestMessage *msg ); +}; + + +#endif diff --git a/Source/DirectFB/lib/voodoo/interface.c b/Source/DirectFB/lib/voodoo/interface.c new file mode 100755 index 0000000..4281cb6 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/interface.c @@ -0,0 +1,114 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 + + +DirectResult +voodoo_construct_requestor( VoodooManager *manager, + const char *name, + VoodooInstanceID instance, + void *arg, + void **ret_requestor ) +{ + DirectResult ret; + DirectInterfaceFuncs *funcs; + void *requestor; + + D_ASSERT( manager != NULL ); + D_ASSERT( name != NULL ); + D_ASSERT( instance != VOODOO_INSTANCE_NONE ); + D_ASSERT( ret_requestor != NULL ); + + ret = DirectGetInterface( &funcs, name, "Requestor", NULL, NULL ); + if (ret) { + D_ERROR( "Voodoo/Interface: Could not load 'Requestor' implementation of '%s'!\n", name ); + return ret; + } + + ret = funcs->Allocate( &requestor ); + if (ret) + return ret; + + ret = funcs->Construct( requestor, manager, instance, arg ); + if (ret) + return ret; + + *ret_requestor = requestor; + + return DR_OK; +} + +DirectResult +voodoo_construct_dispatcher( VoodooManager *manager, + const char *name, + void *interface, + VoodooInstanceID super, + void *arg, + VoodooInstanceID *ret_instance, + void **ret_dispatcher ) +{ + DirectResult ret; + DirectInterfaceFuncs *funcs; + void *dispatcher; + VoodooInstanceID instance; + + D_ASSERT( manager != NULL ); + D_ASSERT( name != NULL ); + D_ASSERT( interface != NULL ); + D_ASSERT( super != VOODOO_INSTANCE_NONE ); + D_ASSERT( ret_instance != NULL ); + + ret = DirectGetInterface( &funcs, name, "Dispatcher", NULL, NULL ); + if (ret) { + D_ERROR( "Voodoo/Interface: Could not load 'Dispatcher' implementation of '%s'!\n", name ); + return ret; + } + + ret = funcs->Allocate( &dispatcher ); + if (ret) + return ret; + + ret = funcs->Construct( dispatcher, interface, manager, super, arg, &instance ); + if (ret) + return ret; + + *ret_instance = instance; + + if (ret_dispatcher) + *ret_dispatcher = dispatcher; + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/interface.h b/Source/DirectFB/lib/voodoo/interface.h new file mode 100755 index 0000000..8b1a47b --- /dev/null +++ b/Source/DirectFB/lib/voodoo/interface.h @@ -0,0 +1,52 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 __VOODOO__INTERFACE_H__ +#define __VOODOO__INTERFACE_H__ + +#include + + +DirectResult +voodoo_construct_requestor( VoodooManager *manager, + const char *name, + VoodooInstanceID instance, + void *arg, + void **ret_interface ); + +DirectResult +voodoo_construct_dispatcher( VoodooManager *manager, + const char *name, + void *interface, + VoodooInstanceID super, + void *arg, + VoodooInstanceID *ret_instance, + void **ret_dispatcher ); + +#endif + diff --git a/Source/DirectFB/lib/voodoo/internal.h b/Source/DirectFB/lib/voodoo/internal.h new file mode 100755 index 0000000..4eae9b0 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/internal.h @@ -0,0 +1,40 @@ +/* + (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 __VOODOO__INTERNAL_H__ +#define __VOODOO__INTERNAL_H__ + +#include + + +DirectResult VOODOO_API voodoo_server_construct( VoodooServer *server, + VoodooManager *manager, + const char *name, + VoodooInstanceID *ret_instance ); + +#endif diff --git a/Source/DirectFB/lib/voodoo/ivoodooplayer.c b/Source/DirectFB/lib/voodoo/ivoodooplayer.c new file mode 100755 index 0000000..2324667 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/ivoodooplayer.c @@ -0,0 +1,247 @@ +/* + (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 +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + + +D_DEBUG_DOMAIN( IVoodooPlayer_, "IVoodooPlayer", "IVoodooPlayer" ); + +/**********************************************************************************************************************/ + +static DirectResult CreateRemote( const char *host, int session, IVoodooPlayer **ret_interface ); + +/**********************************************************************************************************************/ + +typedef struct { + int ref; +} IVoodooPlayer_data; + +static DirectResult +IVoodooPlayer_AddRef( IVoodooPlayer *thiz ) +{ + DIRECT_INTERFACE_GET_DATA( IVoodooPlayer ); + + data->ref++; + + return DR_OK; +} + +static DirectResult +IVoodooPlayer_Release( IVoodooPlayer *thiz ) +{ + DIRECT_INTERFACE_GET_DATA( IVoodooPlayer ); + + if (!--data->ref) + DIRECT_DEALLOCATE_INTERFACE( thiz ); + + return DR_OK; +} + +static DirectResult +IVoodooPlayer_GetApps( IVoodooPlayer *thiz, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppDescription *ret_applications ) +{ + D_DEBUG_AT( IVoodooPlayer_, "%s()\n", __func__ ); + + if (!max_num || !ret_num || !ret_applications) + return DR_INVARG; + + return voodoo_player_get_apps( voodoo_player, max_num, ret_num, ret_applications ); +} + +static DirectResult +IVoodooPlayer_LaunchApp( IVoodooPlayer *thiz, + const u8 app_uuid[16], + const u8 player_uuid[16], + u8 ret_instance_uuid[16] ) +{ + D_DEBUG_AT( IVoodooPlayer_, "%s()\n", __func__ ); + + if (!app_uuid || !player_uuid || !ret_instance_uuid) + return DR_INVARG; + + return voodoo_player_launch_app( voodoo_player, app_uuid, player_uuid, ret_instance_uuid ); +} + +static DirectResult +IVoodooPlayer_StopInstance( IVoodooPlayer *thiz, + const u8 instance_uuid[16] ) +{ + D_DEBUG_AT( IVoodooPlayer_, "%s()\n", __func__ ); + + if (!instance_uuid) + return DR_INVARG; + + return voodoo_player_stop_instance( voodoo_player, instance_uuid ); +} + +static DirectResult +IVoodooPlayer_WaitInstance( IVoodooPlayer *thiz, + const u8 instance_uuid[16] ) +{ + D_DEBUG_AT( IVoodooPlayer_, "%s()\n", __func__ ); + + if (!instance_uuid) + return DR_INVARG; + + return voodoo_player_wait_instance( voodoo_player, instance_uuid ); +} + +static DirectResult +IVoodooPlayer_GetInstances( IVoodooPlayer *thiz, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppInstanceDescription *ret_instances ) +{ + D_DEBUG_AT( IVoodooPlayer_, "%s()\n", __func__ ); + + if (!max_num || !ret_num || !ret_instances) + return DR_INVARG; + + return voodoo_player_get_instances( voodoo_player, max_num, ret_num, ret_instances ); +} + +static DirectResult +IVoodooPlayer_Construct( IVoodooPlayer *thiz ) +{ + DIRECT_ALLOCATE_INTERFACE_DATA( thiz, IVoodooPlayer ); + + data->ref = 1; + + thiz->AddRef = IVoodooPlayer_AddRef; + thiz->Release = IVoodooPlayer_Release; + thiz->GetApps = IVoodooPlayer_GetApps; + thiz->LaunchApp = IVoodooPlayer_LaunchApp; + thiz->StopInstance = IVoodooPlayer_StopInstance; + thiz->WaitInstance = IVoodooPlayer_WaitInstance; + thiz->GetInstances = IVoodooPlayer_GetInstances; + + return DR_OK; +} + +DirectResult +VoodooPlayerCreate( IVoodooPlayer **ret_interface ) +{ + DirectResult ret; + IVoodooPlayer *player; + + if (!ret_interface) + return DR_INVARG; + + if (dfb_config->remote.host) + return CreateRemote( dfb_config->remote.host, dfb_config->remote.session, ret_interface ); + + if (!voodoo_player) + return DR_NOSUCHINSTANCE; + + DIRECT_ALLOCATE_INTERFACE( player, IVoodooPlayer ); + + ret = IVoodooPlayer_Construct( player ); + if (ret) + return ret; + + *ret_interface = player; + + return DR_OK; +} + +/**********************************************************************************************************************/ + +static DirectResult +CreateRemote( const char *host, int session, IVoodooPlayer **ret_interface ) +{ + DFBResult ret; + DirectInterfaceFuncs *funcs; + void *interface; + + D_ASSERT( host != NULL ); + D_ASSERT( ret_interface != NULL ); + + ret = DirectGetInterface( &funcs, "IVoodooPlayer", "Requestor", NULL, NULL ); + if (ret) + return ret; + + ret = funcs->Allocate( &interface ); + if (ret) + return ret; + + ret = funcs->Construct( interface, host, session ); + if (ret) + return ret; + + *ret_interface = interface; + + return DFB_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/ivoodooplayer.h b/Source/DirectFB/lib/voodoo/ivoodooplayer.h new file mode 100755 index 0000000..ae1ef03 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/ivoodooplayer.h @@ -0,0 +1,74 @@ +/* + (c) Copyright 2001-2010 The DirectFB Organization (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 __IVOODOOPLAYER_H__ +#define __IVOODOOPLAYER_H__ + +#include + + +DECLARE_INTERFACE( IVoodooPlayer ); + +DEFINE_INTERFACE( IVoodooPlayer, + + DirectResult (*GetApps)( + IVoodooPlayer *thiz, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppDescription *ret_applications + ); + + DirectResult (*LaunchApp)( + IVoodooPlayer *thiz, + const u8 app_uuid[16], + const u8 player_uuid[16], + u8 ret_instance_uuid[16] + ); + + DirectResult (*StopInstance)( + IVoodooPlayer *thiz, + const u8 instance_uuid[16] + ); + + DirectResult (*WaitInstance)( + IVoodooPlayer *thiz, + const u8 instance_uuid[16] + ); + + DirectResult (*GetInstances)( + IVoodooPlayer *thiz, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppInstanceDescription *ret_instances + ); +); + + +DirectResult VoodooPlayerCreate( IVoodooPlayer **ret_interface ); + +#endif diff --git a/Source/DirectFB/lib/voodoo/ivoodooplayer_dispatcher.c b/Source/DirectFB/lib/voodoo/ivoodooplayer_dispatcher.c new file mode 100755 index 0000000..bcf4711 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/ivoodooplayer_dispatcher.c @@ -0,0 +1,359 @@ +/* + (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 "ivoodooplayer_dispatcher.h" + +static DirectResult Probe( void ); +static DirectResult Construct( IVoodooPlayer *thiz, + VoodooManager *manager, + VoodooInstanceID *ret_instance ); + +#include + +DIRECT_INTERFACE_IMPLEMENTATION( IVoodooPlayer, Dispatcher ) + + +/**************************************************************************************************/ + +/* + * private data struct of IVoodooPlayer_Dispatcher + */ +typedef struct { + int ref; /* reference counter */ + + IVoodooPlayer *real; + + VoodooInstanceID self; /* The instance of this dispatcher itself. */ +} IVoodooPlayer_Dispatcher_data; + +/**************************************************************************************************/ + +static void +IVoodooPlayer_Dispatcher_Destruct( IVoodooPlayer *thiz ) +{ + D_DEBUG( "%s (%p)\n", __FUNCTION__, thiz ); + + DIRECT_DEALLOCATE_INTERFACE( thiz ); +} + +/**************************************************************************************************/ + +static DirectResult +IVoodooPlayer_Dispatcher_AddRef( IVoodooPlayer *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Dispatcher) + + data->ref++; + + return DR_OK; +} + +static DirectResult +IVoodooPlayer_Dispatcher_Release( IVoodooPlayer *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Dispatcher) + + if (--data->ref == 0) + IVoodooPlayer_Dispatcher_Destruct( thiz ); + + return DR_OK; +} + +static DirectResult +IVoodooPlayer_Dispatcher_GetApps( IVoodooPlayer *thiz, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppDescription *ret_applications ) +{ + return DR_UNIMPLEMENTED; +} + +static DirectResult +IVoodooPlayer_Dispatcher_LaunchApp( IVoodooPlayer *thiz, + const u8 app_uuid[16], + const u8 player_uuid[16], + u8 ret_instance_uuid[16] ) +{ + return DR_UNIMPLEMENTED; +} + +static DirectResult +IVoodooPlayer_Dispatcher_StopInstance( IVoodooPlayer *thiz, + const u8 instance_uuid[16] ) +{ + return DR_UNIMPLEMENTED; +} + +/**************************************************************************************************/ + +static DirectResult +Dispatch_GetApps( IVoodooPlayer *thiz, IVoodooPlayer *real, + VoodooManager *manager, VoodooRequestMessage *msg ) +{ + DirectResult ret; + unsigned int max_num; + VoodooMessageParser parser; + unsigned int num; + VoodooAppDescription *apps; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Dispatcher) + + VOODOO_PARSER_BEGIN( parser, msg ); + VOODOO_PARSER_GET_UINT( parser, max_num ); + VOODOO_PARSER_END( parser ); + + if (max_num > 1000) + return DR_LIMITEXCEEDED; + + apps = D_MALLOC( max_num * sizeof(VoodooAppDescription) ); + if (!apps) + return D_OOM(); + + ret = real->GetApps( real, max_num, &num, apps ); + if (ret == DR_OK) { + if (num > 0) { + ret = voodoo_manager_respond( manager, true, msg->header.serial, + ret, VOODOO_INSTANCE_NONE, + VMBT_UINT, num, + VMBT_DATA, num * sizeof(VoodooAppDescription), apps, + VMBT_NONE ); + } + else { + ret = voodoo_manager_respond( manager, true, msg->header.serial, + ret, VOODOO_INSTANCE_NONE, + VMBT_UINT, num, + VMBT_NONE ); + } + } + + D_FREE( apps ); + + return ret; +} + +static DirectResult +Dispatch_LaunchApp( IVoodooPlayer *thiz, IVoodooPlayer *real, + VoodooManager *manager, VoodooRequestMessage *msg ) +{ + DirectResult ret; + VoodooMessageParser parser; + const u8 *app_uuid; + const u8 *player_uuid; + u8 instance_uuid[16]; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Dispatcher) + + VOODOO_PARSER_BEGIN( parser, msg ); + VOODOO_PARSER_GET_DATA( parser, app_uuid ); + VOODOO_PARSER_GET_DATA( parser, player_uuid ); + VOODOO_PARSER_END( parser ); + + ret = real->LaunchApp( real, app_uuid, player_uuid, instance_uuid ); + + return voodoo_manager_respond( manager, true, msg->header.serial, + ret, VOODOO_INSTANCE_NONE, + VMBT_DATA, 16, instance_uuid, + VMBT_NONE ); +} + +static DirectResult +Dispatch_StopInstance( IVoodooPlayer *thiz, IVoodooPlayer *real, + VoodooManager *manager, VoodooRequestMessage *msg ) +{ + DirectResult ret; + VoodooMessageParser parser; + const u8 *instance_uuid; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Dispatcher) + + VOODOO_PARSER_BEGIN( parser, msg ); + VOODOO_PARSER_GET_DATA( parser, instance_uuid ); + VOODOO_PARSER_END( parser ); + + ret = real->StopInstance( real, instance_uuid ); + + return voodoo_manager_respond( manager, true, msg->header.serial, + ret, VOODOO_INSTANCE_NONE, + VMBT_NONE ); +} + +static DirectResult +Dispatch_WaitInstance( IVoodooPlayer *thiz, IVoodooPlayer *real, + VoodooManager *manager, VoodooRequestMessage *msg ) +{ + DirectResult ret; + VoodooMessageParser parser; + const u8 *instance_uuid; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Dispatcher) + + VOODOO_PARSER_BEGIN( parser, msg ); + VOODOO_PARSER_GET_DATA( parser, instance_uuid ); + VOODOO_PARSER_END( parser ); + + ret = real->WaitInstance( real, instance_uuid ); + + return voodoo_manager_respond( manager, true, msg->header.serial, + ret, VOODOO_INSTANCE_NONE, + VMBT_NONE ); +} + +static DirectResult +Dispatch_GetInstances( IVoodooPlayer *thiz, IVoodooPlayer *real, + VoodooManager *manager, VoodooRequestMessage *msg ) +{ + DirectResult ret; + unsigned int max_num; + VoodooMessageParser parser; + unsigned int num; + VoodooAppInstanceDescription *instances; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Dispatcher) + + VOODOO_PARSER_BEGIN( parser, msg ); + VOODOO_PARSER_GET_UINT( parser, max_num ); + VOODOO_PARSER_END( parser ); + + if (max_num > 1000) + return DR_LIMITEXCEEDED; + + instances = D_MALLOC( max_num * sizeof(VoodooAppInstanceDescription) ); + if (!instances) + return D_OOM(); + + ret = real->GetInstances( real, max_num, &num, instances ); + if (ret == DR_OK) { + if (num > 0) { + ret = voodoo_manager_respond( manager, true, msg->header.serial, + ret, VOODOO_INSTANCE_NONE, + VMBT_UINT, num, + VMBT_DATA, num * sizeof(VoodooAppInstanceDescription), instances, + VMBT_NONE ); + } + else { + ret = voodoo_manager_respond( manager, true, msg->header.serial, + ret, VOODOO_INSTANCE_NONE, + VMBT_UINT, num, + VMBT_NONE ); + } + } + + D_FREE( instances ); + + return ret; +} + +static DirectResult +Dispatch( void *dispatcher, void *real, VoodooManager *manager, VoodooRequestMessage *msg ) +{ + D_DEBUG( "IVoodooPlayer/Dispatcher: " + "Handling request for instance %u with method %u...\n", msg->instance, msg->method ); + + switch (msg->method) { + case IVOODOOPLAYER_METHOD_ID_GetApps: + return Dispatch_GetApps( dispatcher, real, manager, msg ); + + case IVOODOOPLAYER_METHOD_ID_LaunchApp: + return Dispatch_LaunchApp( dispatcher, real, manager, msg ); + + case IVOODOOPLAYER_METHOD_ID_StopInstance: + return Dispatch_StopInstance( dispatcher, real, manager, msg ); + + case IVOODOOPLAYER_METHOD_ID_WaitInstance: + return Dispatch_WaitInstance( dispatcher, real, manager, msg ); + + case IVOODOOPLAYER_METHOD_ID_GetInstances: + return Dispatch_GetInstances( dispatcher, real, manager, msg ); + } + + return DR_NOSUCHMETHOD; +} + +/**************************************************************************************************/ + +static DirectResult +Probe() +{ + /* This implementation has to be loaded explicitly. */ + return DR_UNSUPPORTED; +} + +/* + * Constructor + * + * Fills in function pointers and intializes data structure. + */ +static DirectResult +Construct( IVoodooPlayer *thiz, VoodooManager *manager, VoodooInstanceID *ret_instance ) +{ + DirectResult ret; + IVoodooPlayer *real; + VoodooInstanceID instance; + + DIRECT_ALLOCATE_INTERFACE_DATA(thiz, IVoodooPlayer_Dispatcher) + + ret = VoodooPlayerCreate( &real ); + if (ret) { + DIRECT_DEALLOCATE_INTERFACE( thiz ); + return ret; + } + + ret = voodoo_manager_register_local( manager, VOODOO_INSTANCE_NONE, thiz, real, Dispatch, &instance ); + if (ret) { + real->Release( real ); + DIRECT_DEALLOCATE_INTERFACE( thiz ); + return ret; + } + + *ret_instance = instance; + + data->ref = 1; + data->real = real; + data->self = instance; + + thiz->AddRef = IVoodooPlayer_Dispatcher_AddRef; + thiz->Release = IVoodooPlayer_Dispatcher_Release; + thiz->GetApps = IVoodooPlayer_Dispatcher_GetApps; + thiz->LaunchApp = IVoodooPlayer_Dispatcher_LaunchApp; + thiz->StopInstance = IVoodooPlayer_Dispatcher_StopInstance; + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/ivoodooplayer_dispatcher.h b/Source/DirectFB/lib/voodoo/ivoodooplayer_dispatcher.h new file mode 100755 index 0000000..a01d0d9 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/ivoodooplayer_dispatcher.h @@ -0,0 +1,41 @@ +/* + (c) Copyright 2001-2010 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 __IVOODOOPLAYER_DISPATCHER_H__ +#define __IVOODOOPLAYER_DISPATCHER_H__ + +#define IVOODOOPLAYER_METHOD_ID_AddRef 1 +#define IVOODOOPLAYER_METHOD_ID_Release 2 +#define IVOODOOPLAYER_METHOD_ID_GetApps 3 +#define IVOODOOPLAYER_METHOD_ID_LaunchApp 4 +#define IVOODOOPLAYER_METHOD_ID_StopInstance 5 +#define IVOODOOPLAYER_METHOD_ID_WaitInstance 6 +#define IVOODOOPLAYER_METHOD_ID_GetInstances 7 + +#endif + diff --git a/Source/DirectFB/lib/voodoo/ivoodooplayer_requestor.c b/Source/DirectFB/lib/voodoo/ivoodooplayer_requestor.c new file mode 100755 index 0000000..1ffdcf9 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/ivoodooplayer_requestor.c @@ -0,0 +1,330 @@ +/* + (c) Copyright 2001-2010 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 "ivoodooplayer_dispatcher.h" + + +static DirectResult Probe( void ); +static DirectResult Construct( IVoodooPlayer *thiz, const char *host, int session ); + +#include + +DIRECT_INTERFACE_IMPLEMENTATION( IVoodooPlayer, Requestor ) + + +/**************************************************************************************************/ + +/* + * private data struct of IVoodooPlayer_Requestor + */ +typedef struct { + int ref; /* reference counter */ + + VoodooClient *client; + VoodooManager *manager; + + VoodooInstanceID instance; +} IVoodooPlayer_Requestor_data; + +/**************************************************************************************************/ + +static void +IVoodooPlayer_Requestor_Destruct( IVoodooPlayer *thiz ) +{ + IVoodooPlayer_Requestor_data *data = thiz->priv; + + D_DEBUG( "%s (%p)\n", __FUNCTION__, thiz ); + + voodoo_client_destroy( data->client ); + + DIRECT_DEALLOCATE_INTERFACE( thiz ); +} + +/**************************************************************************************************/ + +static DirectResult +IVoodooPlayer_Requestor_AddRef( IVoodooPlayer *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Requestor) + + data->ref++; + + return DR_OK; +} + +static DirectResult +IVoodooPlayer_Requestor_Release( IVoodooPlayer *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Requestor) + + if (--data->ref == 0) + IVoodooPlayer_Requestor_Destruct( thiz ); + + return DR_OK; +} + +static DirectResult +IVoodooPlayer_Requestor_GetApps( IVoodooPlayer *thiz, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppDescription *ret_applications ) +{ + DirectResult ret; + VoodooResponseMessage *response; + + if (!max_num || !ret_num || !ret_applications) + return DR_INVARG; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Requestor) + + ret = voodoo_manager_request( data->manager, data->instance, + IVOODOOPLAYER_METHOD_ID_GetApps, VREQ_RESPOND, &response, + VMBT_UINT, max_num, + VMBT_NONE ); + if (ret) + return ret; + + ret = response->result; + if (ret == DR_OK) { + VoodooMessageParser parser; + unsigned int num; + + VOODOO_PARSER_BEGIN( parser, response ); + VOODOO_PARSER_GET_UINT( parser, num ); + + if (num > max_num) + num = max_num; + + *ret_num = num; + + if (num > 0) + VOODOO_PARSER_READ_DATA( parser, ret_applications, num * sizeof(VoodooAppDescription) ); + + VOODOO_PARSER_END( parser ); + } + + voodoo_manager_finish_request( data->manager, response ); + + return ret; +} + +static DirectResult +IVoodooPlayer_Requestor_LaunchApp( IVoodooPlayer *thiz, + const u8 app_uuid[16], + const u8 player_uuid[16], + u8 ret_instance_uuid[16] ) +{ + DirectResult ret; + VoodooResponseMessage *response; + + if (!app_uuid || !player_uuid || !ret_instance_uuid) + return DR_INVARG; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Requestor) + + ret = voodoo_manager_request( data->manager, data->instance, + IVOODOOPLAYER_METHOD_ID_LaunchApp, VREQ_RESPOND, &response, + VMBT_DATA, 16, app_uuid, + VMBT_DATA, 16, player_uuid, + VMBT_NONE ); + if (ret) + return ret; + + ret = response->result; + if (ret == DR_OK) { + VoodooMessageParser parser; + + VOODOO_PARSER_BEGIN( parser, response ); + VOODOO_PARSER_READ_DATA( parser, ret_instance_uuid, 16 ); + VOODOO_PARSER_END( parser ); + } + + voodoo_manager_finish_request( data->manager, response ); + + return ret; +} + +static DirectResult +IVoodooPlayer_Requestor_StopInstance( IVoodooPlayer *thiz, + const u8 instance_uuid[16] ) +{ + DirectResult ret; + VoodooResponseMessage *response; + + if (!instance_uuid) + return DR_INVARG; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Requestor) + + ret = voodoo_manager_request( data->manager, data->instance, + IVOODOOPLAYER_METHOD_ID_StopInstance, VREQ_RESPOND, &response, + VMBT_DATA, 16, instance_uuid, + VMBT_NONE ); + if (ret) + return ret; + + ret = response->result; + + voodoo_manager_finish_request( data->manager, response ); + + return ret; +} + +static DirectResult +IVoodooPlayer_Requestor_WaitInstance( IVoodooPlayer *thiz, + const u8 instance_uuid[16] ) +{ + DirectResult ret; + VoodooResponseMessage *response; + + if (!instance_uuid) + return DR_INVARG; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Requestor) + + ret = voodoo_manager_request( data->manager, data->instance, + IVOODOOPLAYER_METHOD_ID_WaitInstance, VREQ_RESPOND, &response, + VMBT_DATA, 16, instance_uuid, + VMBT_NONE ); + if (ret) + return ret; + + ret = response->result; + + voodoo_manager_finish_request( data->manager, response ); + + return ret; +} + +static DirectResult +IVoodooPlayer_Requestor_GetInstances( IVoodooPlayer *thiz, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppInstanceDescription *ret_instances ) +{ + DirectResult ret; + VoodooResponseMessage *response; + + if (!max_num || !ret_num || !ret_instances) + return DR_INVARG; + + DIRECT_INTERFACE_GET_DATA(IVoodooPlayer_Requestor) + + ret = voodoo_manager_request( data->manager, data->instance, + IVOODOOPLAYER_METHOD_ID_GetInstances, VREQ_RESPOND, &response, + VMBT_UINT, max_num, + VMBT_NONE ); + if (ret) + return ret; + + ret = response->result; + if (ret == DR_OK) { + VoodooMessageParser parser; + unsigned int num; + + VOODOO_PARSER_BEGIN( parser, response ); + VOODOO_PARSER_GET_UINT( parser, num ); + + if (num > max_num) + num = max_num; + + *ret_num = num; + + if (num > 0) + VOODOO_PARSER_READ_DATA( parser, ret_instances, num * sizeof(VoodooAppInstanceDescription) ); + + VOODOO_PARSER_END( parser ); + } + + voodoo_manager_finish_request( data->manager, response ); + + return ret; +} + +/**************************************************************************************************/ + +static DirectResult +Probe() +{ + /* This implementation has to be loaded explicitly. */ + return DR_UNSUPPORTED; +} + +/* + * Constructor + * + * Fills in function pointers and intializes data structure. + */ +static DirectResult +Construct( IVoodooPlayer *thiz, const char *host, int session ) +{ + DirectResult ret; + + DIRECT_ALLOCATE_INTERFACE_DATA(thiz, IVoodooPlayer_Requestor) + + data->ref = 1; + + ret = voodoo_client_create( host, session, &data->client ); + if (ret) { + DIRECT_DEALLOCATE_INTERFACE( thiz ); + return ret; + } + + data->manager = voodoo_client_manager( data->client ); + + ret = voodoo_manager_super( data->manager, "IVoodooPlayer", &data->instance ); + if (ret) { + voodoo_client_destroy( data->client ); + DIRECT_DEALLOCATE_INTERFACE( thiz ); + return ret; + } + + thiz->AddRef = IVoodooPlayer_Requestor_AddRef; + thiz->Release = IVoodooPlayer_Requestor_Release; + thiz->GetApps = IVoodooPlayer_Requestor_GetApps; + thiz->LaunchApp = IVoodooPlayer_Requestor_LaunchApp; + thiz->StopInstance = IVoodooPlayer_Requestor_StopInstance; + thiz->WaitInstance = IVoodooPlayer_Requestor_WaitInstance; + thiz->GetInstances = IVoodooPlayer_Requestor_GetInstances; + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/link.h b/Source/DirectFB/lib/voodoo/link.h new file mode 100755 index 0000000..e54b1d4 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/link.h @@ -0,0 +1,78 @@ +/* + (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 __VOODOO__LINK_H__ +#define __VOODOO__LINK_H__ + +#include + + +typedef struct { + void *ptr; + size_t length; + size_t done; +} VoodooChunk; + + +struct __V_VoodooLink { + void *priv; + u32 code; + + void (*Close)( VoodooLink *link ); + + /* See 'read(2)', blocking */ + ssize_t (*Read) ( VoodooLink *link, + void *buffer, + size_t count ); + + /* See 'write(2)', blocking */ + ssize_t (*Write)( VoodooLink *link, + const void *buffer, + size_t count ); + + + /* For later... */ + DirectResult (*SendReceive)( VoodooLink *link, + VoodooChunk *send, + size_t num_send, + VoodooChunk *recv, + size_t num_recv ); + + DirectResult (*WakeUp) ( VoodooLink *link ); +}; + + +DirectResult VOODOO_API voodoo_link_init_connect( VoodooLink *link, + const char *hostname, + int port, + bool raw ); + +DirectResult VOODOO_API voodoo_link_init_fd ( VoodooLink *link, + int fd[2] ); + +#endif diff --git a/Source/DirectFB/lib/voodoo/manager.cpp b/Source/DirectFB/lib/voodoo/manager.cpp new file mode 100755 index 0000000..3b2f70c --- /dev/null +++ b/Source/DirectFB/lib/voodoo/manager.cpp @@ -0,0 +1,937 @@ +/* + (c) Copyright 2001-2011 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +#include + +extern "C" { +#include +#include +#include +#include +#include +#include + +#include +#include +#include +} + +#include +#include +#include +#include +#include + + +//namespace Voodoo { + +D_DEBUG_DOMAIN( Voodoo_Dispatch, "Voodoo/Dispatch", "Voodoo Dispatch" ); +D_DEBUG_DOMAIN( Voodoo_Manager, "Voodoo/Manager", "Voodoo Manager" ); + +/**********************************************************************************************************************/ + +VoodooManager::VoodooManager( VoodooLink *link, + VoodooContext *context ) + : + magic(0), + is_quit(false), + msg_count(0), + msg_serial(0) +{ + D_ASSERT( link != NULL ); + + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + /* Store link and context */ + this->link = link; + this->context = context; + + + instances.last = 0; + + response.current = NULL; + + + /* Initialize all locks. */ + direct_recursive_mutex_init( &instances.lock ); + direct_recursive_mutex_init( &response.lock ); + + /* Initialize all wait conditions. */ + direct_waitqueue_init( &response.wait_get ); + direct_waitqueue_init( &response.wait_put ); + + D_MAGIC_SET( this, VoodooManager ); + + + dispatcher = new VoodooDispatcher( this ); + + + /* Add connection */ + if ((link->code & 0x8000ffff) == 0x80008676) { + D_INFO( "Voodoo/Manager: Connection mode is PACKET\n" ); + + connection = new VoodooConnectionPacket( this, link ); + } + else { + D_INFO( "Voodoo/Manager: Connection mode is RAW\n" ); + + connection = new VoodooConnectionRaw( this, link ); + + // FIXME: query manager dynamically for compression instead + voodoo_config->compression_min = 0; + } + + connection->Start(); +} + +static void +instance_iterator( std::pair pair ) +{ + D_DEBUG_AT( Voodoo_Manager, "%s( id %u, instance %p )\n", __func__, pair.first, pair.second ); + + pair.second->Release(); +} + +VoodooManager::~VoodooManager() +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooManager ); + + if (!is_quit) + quit(); + + connection->Stop(); + + /* Destroy dispatcher */ + delete dispatcher; + + /* Remove connection */ + delete connection; + + /* Destroy conditions. */ + direct_waitqueue_deinit( &response.wait_get ); + direct_waitqueue_deinit( &response.wait_put ); + + /* Destroy locks. */ + direct_mutex_deinit( &instances.lock ); + direct_mutex_deinit( &response.lock ); + + /* Release all remaining interfaces. */ + std::for_each( instances.remote.begin(), instances.remote.end(), instance_iterator ); + std::for_each( instances.local.begin(), instances.local.end(), instance_iterator ); + + D_MAGIC_CLEAR( this ); +} + +/**********************************************************************************************************************/ + +void +VoodooManager::DispatchPacket( VoodooPacket *packet ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p, packet %p )\n", __func__, this, packet ); + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSUME( !is_quit ); + + if (is_quit) + return; + + dispatcher->PutPacket( packet ); +} + +bool +VoodooManager::DispatchReady() +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooManager ); +// D_ASSUME( !is_quit ); + + if (is_quit) + return false; + + return dispatcher->Ready(); +} + +/**********************************************************************************************************************/ + +void +VoodooManager::quit() +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSUME( !is_quit ); + + if (is_quit) + return; + + /* Have all threads quit upon this. */ + is_quit = true; + + /* Acquire locks and wake up waiters. */ + direct_mutex_lock( &response.lock ); + direct_waitqueue_broadcast( &response.wait_get ); + direct_waitqueue_broadcast( &response.wait_put ); + direct_mutex_unlock( &response.lock ); +} + +void +VoodooManager::handle_disconnect() +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooManager ); + + D_DEBUG_AT( Voodoo_Manager, " -> Remote site disconnected from manager at %p!\n", this ); + + quit(); +} + +void +VoodooManager::handle_super( VoodooSuperMessage *super ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + DirectResult ret; + const char *name; + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( super != NULL ); + D_ASSERT( super->header.size >= (int) sizeof(VoodooSuperMessage) ); + D_ASSERT( super->header.type == VMSG_SUPER ); + + name = (const char *) (super + 1); + + D_DEBUG_AT( Voodoo_Dispatch, " -> Handling SUPER message %llu for '%s' (%d bytes).\n", + (unsigned long long)super->header.serial, name, super->header.size ); + + VoodooInstanceID instance_id; + + ret = context->HandleSuper( this, name, &instance_id ); + if (ret) + do_respond( true, super->header.serial, ret ); + else + do_respond( true, super->header.serial, DR_OK, instance_id ); +} + +typedef struct { + VoodooManager *manager; + VoodooInstance *instance; + VoodooRequestMessage *request; +} DispatchAsyncContext; + +void * +VoodooManager::dispatch_async_thread( DirectThread *thread, + void *arg ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, arg ); + + DirectResult ret; + DispatchAsyncContext *context = (DispatchAsyncContext*) arg; + VoodooManager *manager = context->manager; + VoodooInstance *instance = context->instance; + VoodooRequestMessage *request = context->request; + + ret = instance->Dispatch( manager, request ); + + if (ret && (request->flags & VREQ_RESPOND)) + manager->do_respond( true, request->header.serial, ret ); + + D_FREE( context ); + + return NULL; +} + +void +VoodooManager::handle_request( VoodooRequestMessage *request ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + DirectResult ret; + VoodooInstance *instance; + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( request != NULL ); + D_ASSERT( request->header.size >= (int) sizeof(VoodooRequestMessage) ); + D_ASSERT( request->header.type == VMSG_REQUEST ); + + D_DEBUG_AT( Voodoo_Dispatch, " -> Handling REQUEST message %llu to %u::%u %s%s(%d bytes).\n", + (unsigned long long)request->header.serial, request->instance, request->method, + (request->flags & VREQ_RESPOND) ? "[RESPONDING] " : "", + (request->flags & VREQ_ASYNC) ? "[ASYNC] " : "", + request->header.size ); + + direct_mutex_lock( &instances.lock ); + + InstanceMap::iterator itr = instances.local.find( request->instance ); + + if (itr == instances.local.end()) { + direct_mutex_unlock( &instances.lock ); + + D_ERROR( "Voodoo/Dispatch: " + "Requested instance %u doesn't exist (anymore)!\n", request->instance ); + + if (request->flags & VREQ_RESPOND) + do_respond( true, request->header.serial, DR_NOSUCHINSTANCE ); + + return; + } + + instance = (*itr).second; + + if (request->flags & VREQ_ASYNC) { + DirectThread *thread; + DispatchAsyncContext *context; + + context = (DispatchAsyncContext*) D_MALLOC( sizeof(DispatchAsyncContext) + request->header.size ); + if (!context) { + D_WARN( "out of memory" ); + direct_mutex_unlock( &instances.lock ); + return; + } + + context->manager = this; + context->instance = instance; + context->request = (VoodooRequestMessage*) (context + 1); + + direct_memcpy( context->request, request, request->header.size ); + + thread = direct_thread_create( DTT_DEFAULT, dispatch_async_thread, context, "Voodoo Async" ); + direct_thread_detach( thread ); + // FIXME: free thread? + } + else { + ret = instance->Dispatch( this, request ); + + if (ret && (request->flags & VREQ_RESPOND)) + do_respond( true, request->header.serial, ret ); + } + + direct_mutex_unlock( &instances.lock ); +} + +void +VoodooManager::handle_response( VoodooResponseMessage *msg ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( msg != NULL ); + D_ASSERT( msg->header.size >= (int) sizeof(VoodooResponseMessage) ); + D_ASSERT( msg->header.type == VMSG_RESPONSE ); + D_ASSERT( msg->request < msg_serial ); + + D_DEBUG_AT( Voodoo_Dispatch, " -> Handling RESPONSE message %llu (%s) with instance %u for request " + "%llu (%d bytes).\n", (unsigned long long)msg->header.serial, DirectResultString( msg->result ), + msg->instance, (unsigned long long)msg->request, msg->header.size ); + + direct_mutex_lock( &response.lock ); + + D_ASSERT( response.current == NULL ); + + response.current = msg; + + direct_mutex_unlock( &response.lock ); + + + direct_waitqueue_broadcast( &response.wait_get ); + + direct_mutex_lock( &response.lock ); + + while (response.current && !is_quit) + direct_waitqueue_wait( &response.wait_put, &response.lock ); + + direct_mutex_unlock( &response.lock ); +} + +/**************************************************************************************************/ + +DirectResult +VoodooManager::lock_response( VoodooMessageSerial request, + VoodooResponseMessage **ret_response ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + VoodooResponseMessage *msg = NULL; + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( ret_response != NULL ); + + D_DEBUG_AT( Voodoo_Manager, " -> Locking response to request %llu...\n", (unsigned long long)request ); + + direct_mutex_lock( &response.lock ); + + while (!is_quit) { + msg = response.current; + if (msg && msg->request == request) + break; + + if (msg) + D_DEBUG_AT( Voodoo_Manager, " -> ...current response is for request %llu...\n", (unsigned long long)msg->request ); + + D_DEBUG_AT( Voodoo_Manager, " -> ...(still) waiting for response to request %llu...\n", (unsigned long long)request ); + + direct_waitqueue_wait( &response.wait_get, &response.lock ); + } + + if (is_quit) { + D_ERROR( "Voodoo/Manager: Quit while waiting for response!\n" ); + direct_mutex_unlock( &response.lock ); + return DR_DESTROYED; + } + + D_DEBUG_AT( Voodoo_Manager, " -> ...locked response %llu to request %llu (%d bytes).\n", + (unsigned long long)msg->header.serial, (unsigned long long)request, msg->header.size ); + + *ret_response = msg; + + return DR_OK; +} + +DirectResult +VoodooManager::unlock_response( VoodooResponseMessage *msg ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( msg != NULL ); + D_ASSERT( msg == response.current ); + + D_DEBUG_AT( Voodoo_Manager, " -> Unlocking response %llu to request %llu (%d bytes)...\n", + (unsigned long long)msg->header.serial, (unsigned long long)msg->request, msg->header.size ); + + response.current = NULL; + + direct_mutex_unlock( &response.lock ); + + direct_waitqueue_broadcast( &response.wait_put ); + + return DR_OK; +} + + + + +DirectResult +VoodooManager::do_super( const char *name, + VoodooInstanceID *ret_instance ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + DirectResult ret; + int len; + int size; + VoodooPacket *packet; + VoodooMessageSerial serial; + VoodooSuperMessage *msg; + VoodooResponseMessage *response; + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( name != NULL ); + D_ASSERT( ret_instance != NULL ); + + if (is_quit) { + D_DEBUG_AT( Voodoo_Manager, " -> QUIT!\n" ); + return DR_IO; + } + + /* Calculate the total message size. */ + len = strlen( name ) + 1; + size = sizeof(VoodooSuperMessage) + len; + + + /* Lock the output buffer for direct writing. */ + packet = connection->GetPacket( size ); + if (!packet) + return DR_FAILURE; + + msg = (VoodooSuperMessage*) packet->data_raw(); + + serial = msg_serial++; + + /* Fill message header. */ + msg->header.size = size; + msg->header.serial = serial; + msg->header.type = VMSG_SUPER; + + /* Append the name of the super interface to create. */ + direct_memcpy( msg + 1, name, len ); + + D_DEBUG_AT( Voodoo_Manager, " -> Sending SUPER message %llu for '%s' (%d bytes).\n", (unsigned long long)serial, name, size ); + + /* Unlock the output buffer. */ + connection->PutPacket( packet, true ); + + + /* Wait for and lock the response buffer. */ + ret = lock_response( serial, &response ); + if (ret) { + D_ERROR( "Voodoo/Manager: " + "Waiting for the response failed (%s)!\n", DirectResultString( ret ) ); + return ret; + } + + D_DEBUG_AT( Voodoo_Manager, " -> Got response %llu (%s) with instance %u for request %llu " + "(%d bytes).\n", (unsigned long long)response->header.serial, DirectResultString( ret ), + response->instance, (unsigned long long)response->request, response->header.size ); + + ret = response->result; + if (ret) { + D_ERROR( "Voodoo/Manager: Could not create remote super interface '%s' (%s)!\n", + name, DirectResultString( ret ) ); + unlock_response( response ); + return ret; + } + + D_INFO( "Voodoo/Manager: Created remote super interface '%s'.\n", name ); + + /* Return the new instance ID. */ + *ret_instance = response->instance; + + /* Unlock the response buffer. */ + unlock_response( response ); + + return DR_OK; +} + +void +VoodooManager::write_blocks( void *dst, + const VoodooMessageBlock *blocks, + size_t num ) +{ + size_t i; + u32 *d32 = (u32*) dst; + + for (i=0; i> 2); + } + + /* Write terminator. */ + d32[0] = VMBT_NONE; +} + +DirectResult +VoodooManager::do_request( VoodooInstanceID instance, + VoodooMethodID method, + VoodooRequestFlags flags, + VoodooResponseMessage **ret_response, + VoodooMessageBlock *blocks, + size_t num_blocks, + size_t data_size ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + DirectResult ret; + size_t size; + VoodooPacket *packet; + VoodooMessageSerial serial; + VoodooRequestMessage *msg; + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( instance != VOODOO_INSTANCE_NONE ); + D_ASSERT( ret_response != NULL || !(flags & VREQ_RESPOND) ); + D_ASSUME( (flags & (VREQ_RESPOND | VREQ_QUEUE)) != (VREQ_RESPOND | VREQ_QUEUE) ); + + D_DEBUG_AT( Voodoo_Manager, " -> Instance %u, method %u, flags 0x%08x...\n", instance, method, flags ); + + if (is_quit) { + D_DEBUG_AT( Voodoo_Manager, " -> QUIT!\n" ); + return DR_IO; + } + + /* Calculate the total message size. */ + size = sizeof(VoodooRequestMessage) + data_size; + + D_DEBUG_AT( Voodoo_Manager, " -> complete message size: %d\n", size ); + + /* Lock the output buffer for direct writing. */ + packet = connection->GetPacket( size ); + if (!packet) + return DR_FAILURE; + + msg = (VoodooRequestMessage*) packet->data_raw(); + + serial = msg_serial++; + + /* Fill message header. */ + msg->header.size = size; + msg->header.serial = serial; + msg->header.type = VMSG_REQUEST; + + /* Fill message body. */ + msg->instance = instance; + msg->method = method; + msg->flags = flags; + + /* Append custom data. */ + write_blocks( msg + 1, blocks, num_blocks ); + + + D_DEBUG_AT( Voodoo_Manager, " -> Sending REQUEST message %llu to %u::%u %s(%d bytes).\n", + (unsigned long long)serial, instance, method, (flags & VREQ_RESPOND) ? "[RESPONDING] " : "", size ); + + /* Unlock the output buffer. */ + connection->PutPacket( packet, !(flags & VREQ_QUEUE) ); + + /* Wait for and lock the response buffer. */ + if (flags & VREQ_RESPOND) { + VoodooResponseMessage *response; + + ret = lock_response( serial, &response ); + if (ret) { + D_ERROR( "Voodoo/Manager: " + "Waiting for the response failed (%s)!\n", DirectResultString( ret ) ); + return ret; + } + + D_DEBUG_AT( Voodoo_Manager, " -> Got response %llu (%s) with instance %u for request %llu " + "(%d bytes).\n", (unsigned long long)response->header.serial, DirectResultString( response->result ), + response->instance, (unsigned long long)response->request, response->header.size ); + + *ret_response = response; + } + + return DR_OK; +} + +DirectResult +VoodooManager::next_response( VoodooResponseMessage *response, + VoodooResponseMessage **ret_response ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + DirectResult ret; + VoodooMessageSerial serial; + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( response != NULL ); + + serial = response->request; + + /* Unlock the response buffer. */ + unlock_response( response ); + + ret = lock_response( serial, &response ); + if (ret) { + D_ERROR( "Voodoo/Manager: " + "Waiting for the response failed (%s)!\n", DirectResultString( ret ) ); + return ret; + } + + D_DEBUG_AT( Voodoo_Manager, " -> Got response %llu (%s) with instance %u for request %llu " + "(%d bytes).\n", (unsigned long long)response->header.serial, DirectResultString( response->result ), + response->instance, (unsigned long long)response->request, response->header.size ); + + *ret_response = response; + + return DR_OK; +} + +DirectResult +VoodooManager::finish_request( VoodooResponseMessage *response ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( response != NULL ); + + /* Unlock the response buffer. */ + return unlock_response( response ); +} + +DirectResult +VoodooManager::do_respond( bool flush, + VoodooMessageSerial request, + DirectResult result, + VoodooInstanceID instance, + VoodooMessageBlock *blocks, + size_t num_blocks, + size_t data_size ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + size_t size; + VoodooPacket *packet; + VoodooMessageSerial serial; + VoodooResponseMessage *msg; + + D_MAGIC_ASSERT( this, VoodooManager ); + + D_DEBUG_AT( Voodoo_Manager, " -> Request %llu, result %d, instance %u...\n", (unsigned long long)request, result, instance ); + + if (is_quit) { + D_DEBUG_AT( Voodoo_Manager, " -> QUIT!\n" ); + return DR_IO; + } + + /* Calculate the total message size. */ + size = sizeof(VoodooResponseMessage) + data_size; + + D_DEBUG_AT( Voodoo_Manager, " -> complete message size: %d\n", size ); + + + /* Lock the output buffer for direct writing. */ + packet = connection->GetPacket( size ); + if (!packet) + return DR_FAILURE; + + msg = (VoodooResponseMessage*) packet->data_raw(); + + serial = msg_serial++; + + /* Fill message header. */ + msg->header.size = size; + msg->header.serial = serial; + msg->header.type = VMSG_RESPONSE; + + /* Fill message body. */ + msg->request = request; + msg->result = result; + msg->instance = instance; + + /* Append custom data. */ + write_blocks( msg + 1, blocks, num_blocks ); + + + D_DEBUG_AT( Voodoo_Manager, " -> Sending RESPONSE message %llu (%s) with instance %u for request %llu (%d bytes).\n", + (unsigned long long)serial, DirectResultString( result ), instance, (unsigned long long)request, size ); + + /* Unlock the output buffer. */ + connection->PutPacket( packet, flush ); + + return DR_OK; +} + +DirectResult +VoodooManager::register_local( VoodooInstance *instance, + VoodooInstanceID *ret_instance ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + VoodooInstanceID instance_id; + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( instance != NULL ); + D_ASSERT( ret_instance != NULL ); + + instance->AddRef(); + + direct_mutex_lock( &instances.lock ); + + instance_id = ++instances.last; + + instances.local[instance_id] = instance; + + direct_mutex_unlock( &instances.lock ); + + D_DEBUG_AT( Voodoo_Manager, " -> Added local instance %u (%p)\n", instance_id, instance ); + + *ret_instance = instance_id; + + return DR_OK; +} + +DirectResult +VoodooManager::unregister_local( VoodooInstanceID instance_id ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + VoodooInstance *instance; + + D_MAGIC_ASSERT( this, VoodooManager ); + + direct_mutex_lock( &instances.lock ); + + InstanceMap::iterator itr = instances.local.find( instance_id ); + + if (itr == instances.local.end()) { + direct_mutex_unlock( &instances.lock ); + return DR_NOSUCHINSTANCE; + } + + instance = (*itr).second; + + instances.local.erase( itr ); + + direct_mutex_unlock( &instances.lock ); + + instance->Release(); + + return DR_OK; +} + +DirectResult +VoodooManager::lookup_local( VoodooInstanceID instance_id, + VoodooInstance **ret_instance ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + VoodooInstance *instance; + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( instance_id != VOODOO_INSTANCE_NONE ); + D_ASSERT( ret_instance != NULL ); + + direct_mutex_lock( &instances.lock ); + + InstanceMap::iterator itr = instances.local.find( instance_id ); + + direct_mutex_unlock( &instances.lock ); + + if (itr == instances.local.end()) + return DR_NOSUCHINSTANCE; + + instance = (*itr).second; + + // FIXME: addref? + + *ret_instance = instance; + + return DR_OK; +} + +DirectResult +VoodooManager::register_remote( VoodooInstance *instance, + VoodooInstanceID instance_id ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( instance != NULL ); + D_ASSERT( instance_id != VOODOO_INSTANCE_NONE ); + + instance->AddRef(); + + direct_mutex_lock( &instances.lock ); + + instances.remote[instance_id] = instance; + + direct_mutex_unlock( &instances.lock ); + + D_DEBUG_AT( Voodoo_Manager, " -> Added remote instance %u (%p)\n", instance_id, instance ); + + return DR_OK; +} + +DirectResult +VoodooManager::unregister_remote( VoodooInstanceID instance_id ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + VoodooInstance *instance; + + D_MAGIC_ASSERT( this, VoodooManager ); + + direct_mutex_lock( &instances.lock ); + + InstanceMap::iterator itr = instances.remote.find( instance_id ); + + if (itr == instances.remote.end()) { + direct_mutex_unlock( &instances.lock ); + return DR_NOSUCHINSTANCE; + } + + instance = (*itr).second; + + instances.remote.erase( itr ); + + direct_mutex_unlock( &instances.lock ); + + instance->Release(); + + return DR_OK; +} + +DirectResult +VoodooManager::lookup_remote( VoodooInstanceID instance_id, + VoodooInstance **ret_instance ) +{ + D_DEBUG_AT( Voodoo_Manager, "VoodooManager::%s( %p )\n", __func__, this ); + + VoodooInstance *instance; + + D_MAGIC_ASSERT( this, VoodooManager ); + D_ASSERT( instance_id != VOODOO_INSTANCE_NONE ); + D_ASSERT( ret_instance != NULL ); + + direct_mutex_lock( &instances.lock ); + + InstanceMap::iterator itr = instances.remote.find( instance_id ); + + direct_mutex_unlock( &instances.lock ); + + if (itr == instances.remote.end()) + return DR_NOSUCHINSTANCE; + + instance = (*itr).second; + + // FIXME: addref? + + *ret_instance = instance; + + return DR_OK; +} + +//} + diff --git a/Source/DirectFB/lib/voodoo/manager.h b/Source/DirectFB/lib/voodoo/manager.h new file mode 100755 index 0000000..ae3189b --- /dev/null +++ b/Source/DirectFB/lib/voodoo/manager.h @@ -0,0 +1,279 @@ +/* + (c) Copyright 2001-2011 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 __VOODOO__MANAGER_H__ +#define __VOODOO__MANAGER_H__ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#include +#include +} + +#include + +#include + + +typedef struct { + VoodooMessageBlockType type; + unsigned int len; + void *ptr; + u32 val; +} VoodooMessageBlock; + + +typedef std::map InstanceMap; + + +class VoodooDispatcher; + + +class VoodooContext { +public: + virtual DirectResult HandleSuper( VoodooManager *manager, + const char *name, + VoodooInstanceID *ret_instance ) = 0; +}; + + +class VoodooManager { +public: + int magic; + + bool is_quit; + +private: + friend class VoodooDispatcher; + + VoodooLink *link; + VoodooConnection *connection; + + VoodooContext *context; + + size_t msg_count; + VoodooMessageSerial msg_serial; + + struct { + DirectMutex lock; + InstanceMap local; + InstanceMap remote; + VoodooInstanceID last; + } instances; + + struct { + DirectMutex lock; + DirectWaitQueue wait_get; + DirectWaitQueue wait_put; + VoodooResponseMessage *current; + } response; + + + VoodooDispatcher *dispatcher; + + + +public: + VoodooManager( VoodooLink *link, + VoodooContext *context ); + ~VoodooManager(); + + + /** New API **/ + + void DispatchPacket ( VoodooPacket *packet ); + bool DispatchReady (); // FIXME: will be obsolete with GetPacket() method, called by connection code to read directly into packet + + + + /** Old API **/ + + void quit (); + + + void handle_disconnect (); + void handle_super ( VoodooSuperMessage *super ); + + void handle_request ( VoodooRequestMessage *request ); + void handle_response ( VoodooResponseMessage *response ); + + +private: + static void *dispatch_async_thread( DirectThread *thread, + void *arg ); + + + + +public: + DirectResult do_super ( const char *name, + VoodooInstanceID *ret_instance ); + + DirectResult do_request ( VoodooInstanceID instance, + VoodooMethodID method, + VoodooRequestFlags flags, + VoodooResponseMessage **ret_response, + VoodooMessageBlock *blocks = NULL, + size_t num_blocks = 0, + size_t data_size = 0 ); + + DirectResult next_response ( VoodooResponseMessage *response, + VoodooResponseMessage **ret_response ); + + DirectResult finish_request ( VoodooResponseMessage *response ); + + DirectResult do_respond ( bool flush, + VoodooMessageSerial request, + DirectResult result, + VoodooInstanceID instance = VOODOO_INSTANCE_NONE, + VoodooMessageBlock *blocks = NULL, + size_t num_blocks = 0, + size_t data_size = 0 ); + +private: + inline void write_blocks ( void *dst, + const VoodooMessageBlock *blocks, + size_t num_blocks ); + + DirectResult lock_response ( VoodooMessageSerial request, + VoodooResponseMessage **ret_response ); + + DirectResult unlock_response ( VoodooResponseMessage *response ); + + +public: + DirectResult register_local ( VoodooInstance *instance, + VoodooInstanceID *ret_instance ); + + DirectResult unregister_local ( VoodooInstanceID instance_id ); + + DirectResult lookup_local ( VoodooInstanceID instance_id, + VoodooInstance **ret_instance ); + + DirectResult register_remote ( VoodooInstance *instance, + VoodooInstanceID instance_id ); + + DirectResult unregister_remote ( VoodooInstanceID instance_id ); + + DirectResult lookup_remote ( VoodooInstanceID instance_id, + VoodooInstance **ret_instance ); +}; +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + +DirectResult VOODOO_API voodoo_manager_create ( VoodooLink *link, + VoodooClient *client, + VoodooServer *server, + VoodooManager **ret_manager ); + +DirectResult VOODOO_API voodoo_manager_quit ( VoodooManager *manager ); + +bool VOODOO_API voodoo_manager_is_closed ( const VoodooManager *manager ); + +DirectResult VOODOO_API voodoo_manager_destroy ( VoodooManager *manager ); + + +/* Super */ + +DirectResult VOODOO_API voodoo_manager_super ( VoodooManager *manager, + const char *name, + VoodooInstanceID *ret_instance ); + + +/* Request */ + +DirectResult VOODOO_API voodoo_manager_request ( VoodooManager *manager, + VoodooInstanceID instance, + VoodooMethodID method, + VoodooRequestFlags flags, + VoodooResponseMessage **ret_response, ... ); + +DirectResult VOODOO_API voodoo_manager_next_response ( VoodooManager *manager, + VoodooResponseMessage *response, + VoodooResponseMessage **ret_response ); + +DirectResult VOODOO_API voodoo_manager_finish_request ( VoodooManager *manager, + VoodooResponseMessage *response ); + + +/* Response */ + +DirectResult VOODOO_API voodoo_manager_respond ( VoodooManager *manager, + bool flush, + VoodooMessageSerial request, + DirectResult result, + VoodooInstanceID instance, ... ); + + +/* Instances */ + +DirectResult VOODOO_API voodoo_manager_register_local ( VoodooManager *manager, + VoodooInstanceID super, + void *dispatcher, + void *real, + VoodooDispatch dispatch, + VoodooInstanceID *ret_instance_id ); + +DirectResult VOODOO_API voodoo_manager_unregister_local( VoodooManager *manager, + VoodooInstanceID instance_id ); + +DirectResult VOODOO_API voodoo_manager_lookup_local ( VoodooManager *manager, + VoodooInstanceID instance, + void **ret_dispatcher, + void **ret_real ); + +DirectResult VOODOO_API voodoo_manager_register_remote( VoodooManager *manager, + bool super, + void *requestor, + VoodooInstanceID instance ); + +DirectResult VOODOO_API voodoo_manager_lookup_remote ( VoodooManager *manager, + VoodooInstanceID instance, + void **ret_requestor ); + + +/* Security */ + +DirectResult VOODOO_API voodoo_manager_check_allocation( VoodooManager *manager, + unsigned int amount ); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/Source/DirectFB/lib/voodoo/manager_c.cpp b/Source/DirectFB/lib/voodoo/manager_c.cpp new file mode 100755 index 0000000..7019da8 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/manager_c.cpp @@ -0,0 +1,553 @@ +/* + (c) Copyright 2001-2011 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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#include + +#include + +#include + +extern "C" { +#include +#include +#include + +#include +#include +} + +#include + + +D_DEBUG_DOMAIN( Voodoo_Manager, "Voodoo/Manager", "Voodoo Manager" ); + +/**********************************************************************************************************************/ + + +#define VOODOO_MANAGER_MESSAGE_BLOCKS_MAX 20 + +static __inline__ int +calc_blocks( va_list args, + VoodooMessageBlock *ret_blocks, size_t *ret_num ) +{ + int size = 4; /* for the terminating VMBT_NONE */ + size_t num = 0; + VoodooMessageBlockType type; + + /* Fetch first block type. */ + type = (VoodooMessageBlockType) va_arg( args, int ); + + while (type != VMBT_NONE) { + if (num == VOODOO_MANAGER_MESSAGE_BLOCKS_MAX) { + // FIXME: support more blocks? + D_UNIMPLEMENTED(); + break; + } + + /* Set message block type. */ + ret_blocks[num].type = type; + + switch (type) { + case VMBT_ID: + ret_blocks[num].len = 4; + ret_blocks[num].ptr = NULL; + ret_blocks[num].val = va_arg( args, u32 ); + + D_DEBUG( "Voodoo/Message: + ID %u\n", ret_blocks[num].val ); + break; + + case VMBT_INT: + ret_blocks[num].len = 4; + ret_blocks[num].ptr = NULL; + ret_blocks[num].val = va_arg( args, s32 ); + + D_DEBUG( "Voodoo/Message: + INT %d\n", ret_blocks[num].val ); + break; + + case VMBT_UINT: + ret_blocks[num].len = 4; + ret_blocks[num].ptr = NULL; + ret_blocks[num].val = va_arg( args, u32 ); + + D_DEBUG( "Voodoo/Message: + UINT %u\n", ret_blocks[num].val ); + break; + + case VMBT_DATA: + ret_blocks[num].len = va_arg( args, int ); + ret_blocks[num].ptr = va_arg( args, void * ); + +// D_ASSERT( ret_blocks[num].len > 0 ); + D_ASSERT( ret_blocks[num].ptr != NULL ); + + D_DEBUG( "Voodoo/Message: + DATA at %p with length %d\n", ret_blocks[num].ptr, ret_blocks[num].len ); + break; + + case VMBT_ODATA: + ret_blocks[num].len = va_arg( args, int ); + ret_blocks[num].ptr = va_arg( args, void * ); + + D_ASSERT( ret_blocks[num].len > 0 ); + + D_DEBUG( "Voodoo/Message: + ODATA at %p with length %d\n", ret_blocks[num].ptr, ret_blocks[num].len ); + + if (!ret_blocks[num].ptr) + ret_blocks[num].len = 0; + break; + + case VMBT_STRING: + ret_blocks[num].ptr = va_arg( args, char * ); + ret_blocks[num].len = strlen( (const char*) ret_blocks[num].ptr ) + 1; + + D_ASSERT( ret_blocks[num].ptr != NULL ); + + D_DEBUG( "Voodoo/Message: + STRING '%s' at %p with length %d\n", (char*) ret_blocks[num].ptr, ret_blocks[num].ptr, ret_blocks[num].len ); + break; + + default: + D_BREAK( "unknown message block type" ); + } + + /* Fetch next block type. */ + type = (VoodooMessageBlockType) va_arg( args, int ); + + size += 8 + VOODOO_MSG_ALIGN(ret_blocks[num].len); + + num++; + } + + *ret_num = num; + + return size; +} + + +/**********************************************************************************************************************/ +/**********************************************************************************************************************/ +/**********************************************************************************************************************/ +/* Old C API + */ + +/* + + +register add refs proxy +unregister releases proxy + +proxy destruct releases real + +*/ + +class VoodooInstanceInterface : public VoodooInstance { +public: + VoodooManager *manager; + VoodooInstance *super; + IAny *proxy; + IAny *real; + VoodooDispatch dispatch; + + + static std::list interfaces; + + +public: + VoodooInstanceInterface( VoodooManager *manager, + VoodooInstance *super, + IAny *proxy, + IAny *real, + VoodooDispatch dispatch ) + : + manager( manager ), + super( super ), + proxy( proxy ), + real( real ), + dispatch( dispatch ) + { + D_DEBUG_AT( Voodoo_Manager, "VoodooInstanceInterface::%s( %p, manager %p, super %p, proxy %p, real %p, dispatch %p )\n", + __func__, this, manager, super, proxy, real, dispatch ); + + if (super) + super->AddRef(); + + interfaces.push_back( this ); + } + +protected: + virtual ~VoodooInstanceInterface() + { + D_DEBUG_AT( Voodoo_Manager, "VoodooInstanceInterface::%s( %p )\n", __func__, this ); + + D_MAGIC_ASSERT( this, VoodooInstance ); + + if (proxy) { + D_DEBUG_AT( Voodoo_Manager, " -> releasing proxy interface\n" ); + + proxy->Release( proxy ); + } + + + if (super) { + D_DEBUG_AT( Voodoo_Manager, " -> releasing super instance\n" ); + + super->Release(); + } + + interfaces.remove( this ); + } + +public: + virtual DirectResult + Dispatch( VoodooManager *manager, + VoodooRequestMessage *msg ) + { + D_DEBUG_AT( Voodoo_Manager, "VoodooInstanceInterface::%s( %p, manager %p, msg %p )\n", __func__, this, manager, msg ); + + D_MAGIC_ASSERT( this, VoodooInstance ); + + D_ASSERT( dispatch != NULL ); + + return dispatch( proxy, real, manager, msg ); + } +}; + +std::list VoodooInstanceInterface::interfaces; + +/**********************************************************************************************************************/ + +class VoodooContextClassic : public VoodooContext { +private: + VoodooServer *server; + +public: + VoodooContextClassic( VoodooServer *server ) + : + server( server ) + { + } + + virtual DirectResult + HandleSuper( VoodooManager *manager, const char *name, VoodooInstanceID *ret_instance ) + { + return voodoo_server_construct( server, manager, name, ret_instance ); + } +}; + +DirectResult +voodoo_manager_create( VoodooLink *link, + VoodooClient *client, + VoodooServer *server, + VoodooManager **ret_manager ) +{ + D_ASSERT( ret_manager != NULL ); + + *ret_manager = new VoodooManager( link, new VoodooContextClassic( server ) ); // FIXME: leak + + return DR_OK; +} + +DirectResult +voodoo_manager_quit( VoodooManager *manager ) +{ + D_MAGIC_ASSERT( manager, VoodooManager ); + + manager->quit(); + + return DR_OK; +} + +DirectResult +voodoo_manager_destroy( VoodooManager *manager ) +{ + D_MAGIC_ASSERT( manager, VoodooManager ); + + delete manager; + + for (std::list::const_iterator iter = VoodooInstanceInterface::interfaces.begin(); + iter != VoodooInstanceInterface::interfaces.end(); iter++) + { + VoodooInstanceInterface *instance = *iter; + + if (instance->manager == manager) + D_INFO( "Zombie: Instance %p, proxy %p, real %p, super %p\n", instance, instance->proxy, instance->real, instance->super ); + } + + return DR_OK; +} + +bool +voodoo_manager_is_closed( const VoodooManager *manager ) +{ + D_MAGIC_ASSERT( manager, VoodooManager ); + + return manager->is_quit; +} + +/**************************************************************************************************/ + +DirectResult +voodoo_manager_super( VoodooManager *manager, + const char *name, + VoodooInstanceID *ret_instance ) +{ + D_MAGIC_ASSERT( manager, VoodooManager ); + + return manager->do_super( name, ret_instance ); +} + +DirectResult +voodoo_manager_request( VoodooManager *manager, + VoodooInstanceID instance, + VoodooMethodID method, + VoodooRequestFlags flags, + VoodooResponseMessage **ret_response, ... ) +{ + DirectResult ret; + + D_MAGIC_ASSERT( manager, VoodooManager ); + + va_list ap; + + va_start( ap, ret_response ); + + + VoodooMessageBlock blocks[VOODOO_MANAGER_MESSAGE_BLOCKS_MAX]; + size_t num_blocks; + size_t data_size; + + data_size = calc_blocks( ap, blocks, &num_blocks ); + + + ret = manager->do_request( instance, method, flags, ret_response, blocks, num_blocks, data_size ); + + va_end( ap ); + + return ret; +} + +DirectResult +voodoo_manager_next_response( VoodooManager *manager, + VoodooResponseMessage *response, + VoodooResponseMessage **ret_response ) +{ + D_MAGIC_ASSERT( manager, VoodooManager ); + + return manager->next_response( response, ret_response ); +} + +DirectResult +voodoo_manager_finish_request( VoodooManager *manager, + VoodooResponseMessage *response ) +{ + D_MAGIC_ASSERT( manager, VoodooManager ); + + return manager->finish_request( response ); +} + +DirectResult +voodoo_manager_respond( VoodooManager *manager, + bool flush, + VoodooMessageSerial request, + DirectResult result, + VoodooInstanceID instance, ... ) +{ + DirectResult ret; + + D_MAGIC_ASSERT( manager, VoodooManager ); + + va_list ap; + + va_start( ap, instance ); + + + VoodooMessageBlock blocks[VOODOO_MANAGER_MESSAGE_BLOCKS_MAX]; + size_t num_blocks; + size_t data_size; + + data_size = calc_blocks( ap, blocks, &num_blocks ); + + + ret = manager->do_respond( flush, request, result, instance, blocks, num_blocks, data_size ); + + va_end( ap ); + + return ret; +} + +DirectResult +voodoo_manager_register_local( VoodooManager *manager, + VoodooInstanceID super, + void *dispatcher, + void *real, + VoodooDispatch dispatch, + VoodooInstanceID *ret_instance ) +{ + DirectResult ret; + VoodooInstance *super_instance = NULL; + + D_MAGIC_ASSERT( manager, VoodooManager ); + + if (super != VOODOO_INSTANCE_NONE) { + ret = manager->lookup_local( super, &super_instance ); + if (ret) { + D_DERROR( ret, "Voodoo/Manager: Could not lookup super instance %u!\n", super ); + return ret; + } + } + + + VoodooInstanceInterface *instance = new VoodooInstanceInterface( manager, super_instance, (IAny*) dispatcher, (IAny*) real, dispatch ); + + ret = manager->register_local( instance, ret_instance ); + + instance->Release(); + + return ret; +} + +DirectResult +voodoo_manager_unregister_local( VoodooManager *manager, + VoodooInstanceID instance_id ) +{ + D_MAGIC_ASSERT( manager, VoodooManager ); + + return manager->unregister_local( instance_id ); +} + +DirectResult +voodoo_manager_lookup_local( VoodooManager *manager, + VoodooInstanceID instance_id, + void **ret_dispatcher, + void **ret_real ) +{ + DirectResult ret; + VoodooInstance *instance; + + D_MAGIC_ASSERT( manager, VoodooManager ); + + ret = manager->lookup_local( instance_id, &instance ); + if (ret) + return ret; + + if (ret_dispatcher) + *ret_dispatcher = ((VoodooInstanceInterface*) instance)->proxy; + + if (ret_real) + *ret_real = ((VoodooInstanceInterface*) instance)->real; + + return DR_OK; +} + +DirectResult +voodoo_manager_register_remote( VoodooManager *manager, + bool super, + void *requestor, + VoodooInstanceID instance_id ) +{ + DirectResult ret; + + D_MAGIC_ASSERT( manager, VoodooManager ); + + VoodooInstanceInterface *instance = new VoodooInstanceInterface( manager, NULL, (IAny*) requestor, NULL, NULL); + + ret = manager->register_remote( instance, instance_id ); + + instance->Release(); + + return ret; +} + + +DirectResult +voodoo_manager_lookup_remote( VoodooManager *manager, + VoodooInstanceID instance_id, + void **ret_requestor ) +{ + DirectResult ret; + VoodooInstance *instance; + + D_MAGIC_ASSERT( manager, VoodooManager ); + + ret = manager->lookup_remote( instance_id, &instance ); + if (ret) + return ret; + + if (ret_requestor) + *ret_requestor = ((VoodooInstanceInterface*) instance)->proxy; + + return DR_OK; +} + +DirectResult +voodoo_manager_check_allocation( VoodooManager *manager, + unsigned int amount ) +{ +#ifndef WIN32 + FILE *f; + char buf[2000]; + int size; + char *p; + size_t bytes; + + D_MAGIC_ASSERT( manager, VoodooManager ); + + if (!voodoo_config->memory_max) + return DR_OK; + + direct_snprintf( buf, sizeof(buf), "/proc/%d/status", direct_getpid() ); + + f = fopen( buf, "r" ); + if (!f) { + D_ERROR( "Could not open '%s'!\n", buf ); + return DR_FAILURE; + } + + bytes = fread( buf, 1, sizeof(buf)-1, f ); + + fclose( f ); + + if (bytes) { + buf[bytes] = 0; + + p = strstr( buf, "VmRSS:" ); + if (!p) { + D_ERROR( "Could not find memory information!\n" ); + return DR_FAILURE; + } + + sscanf( p + 6, " %u", &size ); + + D_INFO( "SIZE: %u kB (+%u kB)\n", size, amount / 1024 ); + + if (size * 1024 + amount > voodoo_config->memory_max) + return DR_LIMITEXCEEDED; + } +#endif + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/message.h b/Source/DirectFB/lib/voodoo/message.h new file mode 100755 index 0000000..514b3bc --- /dev/null +++ b/Source/DirectFB/lib/voodoo/message.h @@ -0,0 +1,258 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 __VOODOO__MESSAGE_H__ +#define __VOODOO__MESSAGE_H__ + +#include + +#include +#include + + +#define VOODOO_MSG_ALIGN(i) (((i) + 3) & ~3) + +typedef enum { + VMBT_NONE, + VMBT_ID, + VMBT_INT, + VMBT_UINT, + VMBT_DATA, + VMBT_ODATA, + VMBT_STRING +} VoodooMessageBlockType; + +typedef enum { + VREQ_NONE = 0x00000000, + VREQ_RESPOND = 0x00000001, + VREQ_ASYNC = 0x00000002, + VREQ_QUEUE = 0x00000004 +} VoodooRequestFlags; + +typedef enum { + VMSG_SUPER, + VMSG_REQUEST, + VMSG_RESPONSE, + + VMSG_DISCOVER, // temporary solution for compatibility + VMSG_SENDINFO, // temporary solution for compatibility +} VoodooMessageType; + + +struct __V_VoodooMessageHeader { + int size; + VoodooMessageSerial serial; + u32 type; +}; + + +struct __V_VoodooSuperMessage { + VoodooMessageHeader header; +}; + +struct __V_VoodooRequestMessage { + VoodooMessageHeader header; + + VoodooInstanceID instance; + VoodooMethodID method; + + u32 flags; +}; + +struct __V_VoodooResponseMessage { + VoodooMessageHeader header; + + VoodooMessageSerial request; + DirectResult result; + + VoodooInstanceID instance; +}; + + +typedef struct { + int magic; + + const void *msg; + const void *ptr; +} VoodooMessageParser; + + + +#define __VOODOO_PARSER_PROLOG( parser, req_type ) \ + const void *_vp_ptr; \ + VoodooMessageBlockType _vp_type; \ + int _vp_length; \ + \ + D_MAGIC_ASSERT( &(parser), VoodooMessageParser ); \ + \ + _vp_ptr = (parser).ptr; \ + \ + /* Read message block type. */ \ + _vp_type = *(const u32*) _vp_ptr; \ + \ + D_ASSERT( _vp_type == (req_type) ); \ + \ + /* Read data block length. */ \ + _vp_length = *(const s32*) (_vp_ptr + 4) + + +#define __VOODOO_PARSER_EPILOG( parser ) \ + /* Advance message data pointer. */ \ + (parser).ptr += 8 + VOODOO_MSG_ALIGN(_vp_length) + + +#define VOODOO_PARSER_BEGIN( parser, message ) \ + do { \ + const VoodooMessageHeader *_vp_header = (const VoodooMessageHeader *) (message); \ + \ + D_ASSERT( (message) != NULL ); \ + D_ASSERT( _vp_header->type == VMSG_REQUEST || _vp_header->type == VMSG_RESPONSE ); \ + \ + (parser).msg = (message); \ + (parser).ptr = (parser).msg + (_vp_header->type == VMSG_REQUEST ? \ + sizeof(VoodooRequestMessage) : sizeof(VoodooResponseMessage)); \ + \ + D_MAGIC_SET_ONLY( &(parser), VoodooMessageParser ); \ + } while (0) + + +#define VOODOO_PARSER_GET_ID( parser, ret_id ) \ + do { \ + __VOODOO_PARSER_PROLOG( parser, VMBT_ID ); \ + \ + D_ASSERT( _vp_length == 4 ); \ + \ + /* Read the ID. */ \ + (ret_id) = *(const u32*) (_vp_ptr + 8); \ + \ + __VOODOO_PARSER_EPILOG( parser ); \ + } while (0) + +#define VOODOO_PARSER_GET_INT( parser, ret_int ) \ + do { \ + __VOODOO_PARSER_PROLOG( parser, VMBT_INT ); \ + \ + D_ASSERT( _vp_length == 4 ); \ + \ + /* Read the integer. */ \ + (ret_int) = *(const s32*) (_vp_ptr + 8); \ + \ + __VOODOO_PARSER_EPILOG( parser ); \ + } while (0) + +#define VOODOO_PARSER_GET_UINT( parser, ret_uint ) \ + do { \ + __VOODOO_PARSER_PROLOG( parser, VMBT_UINT ); \ + \ + D_ASSERT( _vp_length == 4 ); \ + \ + /* Read the unsigned integer. */ \ + (ret_uint) = *(const u32*) (_vp_ptr + 8); \ + \ + __VOODOO_PARSER_EPILOG( parser ); \ + } while (0) + +#define VOODOO_PARSER_GET_DATA( parser, ret_data ) \ + do { \ + __VOODOO_PARSER_PROLOG( parser, VMBT_DATA ); \ + \ + D_ASSERT( _vp_length > 0 ); \ + \ + /* Return pointer to data. */ \ + (ret_data) = _vp_ptr + 8; \ + \ + __VOODOO_PARSER_EPILOG( parser ); \ + } while (0) + +#define VOODOO_PARSER_READ_DATA( parser, dst, max_len ) \ + do { \ + __VOODOO_PARSER_PROLOG( parser, VMBT_DATA ); \ + \ + D_ASSERT( _vp_length > 0 ); \ + D_ASSERT( _vp_length <= max_len ); \ + \ + /* Copy data block. */ \ + direct_memcpy( (dst), _vp_ptr + 8, _vp_length ); \ + \ + __VOODOO_PARSER_EPILOG( parser ); \ + } while (0) + +#define VOODOO_PARSER_COPY_DATA( parser, ret_data ) \ + do { \ + __VOODOO_PARSER_PROLOG( parser, VMBT_DATA ); \ + \ + D_ASSERT( _vp_length > 0 ); \ + \ + /* Allocate memory on the stack. */ \ + (ret_data) = alloca( _vp_length ); \ + \ + /* Copy data block. */ \ + direct_memcpy( (ret_data), _vp_ptr + 8, _vp_length ); \ + \ + __VOODOO_PARSER_EPILOG( parser ); \ + } while (0) + +#define VOODOO_PARSER_GET_ODATA( parser, ret_data ) \ + do { \ + __VOODOO_PARSER_PROLOG( parser, VMBT_ODATA ); \ + \ + D_ASSERT( _vp_length >= 0 ); \ + \ + /* Return pointer to data or NULL. */ \ + if (_vp_length) \ + (ret_data) = _vp_ptr + 8; \ + else \ + (ret_data) = NULL; \ + \ + __VOODOO_PARSER_EPILOG( parser ); \ + } while (0) + +#define VOODOO_PARSER_GET_STRING( parser, ret_string ) \ + do { \ + __VOODOO_PARSER_PROLOG( parser, VMBT_STRING ); \ + \ + D_ASSERT( _vp_length > 0 ); \ + \ + /* Return pointer to string. */ \ + (ret_string) = (const char*) (_vp_ptr + 8); \ + \ + __VOODOO_PARSER_EPILOG( parser ); \ + } while (0) + + +#define VOODOO_PARSER_END( parser ) \ + do { \ + D_MAGIC_ASSERT( &(parser), VoodooMessageParser ); \ + \ + D_ASSUME( *(const u32*) ((parser).ptr) == VMBT_NONE ); \ + \ + D_MAGIC_CLEAR( &(parser) ); \ + } while (0) + + +#endif diff --git a/Source/DirectFB/lib/voodoo/mutex.c b/Source/DirectFB/lib/voodoo/mutex.c new file mode 100755 index 0000000..dcc287d --- /dev/null +++ b/Source/DirectFB/lib/voodoo/mutex.c @@ -0,0 +1,105 @@ +/* + (c) Copyright 2001-2008 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 "mutex.h" + +/**********************************************************************************************************************/ + +DirectResult +direct_mutex_init( DirectMutex *mutex ) +{ + if (pthread_mutex_init( &mutex->lock, NULL )) + return errno2result( errno ); + + return DR_OK; +} + +DirectResult +direct_recursive_mutex_init( DirectMutex *mutex ) +{ + DirectResult ret = DR_OK; + int result; + pthread_mutexattr_t attr; + + pthread_mutexattr_init( &attr ); +#if HAVE_DECL_PTHREAD_MUTEX_RECURSIVE + pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE ); +#endif + result = pthread_mutex_init( &mutex->lock, &attr ); + if (result) { + ret = errno2result( errno ); + D_PERROR( "Direct/Mutex: Could not initialize recursive mutex!\n" ); + } + + pthread_mutexattr_destroy( &attr ); + + return (DirectResult) ret; +} + +__attribute__((no_instrument_function)) +DirectResult +direct_mutex_lock( DirectMutex *mutex ) +{ + if (pthread_mutex_lock( &mutex->lock )) + return errno2result( errno ); + + return DR_OK; +} + +__attribute__((no_instrument_function)) +DirectResult +direct_mutex_unlock( DirectMutex *mutex ) +{ + if (pthread_mutex_unlock( &mutex->lock )) + return errno2result( errno ); + + return DR_OK; +} + +DirectResult +direct_mutex_trylock( DirectMutex *mutex ) +{ + if (pthread_mutex_trylock( &mutex->lock )) + return errno2result( errno ); + + return DR_OK; +} + +DirectResult +direct_mutex_deinit( DirectMutex *mutex ) +{ + if (pthread_mutex_destroy( &mutex->lock )) + return errno2result( errno ); + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/mutex.h b/Source/DirectFB/lib/voodoo/mutex.h new file mode 100755 index 0000000..fa520fd --- /dev/null +++ b/Source/DirectFB/lib/voodoo/mutex.h @@ -0,0 +1,142 @@ +/* + (c) Copyright 2001-2008 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 __DIRECT__OS__LINUX__GLIBC__MUTEX_H__ +#define __DIRECT__OS__LINUX__GLIBC__MUTEX_H__ + +#include + +#include + + +#define _ZU "%zu" +#define _ZD "%zd" + + +/**********************************************************************************************************************/ + +typedef struct { + pthread_mutex_t lock; +} DirectMutex; + +/**********************************************************************************************************************/ + +#define DIRECT_MUTEX_INITIALIZER(name) { PTHREAD_MUTEX_INITIALIZER } +#define DIRECT_RECURSIVE_MUTEX_INITIALIZER(name) { PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP } + + +DirectResult direct_mutex_init ( DirectMutex *mutex ); + +DirectResult direct_recursive_mutex_init ( DirectMutex *mutex ); + +DirectResult direct_mutex_lock ( DirectMutex *mutex ); + +DirectResult direct_mutex_unlock ( DirectMutex *mutex ); + +DirectResult direct_mutex_trylock ( DirectMutex *mutex ); + +DirectResult direct_mutex_deinit ( DirectMutex *mutex ); + + +/**********************************************************************************************************************/ +/**********************************************************************************************************************/ + +typedef struct { + pthread_key_t key; +} DirectTLS; + +/**********************************************************************************************************************/ + +#define DIRECT_TLS_DATA( name ) \ + static DirectTLS name = { (pthread_key_t) -1 } + +/**********************************************************************************************************************/ + +__attribute__((no_instrument_function)) +static inline void *direct_tls_get__( DirectTLS *tls ); + +__attribute__((no_instrument_function)) +static inline DirectResult direct_tls_set__( DirectTLS *tls, + void *value ); + +__attribute__((no_instrument_function)) +static inline DirectResult direct_tls_register( DirectTLS *tls, + void (*destructor)( void* ) ); + +__attribute__((no_instrument_function)) +static inline DirectResult direct_tls_unregister( DirectTLS *tls ); + +/**********************************************************************************************************************/ + +#define direct_tls_get( name ) direct_tls_get__( &name ) +#define direct_tls_set( name, v ) direct_tls_set__( &name, v ) + +/**********************************************************************************************************************/ + +static inline void * +direct_tls_get__( DirectTLS *tls ) +{ + void *value; + + value = pthread_getspecific( tls->key ); + + return value; +} + +static inline DirectResult +direct_tls_set__( DirectTLS *tls, + void *value ) +{ + if (pthread_setspecific( tls->key, value )) + return errno2result( errno ); + + return DR_OK; +} + +static inline DirectResult +direct_tls_register( DirectTLS *tls, void (*destructor)( void* ) ) +{ + if (pthread_key_create( &tls->key, destructor )) + return errno2result( errno ); + + return DR_OK; +} + +static inline DirectResult +direct_tls_unregister( DirectTLS *tls ) +{ + if (pthread_key_delete( tls->key )) + return errno2result( errno ); + + tls->key = (pthread_key_t) -1; + + return DR_OK; +} + +#endif + diff --git a/Source/DirectFB/lib/voodoo/packet.h b/Source/DirectFB/lib/voodoo/packet.h new file mode 100755 index 0000000..3f97071 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/packet.h @@ -0,0 +1,285 @@ +/* + (c) Copyright 2001-2011 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 __VOODOO__PACKET_H__ +#define __VOODOO__PACKET_H__ + +extern "C" { +#include +#include +#include +#include + + +#include +} + + +typedef enum { + VPHF_NONE = 0x00000000, + + VPHF_COMPRESSED = 0x00000001, + + VPHF_ALL = 0x00000001 +} VoodooPacketHeaderFlags; + + +typedef struct { + u32 size; + u32 flags; + u32 uncompressed; + u32 align; +} VoodooPacketHeader; + + +class VoodooPacket { +public: + DirectLink link; + bool sending; + +private: + void *data; + void *current; + VoodooPacketHeader header; + + VoodooPacket( u32 size, + void *data ) + : + sending(false), + data(data), + current(data) + { + memset( &link, 0, sizeof(link) ); + + header.size = size; + header.flags = VPHF_NONE; + header.uncompressed = size; + } + + VoodooPacket( u32 size, + u32 flags, + u32 uncompressed, + void *data ) + : + sending(false), + data(data), + current(data) + { + memset( &link, 0, sizeof(link) ); + + header.size = size; + header.flags = VPHF_COMPRESSED; + header.uncompressed = uncompressed; + } + + ~VoodooPacket() {}; + +public: +/* + static VoodooPacket * + New( u32 size ) + { + VoodooPacket *packet = (VoodooPacket*) D_MALLOC( sizeof(VoodooPacket) + size ); + + if (!packet) { + D_OOM(); + return NULL; + } + + return new (packet) VoodooPacket( size, packet + 1 ); + + + if (data) + this->data = data; + else + this->data = header + 1; + } +*/ + static VoodooPacket * + New( u32 size, + void *data ) + { + return new VoodooPacket( size, data ); + } + + static VoodooPacket * + Reset( VoodooPacket *packet, + u32 size, + void *data ) + { + return new (packet) VoodooPacket( size, data ); + } + + static VoodooPacket * + New( void *header, + u32 size ) + { + VoodooPacketHeader *h = (VoodooPacketHeader*) header; + + h->size = size; + h->flags = VPHF_NONE; + h->uncompressed = size; + + return new VoodooPacket( size, (char*) header + sizeof(VoodooPacketHeader) ); + } + + static VoodooPacket * + New( u32 size ) + { + VoodooPacket *p = (VoodooPacket*) D_MALLOC( sizeof(VoodooPacket) + VOODOO_PACKET_MAX ); + + if (!p) { + D_OOM(); + return NULL; + } + + return new (p) VoodooPacket( size, p + 1 ); + } + + static VoodooPacket * + Compressed( VoodooPacket *packet ) + { + VoodooPacket *p = (VoodooPacket*) D_MALLOC( sizeof(VoodooPacket) + packet->header.size * 4 / 3 ); + + if (!p) { + D_OOM(); + return NULL; + } + + int compressed = direct_fastlz_compress( packet->data, packet->header.uncompressed, p + 1 ); + + if ((size_t) compressed < packet->header.uncompressed) + return new (p) VoodooPacket( compressed, VPHF_COMPRESSED, packet->header.uncompressed, p + 1 ); + + D_FREE( p ); + + return packet; + } + + static VoodooPacket * + Copy( VoodooPacket *packet ) + { + VoodooPacket *p = (VoodooPacket*) D_MALLOC( sizeof(VoodooPacket) + packet->header.size ); + + if (!p) { + D_OOM(); + return NULL; + } + + direct_memcpy( p + 1, packet->data_start(), packet->header.size ); + + return new (p) VoodooPacket( packet->header.size, packet->header.flags, packet->header.uncompressed, p + 1 ); + } + + static VoodooPacket * + Copy( u32 size, + u32 flags, + u32 uncompressed, + void *data ) + { + VoodooPacket *p = (VoodooPacket*) D_MALLOC( sizeof(VoodooPacket) + size ); + + if (!p) { + D_OOM(); + return NULL; + } + + direct_memcpy( p + 1, data, size ); + + return new (p) VoodooPacket( size, flags, uncompressed, p + 1 ); + } + + inline u32 + size() const + { + return header.size; + } + + inline u32 + flags() const + { + return header.flags; + } + + inline u32 + uncompressed() const + { + return header.uncompressed; + } + + inline const void * + data_header() const + { + D_ASSERT( data == this + 1 ); + + return &header; + } + + inline const void * + data_start() const + { + return data; + } + + inline void * + data_raw() const + { + return current; + } + + + inline bool + append( size_t size ) + { + D_ASSERT( data == this + 1 ); + + if (header.size + size > VOODOO_PACKET_MAX) + return false; + + current = (char*) data + header.size; + + header.size += size; + header.uncompressed += size; + + return true; + } + + inline void + reset( size_t size ) + { + D_ASSERT( data == this + 1 ); + + current = (char*) data; + + header.size = size; + header.uncompressed = size; + } +}; + + +#endif diff --git a/Source/DirectFB/lib/voodoo/play.c b/Source/DirectFB/lib/voodoo/play.c new file mode 100755 index 0000000..a262472 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/play.c @@ -0,0 +1,935 @@ +/* + (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 +#include +#include +#include + +#ifdef MACOS +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) +#endif + +D_DEBUG_DOMAIN( Voodoo_Play, "Voodoo/Play", "Voodoo Play" ); + +/**********************************************************************************************************************/ + +typedef struct { + DirectLink link; + + VoodooPlayVersion version; + VoodooPlayInfo info; + + long long last_seen; + long long broadcast; + + char addr[64]; +} PlayerNode; + +/**********************************************************************************************************************/ + +static void player_send_info( VoodooPlayer *player, + const in_addr_t *in_addr, + bool discover ); + +static void *player_main_loop( DirectThread *thread, + void *arg ); + +/**********************************************************************************************************************/ + +static const int one = 1; + +VoodooPlayVersion g_VoodooPlay_version; +VoodooPlayInfo g_VoodooPlay_info; + +/**********************************************************************************************************************/ + +static VoodooPlayer *g_VoodooPlayer; + +/**********************************************************************************************************************/ + +/* + * FIXME + */ +static void +generate_uuid( u8 *buf ) +{ + int i; + + srand( direct_clock_get_abs_micros() ); + + for (i=0; i<16; i++) { + buf[i] = rand(); + } +} + +/**********************************************************************************************************************/ + +pthread_mutex_t gplayermut = PTHREAD_MUTEX_INITIALIZER; + + +DirectResult createSocketForPlayer (int * retfd) +{ + int fd = -1; + *retfd = -1; + DirectResult ret; + struct sockaddr_in addr; + D_INFO("Voodoo/Player: Creating the Socket for player 0x%08x\n",(int) g_VoodooPlayer); + /* Create the player socket. */ + fd = socket( PF_INET, SOCK_DGRAM, 0 ); + if (fd < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Player: Could not create the socket via socket()!\n" ); + + return ret; + } + + /* Allow reuse of local address. */ + if (setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Player: Could not set SO_REUSEADDR!\n" ); + + if (setsockopt( fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Player: Could not set SO_BROADCAST!\n" ); + + /* Bind the socket to the local port. */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr( "0.0.0.0" ); + addr.sin_port = htons( 2323 ); + + if (bind( fd, (struct sockaddr*) &addr, sizeof(addr) )) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Player: Could not bind() the socket!\n" ); + close( fd ); + + return ret; + } + + *retfd = fd; + return DR_OK; + + +} + + +DirectResult +voodoo_player_create( const VoodooPlayInfo *info, + VoodooPlayer **ret_player ) +{ + DirectResult ret; + int fd; + + VoodooPlayer *player; + pthread_mutex_lock(&gplayermut); + D_ASSERT( ret_player != NULL ); + + if (g_VoodooPlayer) { + *ret_player = g_VoodooPlayer; + pthread_mutex_unlock(&gplayermut); + return DR_OK; + } + + ret = createSocketForPlayer(&fd); + if ( ret != DR_OK) + { + pthread_mutex_unlock(&gplayermut); + return ret; + + } + + + + /* Allocate player structure. */ + player = D_CALLOC( 1, sizeof(VoodooPlayer) ); + if (!player) { + D_WARN( "out of memory" ); + close( fd ); + pthread_mutex_unlock(&gplayermut); + return DR_NOLOCALMEMORY; + } + + pthread_mutex_init( &player->lock, NULL ); + + /* Initialize player structure. */ + player->fd = fd; + + /* Fill version struct */ + player->version.v[0] = VPVF_LITTLE_ENDIAN | VPVF_32BIT_SERIALS; + player->version.v[1] = DIRECTFB_MAJOR_VERSION; + player->version.v[2] = DIRECTFB_MINOR_VERSION; + player->version.v[3] = DIRECTFB_MICRO_VERSION; + + /* Fill info struct */ + direct_snputs( player->info.name, voodoo_config->play_info.name, VOODOO_PLAYER_NAME_LENGTH ); + direct_snputs( player->info.vendor, voodoo_config->play_info.vendor, VOODOO_PLAYER_VENDOR_LENGTH ); + direct_snputs( player->info.model, voodoo_config->play_info.model, VOODOO_PLAYER_MODEL_LENGTH ); + direct_memcpy( player->info.uuid, voodoo_config->play_info.uuid, 16 ); + + if (info) + player->info = *info; + + if (!player->info.name[0]) + direct_snputs( player->info.name, "Unnamed Player", VOODOO_PLAYER_NAME_LENGTH ); + + if (!player->info.vendor[0]) + direct_snputs( player->info.vendor, "Unknown Vendor", VOODOO_PLAYER_VENDOR_LENGTH ); + + if (!player->info.model[0]) + direct_snputs( player->info.model, "Unknown Model", VOODOO_PLAYER_MODEL_LENGTH ); + + if (!player->info.uuid[0]) + generate_uuid( player->info.uuid ); + + player->info.flags |= VPIF_LINK; + + D_MAGIC_SET( player, VoodooPlayer ); + + + g_VoodooPlay_version = player->version; + g_VoodooPlay_info = player->info; + + + char buf[33]; + + snprintf( buf, sizeof(buf), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + player->info.uuid[0], player->info.uuid[1], player->info.uuid[2], player->info.uuid[3], player->info.uuid[4], + player->info.uuid[5], player->info.uuid[6], player->info.uuid[7], player->info.uuid[8], player->info.uuid[9], + player->info.uuid[10], player->info.uuid[11], player->info.uuid[12], player->info.uuid[13], player->info.uuid[14], + player->info.uuid[15] ); + + D_INFO( "Running player '%s' with UUID %s!\n", player->info.name, buf ); + + /* Start messaging thread */ + player->thread = direct_thread_create( DTT_DEFAULT, player_main_loop, player, "Voodoo/Player" ); + + /* Return the new player. */ + *ret_player = player; + + if (!g_VoodooPlayer) + g_VoodooPlayer = player; + + pthread_mutex_unlock(&gplayermut); + return DR_OK; +} + +DirectResult +voodoo_player_destroy( VoodooPlayer *player ) +{ + pthread_mutex_lock(&gplayermut); + D_MAGIC_ASSERT( player, VoodooPlayer ); + + if (g_VoodooPlayer == player) + { + pthread_mutex_unlock(&gplayermut); + return DR_OK; + } + D_INFO("Voodoo/Player: Destroying the player 0x%08x\n",(int) player); + player->quit = true; + + direct_thread_join( player->thread ); + direct_thread_destroy( player->thread ); + + close( player->fd ); + + pthread_mutex_destroy( &player->lock ); + + D_MAGIC_CLEAR( player ); + + D_FREE( player ); + g_VoodooPlayer = NULL; + pthread_mutex_unlock(&gplayermut); + return DR_OK; +} + +DirectResult +voodoo_player_broadcast( VoodooPlayer *player ) +{ +#if !VOODOO_PLAY_FAKE + int ret; +#ifdef MACOS + char *ptr, lastname[IFNAMSIZ]; +#else + int i; +#endif + struct ifreq req[16]; + struct ifconf conf; + + D_MAGIC_ASSERT( player, VoodooPlayer ); + + player->broadcast++; + + conf.ifc_buf = (char*) req; + conf.ifc_len = sizeof(req); + + ret = ioctl( player->fd, SIOCGIFCONF, &conf ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFCONF ) failed!\n" ); + return DR_FAILURE; + } + +#ifdef MACOS + // TIV: On iPhone (and I believe in general on BSD, you can't just plainly iterate on struct size) + + lastname[0] = 0; + + for (ptr = conf.ifc_buf; ptr < conf.ifc_buf + conf.ifc_len; ) + { + char buf[100]; + int len, flags; + struct ifreq ifrcopy, *ifr = (struct ifreq *)ptr; + struct sockaddr_in *addr = (struct sockaddr_in*) &ifr->ifr_broadaddr; + + len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); + ptr += sizeof(ifr->ifr_name) + len; // for next one in buffer + + if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) + { + continue; /* already processed this interface */ + } + + memcpy(lastname, ifr->ifr_name, IFNAMSIZ); + + ifrcopy = *ifr; + ioctl( player->fd, SIOCGIFFLAGS, &ifrcopy); + flags = ifrcopy.ifr_flags; + if ((flags & IFF_UP) == 0) + { + D_INFO( "Voodoo/Player: %-16s is not up.\n", ifrcopy.ifr_name ); + continue; // ignore if interface not up + } + + ret = ioctl( player->fd, SIOCGIFBRDADDR, ifr ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFBRDADDR ) %-16s failed!\n", ifr->ifr_name ); + continue; + } + + if (addr->sin_addr.s_addr) { + inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s)\n", ifr->ifr_name, buf ); + } + else { + ret = ioctl( player->fd, SIOCGIFDSTADDR, ifr ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFDSTADDR ) failed!\n" ); + continue; + } + + inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s) (P-t-P)\n", ifr->ifr_name, buf ); + } + + player_send_info( player, &addr->sin_addr.s_addr, true ); + } +#else + D_INFO( "Voodoo/Player: Detected %d interfaces\n", conf.ifc_len/sizeof(req[0]) ); + + for (i=0; ifd, SIOCGIFBRDADDR, &req[i] ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFBRDADDR ) failed!\n" ); + continue; + } + + if (addr->sin_addr.s_addr) { + inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s)\n", req[i].ifr_name, buf ); + } + else { + ret = ioctl( player->fd, SIOCGIFDSTADDR, &req[i] ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFDSTADDR ) failed!\n" ); + continue; + } + + inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s) (P-t-P)\n", req[i].ifr_name, buf ); + } + + //addr->sin_addr.s_addr = inet_addr( "192.168.1.150" ); + //addr->sin_addr.s_addr = inet_addr( "192.168.255.255" ); + + player_send_info( player, &addr->sin_addr.s_addr, true ); + } +#endif +#endif + + return DR_OK; +} + +DirectResult +voodoo_player_lookup( VoodooPlayer *player, + const u8 uuid[16], + VoodooPlayInfo *ret_info, + char *ret_addr, + int max_addr ) +{ + PlayerNode *node; + + D_MAGIC_ASSERT( player, VoodooPlayer ); + + pthread_mutex_lock( &player->lock ); + + direct_list_foreach (node, player->nodes) { + if (!uuid || !memcmp( node->info.uuid, uuid, 16 )) { + if (ret_info) + direct_memcpy( ret_info, &node->info, sizeof(VoodooPlayInfo) ); + + if (ret_addr) + direct_snputs( ret_addr, node->addr, max_addr ); + + pthread_mutex_unlock( &player->lock ); + return DR_OK; + } + } + + if (uuid && !memcmp( player->info.uuid, uuid, 16 )) { + if (ret_info) + direct_memcpy( ret_info, &player->info, sizeof(VoodooPlayInfo) ); + + if (ret_addr) + direct_snputs( ret_addr, "127.0.0.1", max_addr ); + + pthread_mutex_unlock( &player->lock ); + return DR_OK; + } + + pthread_mutex_unlock( &player->lock ); + + return DR_ITEMNOTFOUND; +} + +DirectResult +voodoo_player_lookup_by_address( VoodooPlayer *player, + const char *addr, + VoodooPlayInfo *ret_info ) +{ + PlayerNode *node; + + D_MAGIC_ASSERT( player, VoodooPlayer ); + + pthread_mutex_lock( &player->lock ); + + direct_list_foreach (node, player->nodes) { + if (!addr || !strcmp( node->addr, addr )) { + direct_memcpy( ret_info, &node->info, sizeof(VoodooPlayInfo) ); + + pthread_mutex_unlock( &player->lock ); + return DR_OK; + } + } + + if (addr && !strcmp( "127.0.0.1", addr )) { + direct_memcpy( ret_info, &player->info, sizeof(VoodooPlayInfo) ); + + pthread_mutex_unlock( &player->lock ); + return DR_OK; + } + + pthread_mutex_unlock( &player->lock ); + + return DR_ITEMNOTFOUND; +} + +DirectResult +voodoo_player_enumerate( VoodooPlayer *player, + VoodooPlayerCallback callback, + void *ctx ) +{ + PlayerNode *node; + long long now = direct_clock_get_abs_millis(); + + + D_MAGIC_ASSERT( player, VoodooPlayer ); + + pthread_mutex_lock( &player->lock ); + + direct_list_foreach (node, player->nodes) { + if (node->broadcast != player->broadcast && direct_clock_get_abs_millis() - node->last_seen > 1000) + continue; + + if (callback( ctx, &node->info, &node->version, + node->addr, now - node->last_seen ) == DENUM_CANCEL) + break; + } + + pthread_mutex_unlock( &player->lock ); + + return DR_OK; +} + +/**********************************************************************************************************************/ + +__attribute__((unused)) +static void +player_send_info( VoodooPlayer *player, + const in_addr_t *in_addr, + bool discover ) +{ + int ret; + struct sockaddr_in addr; + VoodooPlayMessage msg; + PlayerNode *node; + + D_MAGIC_ASSERT( player, VoodooPlayer ); + + msg.version = player->version; + msg.type = discover ? VPMT_DISCOVER : VPMT_SENDINFO; + msg.info = player->info; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = *in_addr; + addr.sin_port = htons( 2323 ); + + ret = sendto( player->fd, &msg, sizeof(msg), 0, (struct sockaddr*) &addr, sizeof(addr) ); + if (ret < 0) { + D_PERROR( "Voodoo/Player: sendto() failed!\n" ); + return; + } + + if (!discover && voodoo_config->forward_nodes) { + direct_list_foreach (node, player->nodes) { + VoodooPlayInfo info = node->info; + + info.flags |= VPIF_LEVEL2; + + msg.version = node->version; + msg.type = discover ? VPMT_DISCOVER : VPMT_SENDINFO; + msg.info = info; + + ret = sendto( player->fd, &msg, sizeof(msg), 0, (struct sockaddr*) &addr, sizeof(addr) ); + if (ret < 0) { + D_PERROR( "Voodoo/Player: sendto() failed!\n" ); + return; + } + } + } +} + +static void +player_save_info( VoodooPlayer *player, + const VoodooPlayMessage *msg, + const char *addr ) +{ + PlayerNode *node; + + D_MAGIC_ASSERT( player, VoodooPlayer ); + + direct_list_foreach (node, player->nodes) { + if (!memcmp( node->info.uuid, msg->info.uuid, 16 )) { + if (msg->info.flags & VPIF_LEVEL2 && !(node->info.flags & VPIF_LEVEL2)) { + node->version = msg->version; + node->info = msg->info; + + direct_snputs( node->addr, addr, sizeof(node->addr) ); + } + node->version = msg->version; + node->info = msg->info; + + node->last_seen = direct_clock_get_abs_millis(); + node->broadcast = player->broadcast; + + direct_snputs( node->addr, addr, sizeof(node->addr) ); + + return; + + } + } + + node = D_CALLOC( 1, sizeof(PlayerNode) ); + if (!node) { + D_OOM(); + return; + } + + node->version = msg->version; + node->info = msg->info; + + node->last_seen = direct_clock_get_abs_millis(); + node->broadcast = player->broadcast; + + direct_snputs( node->addr, addr, sizeof(node->addr) ); + + + direct_list_append( &player->nodes, &node->link ); +} + +#if !VOODOO_PLAY_FAKE +static void * +player_main_loop( DirectThread *thread, void *arg ) +{ + VoodooPlayer *player = arg; + int ret; + struct sockaddr_in addr; + socklen_t addr_len = sizeof(addr); + VoodooPlayMessage msg; + char buf[100]; + + D_MAGIC_ASSERT( player, VoodooPlayer ); + + while (!player->quit) { + struct pollfd pf; + + pf.fd = player->fd; + pf.events = POLLIN; + + switch (poll( &pf, 1, 100 )) { + default: + ret = recvfrom( player->fd, &msg, sizeof(msg), 0, (struct sockaddr*) &addr, &addr_len ); + if (ret < 0) { + D_PERROR( "Voodoo/Player: recvfrom() failed!\n" ); + close(player->fd); + ret = createSocketForPlayer(&player->fd); + + continue; + } + + inet_ntop( AF_INET, &addr.sin_addr, buf, sizeof(buf) ); + + pthread_mutex_lock( &player->lock ); + + /* Send reply if message is not from ourself */ + if (memcmp( msg.info.uuid, player->info.uuid, 16 )) { + switch (msg.type) { + case VPMT_DISCOVER: + D_INFO( "Voodoo/Player: Received DISCOVER from '%s' (%s)\n", msg.info.name, buf ); + player_send_info( player, &addr.sin_addr.s_addr, false ); + break; + + case VPMT_SENDINFO: + D_INFO( "Voodoo/Player: Received SENDINFO from '%s' (%s)\n", msg.info.name, buf ); + player_save_info( player, &msg, buf ); + break; + + default: + D_ERROR( "Voodoo/Player: Received unknown message (%s)\n", buf ); + break; + } + } + else + D_INFO( "Voodoo/Player: Received message from ourself (%s)\n", buf ); + + pthread_mutex_unlock( &player->lock ); + break; + + case 0: + D_DEBUG( "Voodoo/Player: Timeout during poll()\n" ); + break; + + case -1: + if (errno != EINTR) { + D_PERROR( "Voodoo/Player: Could not poll() the socket!\n" ); + close(player->fd); + ret = createSocketForPlayer(&player->fd); + // player->quit = true; + } + break; + } + } + + return DR_OK; +} +#else + +static DirectResult +send_discover_and_receive_info( int fd, + VoodooPlayVersion *ret_version, + VoodooPlayInfo *ret_info ) +{ + int ret; + VoodooMessageHeader header; + + D_INFO( "Voodoo/Player: Sending VMSG_DISCOVER message via Voodoo TCP port...\n" ); + + header.size = sizeof(VoodooMessageHeader); + header.serial = 0; + header.type = VMSG_DISCOVER; + + ret = write( fd, &header, sizeof(header) ); + if (ret < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Player: Failed to send VMSG_DISCOVER message via Voodoo TCP port!\n" ); + return ret; + } + + + + struct pollfd pfd; + + pfd.events = POLL_IN; + pfd.fd = fd; + + // wait for up to one second (old server will not reply anything, so we have to timeout) + ret = poll( &pfd, 1, 1000 ); + if (ret < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Player: Failed to wait for reply after sending VMSG_DISCOVER message via Voodoo TCP port!\n" ); + return ret; + } + + if (ret == 0) { + D_INFO( "Voodoo/Player: Old Voodoo Server without VMSG_DISCOVER support (timeout waiting for reply)\n" ); + return DR_UNSUPPORTED; + } + + D_INFO( "Voodoo/Player: New Voodoo Server with VMSG_DISCOVER support, reading version/info (SENDINFO) reply...\n" ); + + + struct { + VoodooMessageHeader header; + VoodooPlayVersion version; + VoodooPlayInfo info; + } msg; + + size_t got = 0; + + while (got < sizeof(msg)) { + ret = read( fd, (void*) &msg + got, sizeof(msg) - got ); + if (ret < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Player: Failed to read after sending VMSG_DISCOVER message via Voodoo TCP port!\n" ); + return ret; + } + + got += ret; + } + + + if (msg.header.type != VMSG_SENDINFO) { + D_ERROR( "Voodoo/Player: Received message after sending VMSG_DISCOVER message via Voodoo TCP port is no VMSG_SENDINFO!\n"); + return DR_INVARG; + } + + *ret_version = msg.version; + *ret_info = msg.info; + + D_INFO( "Voodoo/Player: Voodoo Server sent name '%s', version %d.%d.%d\n", + msg.info.name, msg.version.v[1], msg.version.v[2], msg.version.v[3] ); + + return DR_OK; +} + +static void +player_try_connect( VoodooPlayer *player, + u32 addr ) +{ + DirectResult ret; + int fd, err; + struct in_addr sin_addr = { addr }; + + char buf[100]; + + inet_ntop( AF_INET, &sin_addr, buf, sizeof(buf) ); + + + /* Create the client socket. */ + fd = socket( AF_INET, SOCK_STREAM, 0 ); + if (fd < 0) { + D_PERROR( "Voodoo/Player: Could not create the socket via socket( %d )!\n", AF_INET ); + return; + } + + struct sockaddr_in sock_addr; + + sock_addr.sin_family = AF_INET; + sock_addr.sin_port = htons( 2323 ); + sock_addr.sin_addr = sin_addr; + + /* Connect to the server. */ + err = connect( fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr) ); + if (err) { + D_PERROR( "Voodoo/Player: No Voodoo at '%s:2323'", buf ); + close( fd ); + return; + } + + D_INFO( "Voodoo/Player: Found Voodoo at '%s'!\n", buf ); + + + VoodooPlayMessage msg; + + + ret = send_discover_and_receive_info( fd, &msg.version, &msg.info ); + if (ret) { + /* Fill version struct */ + msg.version.v[0] = VPVF_LITTLE_ENDIAN | VPVF_32BIT_SERIALS; + msg.version.v[1] = DIRECTFB_MAJOR_VERSION; + msg.version.v[2] = DIRECTFB_MINOR_VERSION; + msg.version.v[3] = DIRECTFB_MICRO_VERSION; + + msg.type = VPMT_SENDINFO; + + /* Fill info struct */ + direct_snputs( msg.info.name, "Unknown", VOODOO_PLAYER_NAME_LENGTH ); + direct_snputs( msg.info.vendor, "Unknown", VOODOO_PLAYER_VENDOR_LENGTH ); + direct_snputs( msg.info.model, "Unknown", VOODOO_PLAYER_MODEL_LENGTH ); + generate_uuid( msg.info.uuid ); + } + + + close( fd ); + + + pthread_mutex_lock( &player->lock ); + + player_save_info( player, &msg, buf ); + + pthread_mutex_unlock( &player->lock ); +} + +typedef struct { + VoodooPlayer *player; + u32 addr; +} PlayerTryContext; + +static void * +player_try_thread( void *arg ) +{ + PlayerTryContext *context = arg; + + player_try_connect( context->player, context->addr ); + + D_FREE( context ); + + return NULL; +} + +static void * +player_main_loop( DirectThread *thread, void *arg ) +{ + VoodooPlayer *player = arg; + int ret; + int i; + struct ifreq req[16]; + struct ifconf conf; + + D_MAGIC_ASSERT( player, VoodooPlayer ); + +// while (!player->quit) { + conf.ifc_buf = (char*) req; + conf.ifc_len = sizeof(req); + + ret = ioctl( player->fd, SIOCGIFCONF, &conf ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFCONF ) failed!\n" ); + return NULL; + } + + D_INFO( "Voodoo/Player: Detected %d interfaces\n", conf.ifc_len/sizeof(req[0]) ); + + for (i=0; ifd, SIOCGIFBRDADDR, &req[i] ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFBRDADDR ) failed!\n" ); + continue; + } + + if (addr->sin_addr.s_addr) { + inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s) [0x%08x]\n", req[i].ifr_name, buf, addr->sin_addr.s_addr ); + + u32 _addr = htonl( addr->sin_addr.s_addr ); + u32 a; + + for (a = (_addr & ~0xff) + 1; a < (_addr | 0xff); a++) { + if (a == _addr) + continue; + + PlayerTryContext *context = D_CALLOC( 1, sizeof(PlayerTryContext) ); + + context->player = player; + context->addr = ntohl(a); + + + pthread_t t; + + pthread_create( &t, NULL, player_try_thread, context ); + } + } + else { + ret = ioctl( player->fd, SIOCGIFDSTADDR, &req[i] ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFDSTADDR ) failed!\n" ); + continue; + } + + inet_ntop( AF_INET, &addr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s) (P-t-P)\n", req[i].ifr_name, buf ); + } + } +// } + + return DR_OK; +} +#endif + diff --git a/Source/DirectFB/lib/voodoo/play.h b/Source/DirectFB/lib/voodoo/play.h new file mode 100755 index 0000000..1dc50df --- /dev/null +++ b/Source/DirectFB/lib/voodoo/play.h @@ -0,0 +1,146 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 __VOODOO__PLAY_H__ +#define __VOODOO__PLAY_H__ + +#include + + +#define VOODOO_PLAY_VERSION_FIXED_SIZE 32 + +#define VOODOO_PLAYER_NAME_LENGTH 96 + +#define VOODOO_PLAYER_VENDOR_LENGTH 96 +#define VOODOO_PLAYER_MODEL_LENGTH 96 + + +#define VOODOO_LINK_PORT 8676 // 'V' 'L' + + +typedef enum { + VPVF_NONE = 0x00000000, + + VPVF_LITTLE_ENDIAN = 0x00000001, /* Always set, no big endian support for now */ + VPVF_32BIT_SERIALS = 0x00000002, /* Using 32bit message serials, always set */ + + VPVF_ALL = 0x00000007 +} VoodooPlayVersionFlags; + +typedef struct { + u8 v[4]; /* flags, major, minor, micro */ +} VoodooPlayVersion; + + +typedef enum { + VPIF_NONE = 0x00000000, + + VPIF_LEVEL2 = 0x00000001, + VPIF_LINK = 0x00000002, /* Supports new VoodooLink protocol */ + + VPIF_ALL = 0x00000003 +} VoodooPlayInfoFlags; + +typedef struct { + VoodooPlayInfoFlags flags; + + u8 uuid[16]; + + char name[VOODOO_PLAYER_NAME_LENGTH]; /* "My Philips TV" */ + + char vendor[VOODOO_PLAYER_VENDOR_LENGTH]; /* "Philips Consumer Lifestyle" */ + char model[VOODOO_PLAYER_MODEL_LENGTH]; /* "32PFL9604H/10" */ +} VoodooPlayInfo; + + +typedef enum { + VPMT_INVALID, + + VPMT_DISCOVER, + VPMT_SENDINFO, +} VoodooPlayMessageType; + + + +/* + + One play message on a new connection from both sides. + Both sides having received the other side's info know if the connection is to be closed or can succeed. + + Game about endianness conversion: both sides randomly send 0 or 1 as part of the info, + if both are equal, then server converts, otherwise client +*/ + +typedef struct { + /* Version information first in structure, fixed size (union!) */ + union { + char __fixed[VOODOO_PLAY_VERSION_FIXED_SIZE]; + + + VoodooPlayVersion version; /* (1.0, ...) */ + }; + + VoodooPlayMessageType type; + + union { + VoodooPlayInfo info; /* DISCOVER, SENDINFO */ + }; +} VoodooPlayMessage; + + +typedef DirectEnumerationResult (*VoodooPlayerCallback)( void *ctx, + const VoodooPlayInfo *info, + const VoodooPlayVersion *version, + const char *address, + unsigned int ms_since_last_seen ); + + +DirectResult voodoo_player_create ( const VoodooPlayInfo *info, + VoodooPlayer **ret_player ); + +DirectResult voodoo_player_destroy ( VoodooPlayer *player ); + +DirectResult voodoo_player_broadcast ( VoodooPlayer *player ); + +DirectResult voodoo_player_lookup ( VoodooPlayer *player, + const u8 uuid[16], + VoodooPlayInfo *ret_info, + char *ret_addr, + int max_addr ); + +DirectResult voodoo_player_lookup_by_address( VoodooPlayer *player, + const char *addr, + VoodooPlayInfo *ret_info ); + +DirectResult voodoo_player_enumerate ( VoodooPlayer *player, + VoodooPlayerCallback callback, + void *ctx ); + + +#endif + diff --git a/Source/DirectFB/lib/voodoo/play_internal.h b/Source/DirectFB/lib/voodoo/play_internal.h new file mode 100755 index 0000000..0aa0f91 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/play_internal.h @@ -0,0 +1,89 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 __VOODOO__PLAY_INTERNAL_H__ +#define __VOODOO__PLAY_INTERNAL_H__ + +#include +#include +#include + +#include +#include + + +struct __V_VoodooPlayer { + int magic; + + int fd; + + pthread_mutex_t lock; + + bool quit; + + VoodooPlayVersion version; + VoodooPlayInfo info; + + DirectThread *thread; + + DirectLink *nodes; + + long long broadcast; + + VoodooServer *server; + + const VoodooAppDescription *apps; + unsigned int num_apps; + + VoodooPlayerLaunchFunc launch_func; + VoodooPlayerStopFunc stop_func; + void *ctx; + + DirectLink *instances; + pthread_mutex_t instances_lock; + pthread_cond_t instances_cond; +}; + + +typedef struct { + DirectLink link; + + u8 uuid[16]; + + void *data; + + VoodooAppDescription app; + u8 player_uuid[16]; +} VoodooAppInstance; + + +extern VoodooPlayVersion g_VoodooPlay_version; +extern VoodooPlayInfo g_VoodooPlay_info; + + +#endif diff --git a/Source/DirectFB/lib/voodoo/play_server.c b/Source/DirectFB/lib/voodoo/play_server.c new file mode 100755 index 0000000..1e933f5 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/play_server.c @@ -0,0 +1,430 @@ +/* + (c) Copyright 2001-2010 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 +#include +#include +#include + +D_DEBUG_DOMAIN( Voodoo_Play_Server, "Voodoo/Play/Server", "Voodoo Play Server" ); + +/**********************************************************************************************************************/ + +VoodooPlayer *voodoo_player; + +/**********************************************************************************************************************/ +/* + * FIXME + */ +static void +generate_uuid( u8 *buf ) +{ + int i; + + for (i=0; i<16; i++) { + buf[i] = rand(); + } +} + +static DirectResult +ConstructDispatcher( VoodooServer *server, + VoodooManager *manager, + const char *name, + void *ctx, + VoodooInstanceID *ret_instance ) +{ + DirectResult ret; + DirectInterfaceFuncs *funcs; + void *interface; + VoodooInstanceID instance; + + D_ASSERT( server != NULL ); + D_ASSERT( manager != NULL ); + D_ASSERT( name != NULL ); + D_ASSERT( ret_instance != NULL ); + + ret = DirectGetInterface( &funcs, name, "Dispatcher", NULL, NULL ); + if (ret) + return ret; + + ret = funcs->Allocate( &interface ); + if (ret) + return ret; + + ret = funcs->Construct( interface, manager, &instance ); + if (ret) + return ret; + + *ret_instance = instance; + + return DR_OK; +} + +/**********************************************************************************************************************/ + +DirectResult +voodoo_player_run_server( VoodooPlayer *player, + const VoodooAppDescription *apps, + unsigned int num_apps, + VoodooPlayerLaunchFunc launch_func, + VoodooPlayerStopFunc stop_func, + void *ctx ) +{ + DirectResult ret; + VoodooServer *server; + + D_ASSERT( player != NULL ); + D_ASSERT( apps != NULL ); + D_ASSERT( num_apps > 0 ); + D_ASSERT( launch_func != NULL ); + + if (voodoo_player) { + D_ERROR( "Voodoo/Play: Already running as a server!\n" ); + return DR_BUSY; + } + + ret = voodoo_server_create( &server ); + if (ret) + return ret; + + ret = voodoo_server_register( server, "IVoodooPlayer", ConstructDispatcher, NULL ); + if (ret) { + D_ERROR( "Voodoo/Player: Could not register super interface 'IVoodooPlayer'!\n" ); + voodoo_server_destroy( server ); + return ret; + } + + player->server = server; + player->apps = apps; + player->num_apps = num_apps; + player->launch_func = launch_func; + player->stop_func = stop_func; + player->ctx = ctx; + + pthread_mutex_init( &player->instances_lock, NULL ); + pthread_cond_init( &player->instances_cond, NULL ); + + voodoo_player = player; + + ret = voodoo_server_run( server, false ); + if (ret) + D_DERROR( ret, "Voodoo/Player: Server exiting!\n" ); + + voodoo_player = NULL; + + player->server = NULL; + player->apps = NULL; + player->num_apps = 0; + player->launch_func = NULL; + player->stop_func = NULL; + player->ctx = NULL; + player->instances = NULL; + + pthread_mutex_destroy( &player->instances_lock ); + pthread_cond_destroy( &player->instances_cond ); + + voodoo_server_destroy( server ); + + return ret; +} + +DirectResult +voodoo_player_get_apps( VoodooPlayer *player, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppDescription *ret_apps ) +{ + D_ASSERT( player != NULL ); + D_ASSERT( ret_num != NULL ); + D_ASSERT( ret_apps != NULL ); + + /// + + unsigned int num = max_num; + + if (num > player->num_apps) + num = player->num_apps; + + *ret_num = num; + + direct_memcpy( ret_apps, player->apps, sizeof(VoodooAppDescription) * num ); + + return DR_OK; +} + +DirectResult +voodoo_player_launch_app( VoodooPlayer *player, + const u8 app_uuid[16], + const u8 player_uuid[16], + u8 ret_instance_uuid[16] ) +{ + DirectResult ret; + int i; + + D_ASSERT( player != NULL ); + D_ASSERT( app_uuid != NULL ); + D_ASSERT( player_uuid != NULL ); + D_ASSERT( ret_instance_uuid != NULL ); + + + char buf1[33]; + char buf2[33]; + + snprintf( buf1, sizeof(buf1), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + app_uuid[0], app_uuid[1], app_uuid[2], app_uuid[3], app_uuid[4], + app_uuid[5], app_uuid[6], app_uuid[7], app_uuid[8], app_uuid[9], + app_uuid[10], app_uuid[11], app_uuid[12], app_uuid[13], app_uuid[14], + app_uuid[15] ); + + snprintf( buf2, sizeof(buf2), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + player_uuid[0], player_uuid[1], player_uuid[2], player_uuid[3], player_uuid[4], + player_uuid[5], player_uuid[6], player_uuid[7], player_uuid[8], player_uuid[9], + player_uuid[10], player_uuid[11], player_uuid[12], player_uuid[13], player_uuid[14], + player_uuid[15] ); + + D_INFO( "Voodoo/Player: Launching application %s on %s...\n", buf1, buf2 ); + + + const VoodooAppDescription *app = NULL; + + for (i=0; inum_apps; i++) { + if (!memcmp( app_uuid, player->apps[i].uuid, 16 )) { + app = &player->apps[i]; + break; + } + } + + if (!app) { + D_ERROR( "Voodoo/Player: Could not lookup application with UUID %s!\n", buf1 ); + return DR_ITEMNOTFOUND; + } + + + VoodooPlayInfo info; + char addr[1000]; + + + voodoo_player_broadcast( player ); + sleep( 1 ); + + ret = voodoo_player_lookup( player, player_uuid, &info, addr, sizeof(addr) ); + if (ret) { + if ( (player_uuid[0]==0xf0) && (player_uuid[1]==0xf0) && (player_uuid[2]==0xf0) && (player_uuid[3]==0xf0) + && (player_uuid[4]==0xf0) && (player_uuid[5]==0xf0) && (player_uuid[6]==0xf0) && (player_uuid[7]==0xf0) + && (player_uuid[8]==0xf0) && (player_uuid[9]==0xf0) && (player_uuid[10]==0xf0) && (player_uuid[11]==0xf0) ) + { + sprintf(addr, "%d.%d.%d.%d", player_uuid[12], player_uuid[13], player_uuid[14], player_uuid[15]); + } + else + { + D_DERROR( ret, "Voodoo/Player: Could not lookup player with UUID %s!\n", buf2 ); + return ret; + } + } + + + VoodooAppInstance *instance; + + instance = D_CALLOC( 1, sizeof(VoodooAppInstance) ); + if (!instance) + return D_OOM(); + + ret = player->launch_func( player, player->ctx, app, &info, addr, &instance->data ); + if (ret) { + D_DERROR( ret, "Voodoo/Player: Could not launch application '%s'\n", app->name ); + D_FREE( instance ); + return ret; + } + + generate_uuid( instance->uuid ); + + direct_memcpy( &instance->app, app, sizeof(VoodooAppDescription) ); + direct_memcpy( instance->player_uuid, player_uuid, 16 ); + + + + pthread_mutex_lock( &player->instances_lock ); + + direct_list_append( &player->instances, &instance->link ); + + direct_memcpy( ret_instance_uuid, instance->uuid, 16 ); + + pthread_mutex_unlock( &player->instances_lock ); + + + return DR_OK; +} + +DirectResult +voodoo_player_stop_instance( VoodooPlayer *player, + const u8 instance_uuid[16] ) +{ + DirectResult ret; + char buf1[33]; + VoodooAppInstance *instance; + + snprintf( buf1, sizeof(buf1), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + instance_uuid[0], instance_uuid[1], instance_uuid[2], instance_uuid[3], instance_uuid[4], + instance_uuid[5], instance_uuid[6], instance_uuid[7], instance_uuid[8], instance_uuid[9], + instance_uuid[10], instance_uuid[11], instance_uuid[12], instance_uuid[13], instance_uuid[14], + instance_uuid[15] ); + + D_INFO( "Voodoo/Player: Stopping instance %s...\n", buf1 ); + + pthread_mutex_lock( &player->instances_lock ); + + direct_list_foreach (instance, player->instances) { + if (!memcmp( instance->uuid, instance_uuid, 16 )) + break; + } + + if (!instance) { + D_ERROR( "Voodoo/Player: Could not find instance with UUID %s!\n", buf1 ); + pthread_mutex_unlock( &player->instances_lock ); + return DR_NOSUCHINSTANCE; + } + + ret = player->stop_func( player, player->ctx, instance->data ); + if (ret) { + D_DERROR( ret, "Voodoo/Player: Could not stop instance with UUID %s!\n", buf1 ); + pthread_mutex_unlock( &player->instances_lock ); + return ret; + } + + direct_list_remove( &player->instances, &instance->link ); + + pthread_cond_broadcast( &player->instances_cond ); + + pthread_mutex_unlock( &player->instances_lock ); + + D_FREE( instance ); + + return DR_OK; +} + +DirectResult +voodoo_player_wait_instance( VoodooPlayer *player, + const u8 instance_uuid[16] ) +{ + char buf1[33]; + VoodooAppInstance *instance; + + snprintf( buf1, sizeof(buf1), "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", + instance_uuid[0], instance_uuid[1], instance_uuid[2], instance_uuid[3], instance_uuid[4], + instance_uuid[5], instance_uuid[6], instance_uuid[7], instance_uuid[8], instance_uuid[9], + instance_uuid[10], instance_uuid[11], instance_uuid[12], instance_uuid[13], instance_uuid[14], + instance_uuid[15] ); + + D_INFO( "Voodoo/Player: Waiting for instance %s...\n", buf1 ); + + + do { + pthread_mutex_lock( &player->instances_lock ); + + direct_list_foreach (instance, player->instances) { + if (!memcmp( instance->uuid, instance_uuid, 16 )) { + pthread_cond_wait( &player->instances_cond, &player->instances_lock ); + break; + } + } + + pthread_mutex_unlock( &player->instances_lock ); + } while (instance); + + return DR_OK; +} + +DirectResult +voodoo_player_get_instances( VoodooPlayer *player, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppInstanceDescription *ret_instances ) +{ + VoodooAppInstance *instance; + + D_ASSERT( player != NULL ); + D_ASSERT( ret_num != NULL ); + D_ASSERT( ret_instances != NULL ); + + /// + + pthread_mutex_lock( &player->instances_lock ); + + unsigned int i = 0; + + direct_list_foreach (instance, player->instances) { + if (i == max_num) + break; + + direct_memcpy( ret_instances[i].uuid, instance->uuid, 16 ); + direct_memcpy( &ret_instances[i].app, &instance->app, sizeof(VoodooAppDescription) ); + direct_memcpy( ret_instances[i].player_uuid, instance->player_uuid, 16 ); + + i++; + } + + *ret_num = i; + + pthread_mutex_unlock( &player->instances_lock ); + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/play_server.h b/Source/DirectFB/lib/voodoo/play_server.h new file mode 100755 index 0000000..9677e7e --- /dev/null +++ b/Source/DirectFB/lib/voodoo/play_server.h @@ -0,0 +1,79 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 __VOODOO__PLAY_SERVER_H__ +#define __VOODOO__PLAY_SERVER_H__ + +#include +#include + + +typedef DirectResult (*VoodooPlayerLaunchFunc)( VoodooPlayer *player, + void *ctx, + const VoodooAppDescription *app, + const VoodooPlayInfo *player_info, + const char *player_addr, + void **ret_data ); + +typedef DirectResult (*VoodooPlayerStopFunc) ( VoodooPlayer *player, + void *ctx, + void *data ); + + +DirectResult voodoo_player_run_server ( VoodooPlayer *player, + const VoodooAppDescription *apps, + unsigned int num_apps, + VoodooPlayerLaunchFunc launch_func, + VoodooPlayerStopFunc stop_func, + void *ctx ); + +DirectResult voodoo_player_get_apps ( VoodooPlayer *player, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppDescription *ret_apps ); + +DirectResult voodoo_player_launch_app ( VoodooPlayer *player, + const u8 app_uuid[16], + const u8 player_uuid[16], + u8 ret_instance_uuid[16] ); + +DirectResult voodoo_player_stop_instance( VoodooPlayer *player, + const u8 instance_uuid[16] ); + +DirectResult voodoo_player_wait_instance( VoodooPlayer *player, + const u8 instance_uuid[16] ); + +DirectResult voodoo_player_get_instances( VoodooPlayer *player, + unsigned int max_num, + unsigned int *ret_num, + VoodooAppInstanceDescription *ret_instances ); + + +extern VoodooPlayer *voodoo_player; + +#endif diff --git a/Source/DirectFB/lib/voodoo/server.c b/Source/DirectFB/lib/voodoo/server.c new file mode 100755 index 0000000..0c543b6 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/server.c @@ -0,0 +1,459 @@ +/* + (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 +#include + + +typedef struct { + sem_t sem; + + pid_t gfxpid; +} ServerShared; + +typedef struct { + DirectLink link; + + VoodooLink vl; + VoodooManager *manager; +} Connection; + +typedef struct { + const char *name; + VoodooSuperConstruct func; + void *ctx; + + IAny *interface; +} Super; + +#define MAX_SUPER 8 + +struct __V_VoodooServer { + int fd; + + bool quit; + DirectLink *connections; + + int num_super; + Super supers[MAX_SUPER]; + + ServerShared *shared; +}; + +/**************************************************************************************************/ + +static DirectResult accept_connection( VoodooServer *server, int fd ); + +/**************************************************************************************************/ + +static const int one = 1; + +/**************************************************************************************************/ + +DirectResult +voodoo_server_create( VoodooServer **ret_server ) +{ + DirectResult ret; + struct sockaddr_in addr; + int fd = -1; + VoodooServer *server = NULL; + + D_ASSERT( ret_server != NULL ); + + /* Create the server socket. */ + fd = socket( PF_INET, SOCK_STREAM, 0 ); + if (fd < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Could not create the socket via socket()!\n" ); + goto error; + } + + /* Allow reuse of local address. */ + if (setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Server: Could not set SO_REUSEADDR!\n" ); + + /* Bind the socket to the local port. */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = inet_addr( "0.0.0.0" ); + addr.sin_port = htons( 2323 ); + + if (bind( fd, &addr, sizeof(addr) )) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Could not bind() the socket!\n" ); + goto error; + } + + /* Start listening. */ + if (listen( fd, 4 )) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Could not listen() to the socket!\n" ); + goto error; + } + + /* Allocate server structure. */ + server = D_CALLOC( 1, sizeof(VoodooServer) ); + if (!server) { + ret = D_OOM(); + D_WARN( "out of memory" ); + goto error; + } + + /* Initialize server structure. */ + server->fd = fd; + + { + int zfd; + + zfd = open( "/dev/zero", O_RDWR ); + if (zfd < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Failed to open /dev/zero!\n" ); + goto error; + } + + server->shared = mmap( NULL, sizeof(ServerShared), PROT_READ | PROT_WRITE, MAP_SHARED, zfd, 0 ); + + close( zfd ); + + if (server->shared == MAP_FAILED) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Failed to mmap /dev/zero!\n" ); + server->shared = NULL; + goto error; + } + + if (sem_init( &server->shared->sem, 1, 1 )) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Server: Failed to create process shared semaphore!\n" ); + goto error; + } + } + + /* Return the new server. */ + *ret_server = server; + + return DR_OK; + + +error: + if (server) { + if (server->shared) + munmap( server->shared, sizeof(ServerShared) ); + + D_FREE( server ); + } + + if (fd >= 0) + close( fd ); + + return ret; +} + +DirectResult +voodoo_server_register( VoodooServer *server, + const char *name, + VoodooSuperConstruct func, + void *ctx ) +{ + Super *super; + + D_ASSERT( server != NULL ); + D_ASSERT( name != NULL ); + D_ASSERT( func != NULL ); + + if (server->num_super == MAX_SUPER) + return DR_LIMITEXCEEDED; + + super = &server->supers[server->num_super++]; + + super->name = name; + super->func = func; + super->ctx = ctx; + + return DR_OK; +} + +static inline Super * +lookup_super( VoodooServer *server, + const char *name ) +{ + int i; + + D_ASSERT( server != NULL ); + D_ASSERT( name != NULL ); + + for (i=0; inum_super; i++) { + Super *super = &server->supers[i]; + + if (! strcmp( name, super->name )) + return super; + } + + return NULL; +} + +DirectResult +voodoo_server_construct( VoodooServer *server, + VoodooManager *manager, + const char *name, + VoodooInstanceID *ret_instance ) +{ + DirectResult ret; + Super *super; + VoodooInstanceID instance; + + D_ASSERT( server != NULL ); + D_ASSERT( manager != NULL ); + D_ASSERT( name != NULL ); + D_ASSERT( ret_instance != NULL ); + + super = lookup_super( server, name ); + if (!super) { + D_ERROR( "Voodoo/Server: Super interface '%s' is not available!\n", name ); + return DR_UNSUPPORTED; + } + + if (!strcmp( name, "IDirectFB" )) { + sem_wait( &server->shared->sem ); + + if (server->shared->gfxpid) { + D_INFO( "Voodoo/Server: Killing previous graphics process with pid %d\n", server->shared->gfxpid ); + kill( server->shared->gfxpid, SIGTERM ); + } + + server->shared->gfxpid = getpid(); + + D_INFO( "Voodoo/Server: New graphics process has pid %d\n", server->shared->gfxpid ); + + sem_post( &server->shared->sem ); + } + + ret = super->func( server, manager, name, super->ctx, &instance ); + if (ret) { + D_ERROR( "Voodoo/Server: " + "Creating super interface '%s' failed (%s)!\n", name, DirectResultString(ret) ); + return ret; + } + + *ret_instance = instance; + + return DR_OK; +} + +DirectResult +voodoo_server_run( VoodooServer *server, + bool forking ) +{ + DirectLink *l, *n; + struct pollfd pf; + bool listener = true; + + D_ASSERT( server != NULL ); + + while (!server->quit) { + /* Cleanup dead connections. */ + direct_list_foreach_safe (l, n, server->connections) { + Connection *connection = (Connection*) l; + + if (voodoo_manager_is_closed( connection->manager )) { + sem_wait( &server->shared->sem ); + + if (server->shared->gfxpid == getpid()) { + D_INFO( "Voodoo/Server: Closing graphics process with pid %d\n", server->shared->gfxpid ); + server->shared->gfxpid = 0; + } + + sem_post( &server->shared->sem ); + + + voodoo_manager_destroy( connection->manager ); + + //connection->vl.Close( &connection->vl ); + + direct_list_remove( &server->connections, l ); + + D_INFO( "Voodoo/Server: Closed connection.\n" ); + + D_FREE( connection ); + + if (forking && !server->connections) + return DR_OK; + } + } + + if (listener) { + int i; + int fd; + struct sockaddr addr; + socklen_t addrlen = sizeof(addr); + + pf.fd = server->fd; + pf.events = POLLIN; + + switch (poll( &pf, 1, 200 )) { + default: + fd = accept( server->fd, &addr, &addrlen ); + if (fd < 0) { + D_PERROR( "Voodoo/Server: Could not accept() incoming connection!\n" ); + break; + } + + if (forking) { + switch (fork()) { + case 0: + listener = false; + + for (i=3; i<65535; i++) { + if (i != fd) + close( i ); + } + + accept_connection( server, fd ); + break; + + case -1: + D_PERROR( "Voodoo/Server: Could not fork()!\n" ); + break; + + default: + close( fd ); + break; + } + } + else { + accept_connection( server, fd ); + } + break; + + case 0: + waitpid( -1, NULL, WNOHANG ); + + D_DEBUG( "Voodoo/Server: Timeout during poll()\n" ); + break; + + case -1: + if (errno != EINTR) { + D_PERROR( "Voodoo/Server: Could not poll() the socket!\n" ); + server->quit = true; + } + break; + } + } + else + usleep( 200000 ); + } + + return DR_OK; +} + +DirectResult +voodoo_server_destroy( VoodooServer *server ) +{ + DirectLink *l; + + D_ASSERT( server != NULL ); + + close( server->fd ); + + /* Close all connections. */ + direct_list_foreach (l, server->connections) { + Connection *connection = (Connection*) l; + + voodoo_manager_destroy( connection->manager ); + + //connection->vl.Close( &connection->vl ); + + D_FREE( connection ); + } + + D_FREE( server ); + + return DR_OK; +} + +/**************************************************************************************************/ + +static DirectResult +accept_connection( VoodooServer *server, int fd ) +{ + DirectResult ret; + int fds[2] = { fd, fd }; + Connection *connection; + + connection = D_CALLOC( 1, sizeof(Connection) ); + if (!connection) { + D_WARN( "out of memory" ); + return DR_NOLOCALMEMORY; + } + + voodoo_link_init_fd( &connection->vl, fds ); + + ret = voodoo_manager_create( &connection->vl, NULL, server, &connection->manager ); + if (ret) { + connection->vl.Close( &connection->vl ); + D_FREE( connection ); + return ret; + } + + direct_list_prepend( &server->connections, &connection->link ); + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/server.h b/Source/DirectFB/lib/voodoo/server.h new file mode 100755 index 0000000..e00329f --- /dev/null +++ b/Source/DirectFB/lib/voodoo/server.h @@ -0,0 +1,52 @@ +/* + (c) Copyright 2001-2007 The DirectFB Organization (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 __VOODOO__SERVER_H__ +#define __VOODOO__SERVER_H__ + +#include + + +DirectResult voodoo_server_create ( VoodooServer **ret_server ); + +DirectResult voodoo_server_register( VoodooServer *server, + const char *name, + VoodooSuperConstruct func, + void *ctx ); + +DirectResult voodoo_server_run ( VoodooServer *server, + bool forking ); + +DirectResult voodoo_server_destroy ( VoodooServer *server ); + +DirectResult voodoo_server_construct( VoodooServer *server, + VoodooManager *manager, + const char *name, + VoodooInstanceID *ret_instance ); + +#endif diff --git a/Source/DirectFB/lib/voodoo/types.h b/Source/DirectFB/lib/voodoo/types.h new file mode 100755 index 0000000..ef9277c --- /dev/null +++ b/Source/DirectFB/lib/voodoo/types.h @@ -0,0 +1,97 @@ +/* + (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 __VOODOO__TYPES_H__ +#define __VOODOO__TYPES_H__ + +#include + +#include "compat.h" + +#ifdef WIN32 +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the VOODOO_EXPORTS +// symbol defined on the command line. This symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// VOODOO_API functions as being imported from a DLL, whereas this DLL sees symbols +// defined with this macro as being exported. +#ifdef VOODOO_EXPORTS +#define VOODOO_API __declspec(dllexport) +#else +#define VOODOO_API __declspec(dllimport) +#endif +#else +#define VOODOO_API +#endif + + +typedef u32 VoodooInstanceID; +typedef u32 VoodooMethodID; +typedef u32 VoodooMessageSerial; + +#define VOODOO_INSTANCE_NONE ((VoodooInstanceID) 0) + + +typedef struct __V_VoodooMessageHeader VoodooMessageHeader; +typedef struct __V_VoodooSuperMessage VoodooSuperMessage; +typedef struct __V_VoodooRequestMessage VoodooRequestMessage; +typedef struct __V_VoodooResponseMessage VoodooResponseMessage; + + +typedef struct __V_VoodooClient VoodooClient; +typedef struct __V_VoodooConfig VoodooConfig; +typedef struct __V_VoodooLink VoodooLink; +typedef struct __V_VoodooPlayer VoodooPlayer; +typedef struct __V_VoodooServer VoodooServer; + +#ifdef __cplusplus +class VoodooConnection; +class VoodooManager; +class VoodooPacket; +#else +typedef void* VoodooManager; +#endif + + +typedef DirectResult (*VoodooSuperConstruct)( VoodooServer *server, + VoodooManager *manager, + const char *name, + void *ctx, + VoodooInstanceID *ret_instance ); + +typedef DirectResult (*VoodooDispatch) ( void *dispatcher, + void *real, + VoodooManager *manager, + VoodooRequestMessage *msg ); + + +#define MAX_MSG_SIZE (17 * 1024) +#define VOODOO_PACKET_MAX (MAX_MSG_SIZE) + +#endif + diff --git a/Source/DirectFB/lib/voodoo/unix/interfaces_unix.c b/Source/DirectFB/lib/voodoo/unix/interfaces_unix.c new file mode 100755 index 0000000..5c3b1f8 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/unix/interfaces_unix.c @@ -0,0 +1,237 @@ +/* + (c) Copyright 2001-2011 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 + + + +DirectResult +voodoo_play_get_broadcast( VoodooPlayAddress **ret_addr, + size_t *ret_num ) +{ + size_t num = 0; + size_t i = 0; + VoodooPlayAddress *addr; + + int ret; + int fd; + char *ptr, lastname[IFNAMSIZ]; + struct ifreq req[16]; + struct ifconf conf; + + D_ASSERT( ret_addr != NULL ); + D_ASSERT( ret_num != NULL ); + + conf.ifc_buf = (char*) req; + conf.ifc_len = sizeof(req); + + fd = socket( AF_INET, SOCK_DGRAM, 0 ); + if (fd < 0) { + D_PERROR( "Voodoo/Unix: socket( AF_INET, SOCK_DGRAM, 0 ) failed!\n" ); + return DR_FAILURE; + } + + ret = ioctl( fd, SIOCGIFCONF, &conf ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFCONF ) failed!\n" ); + close( fd ); + return DR_FAILURE; + } + + lastname[0] = 0; + + for (ptr = conf.ifc_buf; ptr < conf.ifc_buf + conf.ifc_len; ) { + struct ifreq ifrcopy, *ifr = (struct ifreq *)ptr; + struct sockaddr_in *saddr = (struct sockaddr_in*) &ifr->ifr_broadaddr; + +#ifdef MACOS + ptr += sizeof(ifr->ifr_name) + MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); // for next one in buffer +#else + ptr += sizeof(req[0]); +#endif + + if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { + continue; /* already processed this interface */ + } + + memcpy(lastname, ifr->ifr_name, IFNAMSIZ); + + ifrcopy = *ifr; + ioctl( fd, SIOCGIFFLAGS, &ifrcopy); + if ((ifrcopy.ifr_flags & IFF_UP) == 0) + continue; // ignore if interface not up + + ret = ioctl( fd, SIOCGIFBRDADDR, ifr ); + if (ret) + continue; + + if (!saddr->sin_addr.s_addr) { + ret = ioctl( fd, SIOCGIFDSTADDR, ifr ); + if (ret) + continue; + } + + num++; + } + + + addr = D_CALLOC( num, sizeof(VoodooPlayAddress) ); + if (!addr) { + close( fd ); + return D_OOM(); + } + + + for (ptr = conf.ifc_buf; ptr < conf.ifc_buf + conf.ifc_len; ) { + char buf[100]; + struct ifreq ifrcopy, *ifr = (struct ifreq *)ptr; + struct sockaddr_in *saddr = (struct sockaddr_in*) &ifr->ifr_broadaddr; + +#ifdef MACOS + ptr += sizeof(ifr->ifr_name) + MAX(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); // for next one in buffer +#else + ptr += sizeof(req[0]); +#endif + + if (strncmp(lastname, ifr->ifr_name, IFNAMSIZ) == 0) { + continue; /* already processed this interface */ + } + + memcpy(lastname, ifr->ifr_name, IFNAMSIZ); + + ifrcopy = *ifr; + ioctl( fd, SIOCGIFFLAGS, &ifrcopy); + if ((ifrcopy.ifr_flags & IFF_UP) == 0) { + D_INFO( "Voodoo/Player: %-16s is not up.\n", ifrcopy.ifr_name ); + continue; // ignore if interface not up + } + + ret = ioctl( fd, SIOCGIFBRDADDR, ifr ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFBRDADDR ) %-16s failed!\n", ifr->ifr_name ); + continue; + } + + if (saddr->sin_addr.s_addr) { + inet_ntop( AF_INET, &saddr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s)\n", ifr->ifr_name, buf ); + } + else { + ret = ioctl( fd, SIOCGIFDSTADDR, ifr ); + if (ret) { + D_PERROR( "Voodoo/Player: ioctl( SIOCGIFDSTADDR ) failed!\n" ); + continue; + } + + inet_ntop( AF_INET, &saddr->sin_addr, buf, sizeof(buf) ); + + D_INFO( "Voodoo/Player: %-16s (%s) (P-t-P)\n", ifr->ifr_name, buf ); + } + + voodoo_play_from_inet_addr( &addr[i++], saddr->sin_addr.s_addr ); + } + + close( fd ); + + *ret_addr = addr; + *ret_num = num; + + return DR_OK; +} + + + +#if 0 + +DirectResult +voodoo_play_get_broadcast( VoodooPlayAddress **ret_addr, + size_t *ret_num ) +{ + DirectResult ret = DR_OK; + VoodooPlayAddress *addr; + + // Get local host name + char szHostName[128] = ""; + + if (gethostname(szHostName, sizeof(szHostName))) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Win32: gethostname() failed!\n" ); + return ret; + } + + // Get local IP addresses + struct hostent *pHost = 0; + + pHost = gethostbyname(szHostName); + if (!pHost) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Win32: gethostbyname('%s') failed!\n", szHostName ); + return ret; + } + + + size_t iCnt, iTotal = 0; + + for (iCnt = 0; pHost->h_addr_list[iCnt]; ++iCnt) + iTotal++; + + + addr = D_CALLOC( iTotal, sizeof(VoodooPlayAddress) ); + if (!addr) + return D_OOM(); + + for (iCnt = 0; pHost->h_addr_list[iCnt]; ++iCnt) { + struct sockaddr_in SocketAddress; + + memcpy(&SocketAddress.sin_addr, pHost->h_addr_list[iCnt], pHost->h_length); + + voodoo_play_from_inet_addr( &addr[iCnt], SocketAddress.sin_addr.s_addr ); + } + + *ret_addr = addr; + *ret_num = iTotal; + + return DR_OK; +} + +#endif + diff --git a/Source/DirectFB/lib/voodoo/unix/link_unix.c b/Source/DirectFB/lib/voodoo/unix/link_unix.c new file mode 100755 index 0000000..1b6690c --- /dev/null +++ b/Source/DirectFB/lib/voodoo/unix/link_unix.c @@ -0,0 +1,567 @@ +/* + (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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#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 + + +#define UNIX_PATH_MAX 108 + + +D_DEBUG_DOMAIN( Voodoo_Link, "Voodoo/Link", "Voodoo Link" ); + +/**********************************************************************************************************************/ + +#if !VOODOO_BUILD_NO_SETSOCKOPT +static const int one = 1; +static const int tos = IPTOS_LOWDELAY; +#endif + +/**********************************************************************************************************************/ + +#define DUMP_SOCKET_OPTION(fd,o) \ +do { \ + int val = 0; \ + unsigned int len = 4; \ + \ + if (getsockopt( fd, SOL_SOCKET, o, &val, &len )) \ + D_PERROR( "Voodoo/Manager: getsockopt() for " #o " failed!\n" ); \ + else \ + D_DEBUG( "Voodoo/Manager: " #o " is %d\n", val ); \ +} while (0) + +/**********************************************************************************************************************/ + +typedef struct { + int fd[2]; + int wakeup_fds[2]; +} Link; + +static void +Close( VoodooLink *link ) +{ + Link *l = link->priv; + + D_INFO( "Voodoo/Link: Closing connection.\n" ); + + close( l->fd[0] ); + + if (l->fd[1] != l->fd[0]) + close( l->fd[1] ); + + close( l->wakeup_fds[0] ); + close( l->wakeup_fds[1] ); + + D_FREE( link->priv ); + link->priv = NULL; +} + +static ssize_t +Read( VoodooLink *link, + void *buffer, + size_t count ) +{ + Link *l = link->priv; + + return recv( l->fd[0], buffer, count, 0 ); +} + +static ssize_t +Write( VoodooLink *link, + const void *buffer, + size_t count ) +{ + Link *l = link->priv; + + return send( l->fd[1], buffer, count, 0 ); +} + + +// FIXME: refactor, optionally using lio_listio +static DirectResult +SendReceive( VoodooLink *link, + VoodooChunk *sends, + size_t num_send, + VoodooChunk *recvs, + size_t num_recv ) +{ + Link *l = link->priv; + size_t i; + ssize_t ret; + int select_result; + + D_DEBUG_AT( Voodoo_Link, "%s( link %p, sends %p, num_send %zu, recvs %p, num_recv %zu )\n", + __func__, link, sends, num_send, recvs, num_recv ); + + while (true) { + fd_set fds_read; + fd_set fds_write; + struct timeval tv; + + FD_ZERO( &fds_read ); + FD_ZERO( &fds_write ); + + if (num_recv) + FD_SET( l->fd[0], &fds_read ); + + if (num_send) + FD_SET( l->fd[1], &fds_write ); + + FD_SET( l->wakeup_fds[0], &fds_read ); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + D_DEBUG_AT( Voodoo_Link, " -> select( %s%s )...\n", num_recv ? "R" : " ", num_send ? "W" : " " ); + select_result = select( MAX(MAX(l->wakeup_fds[0],l->fd[0]),l->fd[1])+1, &fds_read, &fds_write, NULL, &tv ); + switch (select_result) { + default: + if (FD_ISSET( l->fd[1], &fds_write )) { + D_DEBUG_AT( Voodoo_Link, " => WRITE\n" ); + + for (i=0; ifd[1], sends[i].ptr, sends[i].length, MSG_DONTWAIT ); + if (ret < 0) { + D_PERROR( "Voodoo/Link: Failed to send() data!\n" ); + return DR_IO; + } + else { + sends[i].done += ret; +/* + if (sends[i].done != sends[i].length) + D_WARN( "partial send of %d/%d bytes", ret, sends[i].length ); + else + D_WARN( "full send of %d bytes", ret, sends[i].length ); +*/ + return DR_OK; + } +#else + struct aiocb cb; + + memset( &cb, 0, sizeof(struct aiocb) ); + + cb.aio_fildes = l->fd[1]; + cb.aio_buf = sends[i].ptr; + cb.aio_nbytes = sends[i].length; + cb.aio_offset = (intptr_t)-1; + cb.aio_sigevent.sigev_notify = SIGEV_NONE; + + + ret = aio_write( &cb ); + if (ret < 0) { + D_PERROR( "Voodoo/Link: aio_write() failed!\n" ); + return DR_IO; + } + else { + do { + const struct aiocb *cbs[] = { &cb }; + + ret = aio_suspend( cbs, 1, NULL ); + if (ret < 0) { + D_PERROR( "Voodoo/Link: aio_suspend() failed!\n" ); + return DR_IO; + } + + ret = aio_error( &cb ); + } while (ret == EINPROGRESS); + + switch (ret) { + case 0: + ret = aio_return( &cb ); + if (ret < 0) { + D_ERROR( "Voodoo/Link: aio_return() failed!\n -> %s\n", strerror(ret) ); + return DR_IO; + } + break; + + default: + D_ERROR( "Voodoo/Link: aio_error() failed!\n -> %s\n", strerror(ret) ); + return DR_IO; + } + + sends[i].done += ret; +/* + if (sends[i].done != sends[i].length) + D_WARN( "partial send of %d/%d bytes", ret, sends[i].length ); + else + D_WARN( "full send of %d bytes", ret, sends[i].length ); +*/ + return DR_OK; + } +#endif + } + } + } + + if (FD_ISSET( l->fd[0], &fds_read )) { + D_DEBUG_AT( Voodoo_Link, " => READ\n" ); + + for (i=0; ifd[0], recvs[i].ptr, recvs[i].length, MSG_DONTWAIT ); + if (ret < 0) { + if (errno == EAGAIN) { + break; + } + D_PERROR( "Voodoo/Link: Failed to recv() data!\n" ); + return DR_FAILURE; + } + + if (!ret) + return DR_IO; + + + recvs[i].done = ret; + + if (recvs[i].done < recvs[i].length) + break; + } + } + + if (FD_ISSET( l->wakeup_fds[0], &fds_read )) { + D_DEBUG_AT( Voodoo_Link, " => WAKE UP\n" ); + + static char buf[1000]; + read( l->wakeup_fds[0], buf, sizeof(buf) ); + if (!FD_ISSET( l->fd[0], &fds_read ) && !FD_ISSET( l->fd[0], &fds_write )) + return DR_INTERRUPTED; + } + + return DR_OK; + + case 0: + D_DEBUG_AT( Voodoo_Link, " => TIMEOUT\n" ); + return DR_TIMEOUT; + + case -1: + D_ERROR( "Voodoo/Link: select() failed!\n" ); + return DR_FAILURE; + } + } + + return DR_OK; +} + +static DirectResult +WakeUp( VoodooLink *link ) +{ + Link *l = link->priv; + char c = 0; + + write( l->wakeup_fds[1], &c, 1 ); + + return DR_OK; +} + +/**********************************************************************************************************************/ + +DirectResult +voodoo_link_init_connect( VoodooLink *link, + const char *hostname, + int port, + bool raw ) +{ + DirectResult ret; + int err; + struct addrinfo hints; + struct addrinfo *addr; + char portstr[10]; + Link *l; + + + memset( &hints, 0, sizeof(hints) ); + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + + D_INFO( "Voodoo/Link: Looking up host '%s'...\n", hostname ); + + snprintf( portstr, sizeof(portstr), "%d", port ); + + err = getaddrinfo( hostname, portstr, &hints, &addr ); + if (err) { + switch (err) { + case EAI_FAMILY: + D_ERROR( "Direct/Log: Unsupported address family!\n" ); + return DR_UNSUPPORTED; + + case EAI_SOCKTYPE: + D_ERROR( "Direct/Log: Unsupported socket type!\n" ); + return DR_UNSUPPORTED; + + case EAI_NONAME: + D_ERROR( "Direct/Log: Host not found!\n" ); + return DR_FAILURE; + + case EAI_SERVICE: + D_ERROR( "Direct/Log: Service is unreachable!\n" ); + return DR_FAILURE; + +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: +#endif + case EAI_NODATA: + D_ERROR( "Direct/Log: Host found, but has no address!\n" ); + return DR_FAILURE; + + case EAI_MEMORY: + return D_OOM(); + + case EAI_FAIL: + D_ERROR( "Direct/Log: A non-recoverable name server error occurred!\n" ); + return DR_FAILURE; + + case EAI_AGAIN: + D_ERROR( "Direct/Log: Temporary error, try again!\n" ); + return DR_TEMPUNAVAIL; + + default: + D_ERROR( "Direct/Log: Unknown error occured!?\n" ); + return DR_FAILURE; + } + } + + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + /* Create the client socket. */ + l->fd[0] = socket( addr->ai_family, SOCK_STREAM, 0 ); + if (l->fd[0] < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket creation failed!\n" ); + freeaddrinfo( addr ); + D_FREE( l ); + return ret; + } + l->fd[1] = l->fd[0]; + +#if !VOODOO_BUILD_NO_SETSOCKOPT +// if (setsockopt( l->fd[0], SOL_IP, IP_TOS, &tos, sizeof(tos) ) < 0) +// D_PERROR( "Voodoo/Manager: Could not set IP_TOS!\n" ); + + if (setsockopt( l->fd[0], SOL_TCP, TCP_NODELAY, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Manager: Could not set TCP_NODELAY!\n" ); +#endif + + D_INFO( "Voodoo/Link: Connecting to '%s:%d'...\n", addr->ai_canonname, port ); + + /* Connect to the server. */ + err = connect( l->fd[0], addr->ai_addr, addr->ai_addrlen ); + freeaddrinfo( addr ); + + if (err) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket connect failed!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return ret; + } + + D_INFO( "Voodoo/Link: Connected.\n" ); + + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDBUF ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVBUF ); + + if (!raw) { + link->code = 0x80008676; + + if (write( l->fd[1], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not write initial four bytes!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return DR_IO; + } + } + D_INFO( "Voodoo/Link: Sent link code (%s).\n", raw ? "raw" : "packet" ); + + pipe( l->wakeup_fds ); + + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + +DirectResult +voodoo_link_init_local( VoodooLink *link, + const char *path, + bool raw ) +{ + DirectResult ret; + int err; + struct sockaddr_un addr; + Link *l; + + D_ASSERT( link != NULL ); + D_ASSERT( path != NULL ); + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + /* Create the client socket. */ + l->fd[0] = socket( AF_LOCAL, SOCK_STREAM, 0 ); + if (l->fd[0] < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket creation failed!\n" ); + D_FREE( l ); + return ret; + } + l->fd[1] = l->fd[0]; + +#if !VOODOO_BUILD_NO_SETSOCKOPT +// if (setsockopt( l->fd[0], SOL_IP, IP_TOS, &tos, sizeof(tos) ) < 0) +// D_PERROR( "Voodoo/Manager: Could not set IP_TOS!\n" ); + + if (setsockopt( l->fd[0], SOL_TCP, TCP_NODELAY, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Manager: Could not set TCP_NODELAY!\n" ); +#endif + + D_INFO( "Voodoo/Link: Connecting to '%s'...\n", path ); + + + memset( &addr, 0, sizeof(addr) ); + + /* Bind the socket to the local port. */ + addr.sun_family = AF_UNIX; + + snprintf( addr.sun_path + 1, UNIX_PATH_MAX - 1, "%s", path ); + + /* Connect to the server. */ + err = connect( l->fd[0], (struct sockaddr*) &addr, strlen(addr.sun_path+1)+1 + sizeof(addr.sun_family) ); + if (err) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket connect failed!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return ret; + } + + D_INFO( "Voodoo/Link: Connected.\n" ); + + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDBUF ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVBUF ); + + if (!raw) { + link->code = 0x80008676; + + if (write( l->fd[1], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not write initial four bytes!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return DR_IO; + } + } + D_INFO( "Voodoo/Link: Sent link code (%s).\n", raw ? "raw" : "packet" ); + + pipe( l->wakeup_fds ); + + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + +DirectResult +voodoo_link_init_fd( VoodooLink *link, + int fd[2] ) +{ + Link *l; + + if (read( fd[0], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not read initial four bytes!\n" ); + return DR_IO; + } + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + l->fd[0] = fd[0]; + l->fd[1] = fd[1]; + + pipe( l->wakeup_fds ); + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/unix/link_unix_1408limit.c b/Source/DirectFB/lib/voodoo/unix/link_unix_1408limit.c new file mode 100755 index 0000000..790aa99 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/unix/link_unix_1408limit.c @@ -0,0 +1,422 @@ +/* + (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. +*/ + +//#define DIRECT_ENABLE_DEBUG + +#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 + + +D_DEBUG_DOMAIN( Voodoo_Link, "Voodoo/Link", "Voodoo Link" ); + +/**********************************************************************************************************************/ + +#if !VOODOO_BUILD_NO_SETSOCKOPT +static const int one = 1; +static const int tos = IPTOS_LOWDELAY; +#endif + +/**********************************************************************************************************************/ + +#define DUMP_SOCKET_OPTION(fd,o) \ +do { \ + int val = 0; \ + unsigned int len = 4; \ + \ + if (getsockopt( fd, SOL_SOCKET, o, &val, &len )) \ + D_PERROR( "Voodoo/Manager: getsockopt() for " #o " failed!\n" ); \ + else \ + D_DEBUG( "Voodoo/Manager: " #o " is %d\n", val ); \ +} while (0) + +/**********************************************************************************************************************/ + +typedef struct { + int fd[2]; + int wakeup_fds[2]; +} Link; + +static void +Close( VoodooLink *link ) +{ + Link *l = link->priv; + + D_INFO( "Voodoo/Link: Closing connection.\n" ); + + close( l->fd[0] ); + + if (l->fd[1] != l->fd[0]) + close( l->fd[1] ); + + D_FREE( link->priv ); + link->priv = NULL; +} + +static ssize_t +Read( VoodooLink *link, + void *buffer, + size_t count ) +{ + Link *l = link->priv; + + return recv( l->fd[0], buffer, count, 0 ); +} + +static ssize_t +Write( VoodooLink *link, + const void *buffer, + size_t count ) +{ + Link *l = link->priv; + + return send( l->fd[1], buffer, count, 0 ); +} + + +// FIXME: refactor, optionally using lio_listio +static DirectResult +SendReceive( VoodooLink *link, + VoodooChunk *sends, + size_t num_send, + VoodooChunk *recvs, + size_t num_recv ) +{ + Link *l = link->priv; + size_t i; + ssize_t ret; + int select_result; + + D_DEBUG_AT( Voodoo_Link, "%s( link %p, sends %p, num_send %zu, recvs %p, num_recv %zu )\n", + __func__, link, sends, num_send, recvs, num_recv ); + + while (true) { + fd_set fds_read; + fd_set fds_write; + struct timeval tv; + + FD_ZERO( &fds_read ); + FD_ZERO( &fds_write ); + + if (num_recv) + FD_SET( l->fd[0], &fds_read ); + + if (num_send) + FD_SET( l->fd[1], &fds_write ); + + FD_SET( l->wakeup_fds[0], &fds_read ); + + tv.tv_sec = 1; + tv.tv_usec = 0; + + D_DEBUG_AT( Voodoo_Link, " -> select( %s%s )...\n", num_recv ? "R" : " ", num_send ? "W" : " " ); + select_result = select( MAX(MAX(l->wakeup_fds[0],l->fd[0]),l->fd[1])+1, &fds_read, &fds_write, NULL, &tv ); + switch (select_result) { + default: + if (FD_ISSET( l->fd[1], &fds_write )) { + D_DEBUG_AT( Voodoo_Link, " => WRITE\n" ); + + for (i=0; ifd[1], sends[i].ptr, sends[i].length, MSG_DONTWAIT ); + if (ret < 0) { + //if (errno == EAGAIN) { + // break; + //} + D_PERROR( "Voodoo/Link: Failed to send() data!\n" ); + return DR_FAILURE; + } + else { + sends[i].done += ret; +/* + if (sends[i].done != sends[i].length) + D_WARN( "partial send of %d/%d bytes", ret, sends[i].length ); + else + D_WARN( "full send of %d bytes", ret, sends[i].length ); +*/ +// return DR_OK; + break; + } + } + } + } + + if (FD_ISSET( l->fd[0], &fds_read )) { + D_DEBUG_AT( Voodoo_Link, " => READ\n" ); + + for (i=0; ifd[0], recvs[i].ptr, recvs[i].length, MSG_DONTWAIT ); + if (ret < 0) { + if (errno == EAGAIN) { + break; + } + D_PERROR( "Voodoo/Link: Failed to recv() data!\n" ); + return DR_FAILURE; + } + + if (!ret) + return DR_IO; + + + recvs[i].done = ret; + + if (recvs[i].done < recvs[i].length) + break; + } + } + + if (FD_ISSET( l->wakeup_fds[0], &fds_read )) { + D_DEBUG_AT( Voodoo_Link, " => WAKE UP\n" ); + + static char buf[1000]; + read( l->wakeup_fds[0], buf, sizeof(buf) ); + if (!FD_ISSET( l->fd[0], &fds_read ) && !FD_ISSET( l->fd[0], &fds_write )) + return DR_INTERRUPTED; + } + + return DR_OK; + + case 0: + D_DEBUG_AT( Voodoo_Link, " => TIMEOUT\n" ); + return DR_TIMEOUT; + + case -1: + D_ERROR( "Voodoo/Link: select() failed!\n" ); + return DR_FAILURE; + } + } + + return DR_OK; +} + +static DirectResult +WakeUp( VoodooLink *link ) +{ + Link *l = link->priv; + char c = 0; + + write( l->wakeup_fds[1], &c, 1 ); + + return DR_OK; +} + +/**********************************************************************************************************************/ + +DirectResult +voodoo_link_init_connect( VoodooLink *link, + const char *hostname, + int port, + bool raw ) +{ + DirectResult ret; + int err; + struct addrinfo hints; + struct addrinfo *addr; + char portstr[10]; + Link *l; + + + memset( &hints, 0, sizeof(hints) ); + hints.ai_flags = AI_CANONNAME; + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = PF_UNSPEC; + + D_INFO( "Voodoo/Link: Looking up host '%s'...\n", hostname ); + + snprintf( portstr, sizeof(portstr), "%d", port ); + + err = getaddrinfo( hostname, portstr, &hints, &addr ); + if (err) { + switch (err) { + case EAI_FAMILY: + D_ERROR( "Direct/Log: Unsupported address family!\n" ); + return DR_UNSUPPORTED; + + case EAI_SOCKTYPE: + D_ERROR( "Direct/Log: Unsupported socket type!\n" ); + return DR_UNSUPPORTED; + + case EAI_NONAME: + D_ERROR( "Direct/Log: Host not found!\n" ); + return DR_FAILURE; + + case EAI_SERVICE: + D_ERROR( "Direct/Log: Service is unreachable!\n" ); + return DR_FAILURE; + +#ifdef EAI_ADDRFAMILY + case EAI_ADDRFAMILY: +#endif + case EAI_NODATA: + D_ERROR( "Direct/Log: Host found, but has no address!\n" ); + return DR_FAILURE; + + case EAI_MEMORY: + return D_OOM(); + + case EAI_FAIL: + D_ERROR( "Direct/Log: A non-recoverable name server error occurred!\n" ); + return DR_FAILURE; + + case EAI_AGAIN: + D_ERROR( "Direct/Log: Temporary error, try again!\n" ); + return DR_TEMPUNAVAIL; + + default: + D_ERROR( "Direct/Log: Unknown error occured!?\n" ); + return DR_FAILURE; + } + } + + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + /* Create the client socket. */ + l->fd[0] = socket( addr->ai_family, SOCK_STREAM, 0 ); + if (l->fd[0] < 0) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket creation failed!\n" ); + freeaddrinfo( addr ); + D_FREE( l ); + return ret; + } + l->fd[1] = l->fd[0]; + +#if !VOODOO_BUILD_NO_SETSOCKOPT + if (setsockopt( l->fd[0], SOL_IP, IP_TOS, &tos, sizeof(tos) ) < 0) + D_PERROR( "Voodoo/Manager: Could not set IP_TOS!\n" ); + + if (setsockopt( l->fd[0], SOL_TCP, TCP_NODELAY, &one, sizeof(one) ) < 0) + D_PERROR( "Voodoo/Manager: Could not set TCP_NODELAY!\n" ); +#endif + + D_INFO( "Voodoo/Link: Connecting to '%s:%d'...\n", addr->ai_canonname, port ); + + /* Connect to the server. */ + err = connect( l->fd[0], addr->ai_addr, addr->ai_addrlen ); + freeaddrinfo( addr ); + + if (err) { + ret = errno2result( errno ); + D_PERROR( "Voodoo/Link: Socket connect failed!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return ret; + } + + D_INFO( "Voodoo/Link: Connected.\n" ); + + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVLOWAT ); + DUMP_SOCKET_OPTION( l->fd[0], SO_SNDBUF ); + DUMP_SOCKET_OPTION( l->fd[0], SO_RCVBUF ); + + if (!raw) { + link->code = 0x80008676; + + if (write( l->fd[1], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not write initial four bytes!\n" ); + close( l->fd[0] ); + D_FREE( l ); + return DR_IO; + } + } + D_INFO( "Voodoo/Link: Sent link code (%s).\n", raw ? "raw" : "packet" ); + + pipe( l->wakeup_fds ); + + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + +DirectResult +voodoo_link_init_fd( VoodooLink *link, + int fd[2] ) +{ + Link *l; + + if (read( fd[0], &link->code, sizeof(link->code) ) != 4) { + D_ERROR( "Voodoo/Link: Coult not read initial four bytes!\n" ); + return DR_IO; + } + + l = D_CALLOC( 1, sizeof(Link) ); + if (!l) + return D_OOM(); + + l->fd[0] = fd[0]; + l->fd[1] = fd[1]; + + pipe( l->wakeup_fds ); + + link->priv = l; + link->Close = Close; + link->Read = Read; + link->Write = Write; + link->SendReceive = SendReceive; + link->WakeUp = WakeUp; + + return DR_OK; +} + diff --git a/Source/DirectFB/lib/voodoo/voodoo.pc.in b/Source/DirectFB/lib/voodoo/voodoo.pc.in new file mode 100755 index 0000000..8e29024 --- /dev/null +++ b/Source/DirectFB/lib/voodoo/voodoo.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Voodoo +Description: Interface based network transparency (like CORBA) +Version: @VERSION@ +Requires: direct +Libs: -L${libdir} -lvoodoo +Cflags: -I@INCLUDEDIR@ diff --git a/Source/DirectFB/lib/voodoo/waitqueue.h b/Source/DirectFB/lib/voodoo/waitqueue.h new file mode 100755 index 0000000..ab163ce --- /dev/null +++ b/Source/DirectFB/lib/voodoo/waitqueue.h @@ -0,0 +1,117 @@ +/* + (c) Copyright 2001-2008 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 __DIRECT__OS__LINUX__GLIBC__WAITQUEUE_H__ +#define __DIRECT__OS__LINUX__GLIBC__WAITQUEUE_H__ + +#include + +#include + +#include "mutex.h" + +/**********************************************************************************************************************/ + +typedef struct { + pthread_cond_t cond; +} DirectWaitQueue; + +/**********************************************************************************************************************/ + +#define DIRECT_WAITQUEUE_INITIALIZER(name) { PTHREAD_COND_INITIALIZER } + +/**********************************************************************************************************************/ + +static inline DirectResult +direct_waitqueue_init( DirectWaitQueue *queue ) +{ + if (pthread_cond_init( &queue->cond, NULL )) + return errno2result( errno ); + + return DR_OK; +} + +static inline DirectResult +direct_waitqueue_wait( DirectWaitQueue *queue, DirectMutex *mutex ) +{ + if (pthread_cond_wait( &queue->cond, &mutex->lock )) + return errno2result( errno ); + + return DR_OK; +} + +static inline DirectResult +direct_waitqueue_wait_timeout( DirectWaitQueue *queue, DirectMutex *mutex, unsigned long micros ) +{ + struct timeval now; + struct timespec timeout; + long int nano_seconds = micros * 1000; + + gettimeofday( &now, NULL ); + + timeout.tv_sec = now.tv_sec; + timeout.tv_nsec = (now.tv_usec * 1000) + nano_seconds; + + timeout.tv_sec += timeout.tv_nsec / 1000000000; + timeout.tv_nsec %= 1000000000; + + if (pthread_cond_timedwait( &queue->cond, &mutex->lock, &timeout ) == ETIMEDOUT) + return DR_TIMEOUT; + + return DR_OK; +} + +static inline DirectResult +direct_waitqueue_signal( DirectWaitQueue *queue ) +{ + if (pthread_cond_signal( &queue->cond )) + return errno2result( errno ); + + return DR_OK; +} + +static inline DirectResult +direct_waitqueue_broadcast( DirectWaitQueue *queue ) +{ + if (pthread_cond_broadcast( &queue->cond )) + return errno2result( errno ); + + return DR_OK; +} + +static inline DirectResult +direct_waitqueue_deinit( DirectWaitQueue *queue ) +{ + if (pthread_cond_destroy( &queue->cond )) + return errno2result( errno ); + + return DR_OK; +} + +#endif + -- cgit