PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/DirectFB-1.5.3/lib/direct/modules.c

#
C | 458 lines | 307 code | 119 blank | 32 comment | 67 complexity | f5f79ed100283d50e2433767e6777d22 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. (c) Copyright 2001-2008 The world wide DirectFB Open Source Community (directfb.org)
  3. (c) Copyright 2000-2004 Convergence (integrated media) GmbH
  4. All rights reserved.
  5. Written by Denis Oliver Kropp <dok@directfb.org>,
  6. Andreas Hundt <andi@fischlustig.de>,
  7. Sven Neumann <neo@directfb.org>,
  8. Ville Syrj?l? <syrjala@sci.fi> and
  9. Claudio Ciccani <klan@users.sf.net>.
  10. This library is free software; you can redistribute it and/or
  11. modify it under the terms of the GNU Lesser General Public
  12. License as published by the Free Software Foundation; either
  13. version 2 of the License, or (at your option) any later version.
  14. This library is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. Lesser General Public License for more details.
  18. You should have received a copy of the GNU Lesser General Public
  19. License along with this library; if not, write to the
  20. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  21. Boston, MA 02111-1307, USA.
  22. */
  23. #include <config.h>
  24. #include <sys/types.h>
  25. #include <string.h>
  26. #include <stdio.h>
  27. #include <direct/conf.h>
  28. #include <direct/debug.h>
  29. #include <direct/mem.h>
  30. #include <direct/messages.h>
  31. #include <direct/modules.h>
  32. #if DIRECT_BUILD_DYNLOAD
  33. #include <alloca.h>
  34. #include <dirent.h>
  35. #include <dlfcn.h>
  36. #endif
  37. D_LOG_DOMAIN( Direct_Modules, "Direct/Modules", "Module loading and registration" );
  38. /******************************************************************************/
  39. #if DIRECT_BUILD_DYNLOAD
  40. static DirectModuleEntry *lookup_by_name( const DirectModuleDir *directory,
  41. const char *name );
  42. static DirectModuleEntry *lookup_by_file( const DirectModuleDir *directory,
  43. const char *file );
  44. static void *open_module ( DirectModuleEntry *module );
  45. static bool load_module ( DirectModuleEntry *module );
  46. static void unload_module( DirectModuleEntry *module );
  47. #endif
  48. /******************************************************************************/
  49. static int
  50. suppress_module (const char *name)
  51. {
  52. int i = 0;
  53. if (!direct_config || !direct_config->disable_module)
  54. return 0;
  55. while (direct_config->disable_module[i]) {
  56. if (strcmp (direct_config->disable_module[i], name) == 0) {
  57. D_INFO( "Direct/Modules: suppress module '%s'\n", direct_config->disable_module[i] );
  58. return 1;
  59. }
  60. i++;
  61. }
  62. return 0;
  63. }
  64. void
  65. direct_modules_register( DirectModuleDir *directory,
  66. unsigned int abi_version,
  67. const char *name,
  68. const void *funcs )
  69. {
  70. DirectModuleEntry *entry;
  71. D_ASSERT( directory != NULL );
  72. D_ASSERT( name != NULL );
  73. D_ASSERT( funcs != NULL );
  74. D_DEBUG_AT( Direct_Modules, "Registering '%s' ('%s')...\n", name, directory->path );
  75. #if DIRECT_BUILD_DYNLOAD
  76. if ((entry = lookup_by_name( directory, name )) != NULL) {
  77. D_MAGIC_ASSERT( entry, DirectModuleEntry );
  78. entry->loaded = true;
  79. entry->funcs = funcs;
  80. return;
  81. }
  82. #endif
  83. if (directory->loading) {
  84. entry = directory->loading;
  85. D_MAGIC_ASSERT( entry, DirectModuleEntry );
  86. directory->loading = NULL;
  87. }
  88. else {
  89. entry = D_CALLOC( 1, sizeof(DirectModuleEntry) );
  90. if (!entry) {
  91. D_OOM();
  92. return;
  93. }
  94. D_MAGIC_SET( entry, DirectModuleEntry );
  95. }
  96. entry->directory = directory;
  97. entry->loaded = true;
  98. entry->name = D_STRDUP( name );
  99. entry->funcs = funcs;
  100. entry->disabled = suppress_module( name );
  101. if (abi_version != directory->abi_version) {
  102. D_ERROR( "Direct/Modules: ABI version of '%s' (%d) does not match %d!\n",
  103. entry->file ? entry->file : entry->name,
  104. abi_version, directory->abi_version );
  105. entry->disabled = true;
  106. }
  107. direct_list_prepend( &directory->entries, &entry->link );
  108. D_DEBUG_AT( Direct_Modules, "...registered.\n" );
  109. }
  110. void
  111. direct_modules_unregister( DirectModuleDir *directory,
  112. const char *name )
  113. {
  114. #if DIRECT_BUILD_DYNLOAD
  115. DirectModuleEntry *entry;
  116. #endif
  117. D_DEBUG_AT( Direct_Modules, "Unregistering '%s' ('%s')...\n", name, directory->path );
  118. #if DIRECT_BUILD_DYNLOAD
  119. entry = lookup_by_name( directory, name );
  120. if (!entry) {
  121. D_ERROR( "Direct/Modules: Unregister failed, could not find '%s' module!\n", name );
  122. return;
  123. }
  124. D_MAGIC_ASSERT( entry, DirectModuleEntry );
  125. D_FREE( entry->name );
  126. direct_list_remove( &directory->entries, &entry->link );
  127. D_MAGIC_CLEAR( entry );
  128. D_FREE( entry );
  129. #endif
  130. D_DEBUG_AT( Direct_Modules, "...unregistered.\n" );
  131. }
  132. int
  133. direct_modules_explore_directory( DirectModuleDir *directory )
  134. {
  135. #if DIRECT_BUILD_DYNLOAD
  136. DIR *dir;
  137. struct dirent *entry = NULL;
  138. struct dirent tmp;
  139. int count = 0;
  140. const char *pathfront = "";
  141. const char *path;
  142. char *buf;
  143. D_ASSERT( directory != NULL );
  144. D_ASSERT( directory->path != NULL );
  145. D_DEBUG_AT( Direct_Modules, "%s( '%s' )\n", __FUNCTION__, directory->path );
  146. path = directory->path;
  147. if (path[0] != '/') {
  148. pathfront = direct_config->module_dir;
  149. if (!pathfront)
  150. pathfront = MODULEDIR;
  151. }
  152. buf = alloca( strlen(pathfront) + 1 + strlen(path) + 1 ); /* pre, slash, post, 0 */
  153. sprintf( buf, "%s/%s", pathfront, path );
  154. dir = opendir( buf );
  155. if (!dir) {
  156. D_DEBUG_AT( Direct_Modules, " -> ERROR opening directory: %s!\n", strerror(errno) );
  157. return 0;
  158. }
  159. while (readdir_r( dir, &tmp, &entry ) == 0 && entry) {
  160. void *handle;
  161. DirectModuleEntry *module;
  162. int entry_len = strlen(entry->d_name);
  163. if (entry_len < 4 ||
  164. entry->d_name[entry_len-1] != 'o' ||
  165. entry->d_name[entry_len-2] != 's')
  166. continue;
  167. if (lookup_by_file( directory, entry->d_name ))
  168. continue;
  169. module = D_CALLOC( 1, sizeof(DirectModuleEntry) );
  170. if (!module)
  171. continue;
  172. D_MAGIC_SET( module, DirectModuleEntry );
  173. module->directory = directory;
  174. module->dynamic = true;
  175. module->file = D_STRDUP( entry->d_name );
  176. if (!module->file) {
  177. D_MAGIC_CLEAR( module );
  178. D_FREE( module );
  179. continue;
  180. }
  181. directory->loading = module;
  182. if ((handle = open_module( module )) != NULL) {
  183. if (!module->loaded) {
  184. dlclose( handle );
  185. D_ERROR( "Direct/Modules: Module '%s' did not "
  186. "register itself after loading!\n",
  187. entry->d_name );
  188. module->disabled = true;
  189. direct_list_prepend( &directory->entries, &module->link );
  190. }
  191. else if (module->disabled) {
  192. module->loaded = false;
  193. /* may call direct_modules_unregister() */
  194. dlclose( handle );
  195. }
  196. else {
  197. module->handle = handle;
  198. count++;
  199. }
  200. }
  201. else {
  202. module->disabled = true;
  203. direct_list_prepend( &directory->entries, &module->link );
  204. }
  205. directory->loading = NULL;
  206. }
  207. closedir( dir );
  208. return count;
  209. #else
  210. return 0;
  211. #endif
  212. }
  213. const void *
  214. direct_module_ref( DirectModuleEntry *module )
  215. {
  216. D_ASSERT( module != NULL );
  217. D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs )\n", __FUNCTION__, module, module->name, module->refs );
  218. D_MAGIC_ASSERT( module, DirectModuleEntry );
  219. if (module->disabled)
  220. return NULL;
  221. #if DIRECT_BUILD_DYNLOAD
  222. if (!module->loaded && !load_module( module ))
  223. return NULL;
  224. #endif
  225. module->refs++;
  226. return module->funcs;
  227. }
  228. void
  229. direct_module_unref( DirectModuleEntry *module )
  230. {
  231. D_ASSERT( module != NULL );
  232. D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs )\n", __FUNCTION__, module, module->name, module->refs );
  233. D_MAGIC_ASSERT( module, DirectModuleEntry );
  234. D_ASSERT( module->refs > 0 );
  235. if (--module->refs)
  236. return;
  237. #if DIRECT_BUILD_DYNLOAD
  238. if (module->dynamic)
  239. unload_module( module );
  240. #endif
  241. }
  242. /******************************************************************************/
  243. #if DIRECT_BUILD_DYNLOAD
  244. static DirectModuleEntry *
  245. lookup_by_name( const DirectModuleDir *directory,
  246. const char *name )
  247. {
  248. DirectLink *l;
  249. D_ASSERT( directory != NULL );
  250. D_ASSERT( name != NULL );
  251. direct_list_foreach (l, directory->entries) {
  252. DirectModuleEntry *entry = (DirectModuleEntry*) l;
  253. D_MAGIC_ASSERT( entry, DirectModuleEntry );
  254. if (!entry->name)
  255. continue;
  256. if (!strcmp( entry->name, name ))
  257. return entry;
  258. }
  259. return NULL;
  260. }
  261. static DirectModuleEntry *
  262. lookup_by_file( const DirectModuleDir *directory,
  263. const char *file )
  264. {
  265. DirectLink *l;
  266. D_ASSERT( directory != NULL );
  267. D_ASSERT( file != NULL );
  268. direct_list_foreach (l, directory->entries) {
  269. DirectModuleEntry *entry = (DirectModuleEntry*) l;
  270. D_MAGIC_ASSERT( entry, DirectModuleEntry );
  271. if (!entry->file)
  272. continue;
  273. if (!strcmp( entry->file, file ))
  274. return entry;
  275. }
  276. return NULL;
  277. }
  278. static bool
  279. load_module( DirectModuleEntry *module )
  280. {
  281. D_MAGIC_ASSERT( module, DirectModuleEntry );
  282. D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs )\n", __FUNCTION__, module, module->file, module->refs );
  283. D_ASSERT( module->dynamic == true );
  284. D_ASSERT( module->file != NULL );
  285. D_ASSERT( module->loaded == false );
  286. D_ASSERT( module->disabled == false );
  287. module->handle = open_module( module );
  288. return module->loaded;
  289. }
  290. static void
  291. unload_module( DirectModuleEntry *module )
  292. {
  293. void *handle;
  294. D_MAGIC_ASSERT( module, DirectModuleEntry );
  295. D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs )\n", __FUNCTION__, module, module->file, module->refs );
  296. D_ASSERT( module->dynamic == true );
  297. D_ASSERT( module->handle != NULL );
  298. D_ASSERT( module->loaded == true );
  299. handle = module->handle;
  300. module->handle = NULL;
  301. module->loaded = false;
  302. /* may call direct_modules_unregister() */
  303. dlclose( handle );
  304. }
  305. static void *
  306. open_module( DirectModuleEntry *module )
  307. {
  308. DirectModuleDir *directory;
  309. const char *pathfront = "";
  310. const char *path;
  311. char *buf;
  312. void *handle;
  313. D_MAGIC_ASSERT( module, DirectModuleEntry );
  314. D_DEBUG_AT( Direct_Modules, "%s( %p '%s', %d refs )\n", __FUNCTION__, module, module->file, module->refs );
  315. D_ASSERT( module->file != NULL );
  316. D_ASSERT( module->directory != NULL );
  317. D_ASSERT( module->directory->path != NULL );
  318. directory = module->directory;
  319. path = directory->path;
  320. if (path[0] != '/') {
  321. pathfront = direct_config->module_dir;
  322. if (!pathfront)
  323. pathfront = MODULEDIR;
  324. }
  325. buf = alloca( strlen( pathfront ) + 1 + strlen( path ) + 1 + strlen( module->file ) + 1 );
  326. sprintf( buf, "%s/%s/%s", pathfront, path, module->file );
  327. D_DEBUG_AT( Direct_Modules, "Loading '%s'...\n", buf );
  328. handle = dlopen( buf, RTLD_NOW );
  329. if (!handle)
  330. D_DLERROR( "Direct/Modules: Unable to dlopen `%s'!\n", buf );
  331. D_MAGIC_ASSERT( module, DirectModuleEntry );
  332. return handle;
  333. }
  334. #endif