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/direct/modules.c | 463 +++++++++++++++++++++++++++++++++++ 1 file changed, 463 insertions(+) create mode 100755 Source/DirectFB/lib/direct/modules.c (limited to 'Source/DirectFB/lib/direct/modules.c') 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 + -- cgit