gmodule.c revision fac803a223b47d7abbfbf3a2adee2f1862382582
1/* GMODULE - GLIB wrapper code for dynamic module loading
2 * Copyright (C) 1998 Tim Janik
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
18 */
19#include	"gmodule.h"
20#include	"gmoduleconf.h"
21#include	<errno.h>
22#include	<string.h>
23
24
25/* We maintain a list of modules, so we can reference count them.
26 * That's needed because some platforms don't support refernce counts on
27 * modules e.g. the shl_* implementation of HP-UX
28 * (http://www.stat.umn.edu/~luke/xls/projects/dlbasics/dlbasics.html).
29 * Also, the module for the program itself is kept seperatedly for
30 * faster access and because it has special semantics.
31 */
32
33
34/* --- structures --- */
35struct _GModule
36{
37  gchar	*file_name;
38  gpointer handle;
39  guint ref_count;
40  GModuleDeInit de_init;
41  GModule *next;
42};
43
44
45/* --- prototypes --- */
46static gpointer		_g_module_open		(const gchar	*file_name,
47						 gboolean	 bind_lazy);
48static void		_g_module_close		(gpointer	 handle,
49						 gboolean	 is_unref);
50static gpointer		_g_module_self		(void);
51static gpointer		_g_module_symbol	(gpointer	 handle,
52						 const gchar	*symbol_name);
53static inline void	g_module_set_error	(const gchar	*error);
54static inline GModule*	g_module_find_by_handle (gpointer	 handle);
55static inline GModule*	g_module_find_by_name	(const gchar	*name);
56
57
58/* --- variables --- */
59static GModule	*modules = NULL;
60static GModule	*main_module = NULL;
61static gchar	*module_error = NULL;
62
63
64/* --- inline functions --- */
65static inline GModule*
66g_module_find_by_handle (gpointer handle)
67{
68  GModule *module;
69
70  if (main_module && main_module->handle == handle)
71    return main_module;
72
73  for (module = modules; module; module = module->next)
74    if (handle == module->handle)
75      return module;
76  return NULL;
77}
78
79static inline GModule*
80g_module_find_by_name (const gchar *name)
81{
82  GModule *module;
83
84  for (module = modules; module; module = module->next)
85    if (strcmp (name, module->file_name) == 0)
86      return module;
87  return NULL;
88}
89
90static inline void
91g_module_set_error (const gchar *error)
92{
93  if (module_error)
94    g_free (module_error);
95  if (error)
96    module_error = g_strdup (error);
97  else
98    module_error = NULL;
99  errno = 0;
100}
101
102
103/* --- include platform specifc code --- */
104#define	CHECK_ERROR(rv)	{ g_module_set_error (NULL); }
105#if	(G_MODULE_IMPL == G_MODULE_IMPL_DL)
106#include "gmodule-dl.c"
107#elif	(G_MODULE_IMPL == G_MODULE_IMPL_DLD)
108#include "gmodule-dld.c"
109#else
110#undef	CHECK_ERROR
111#define	CHECK_ERROR(rv)	{ g_module_set_error ("unsupported"); return rv; }
112#endif	/* no implementation */
113
114
115/* --- functions --- */
116gboolean
117g_module_supported (void)
118{
119  CHECK_ERROR (FALSE);
120
121  return TRUE;
122}
123
124GModule*
125g_module_open (const gchar    *file_name,
126	       GModuleFlags    flags)
127{
128  GModule *module;
129  gpointer handle;
130
131  CHECK_ERROR (NULL);
132
133  if (!file_name)
134    {
135      if (!main_module)
136	{
137	  handle = _g_module_self ();
138	  if (handle)
139	    {
140	      main_module = g_new (GModule, 1);
141	      main_module->file_name = NULL;
142	      main_module->handle = handle;
143	      main_module->ref_count = 1;
144	      main_module->de_init = NULL;
145	      main_module->next = NULL;
146	    }
147	}
148
149      return main_module;
150    }
151
152  /* we first search the module list by name */
153  module = g_module_find_by_name (file_name);
154  if (module)
155    {
156      module->ref_count++;
157
158      return module;
159    }
160
161  /* open the module */
162  handle = _g_module_open (file_name, (flags & G_MODULE_BIND_LAZY) != 0);
163  if (handle)
164    {
165      gchar *saved_error;
166      GModuleCheckInit check_init;
167      gboolean check_failed = FALSE;
168
169      /* search the module list by handle, since file names are not unique */
170      module = g_module_find_by_handle (handle);
171      if (module)
172	{
173	  _g_module_close (module->handle, TRUE);
174	  module->ref_count++;
175	  g_module_set_error (NULL);
176
177	  return module;
178	}
179
180      saved_error = module_error;
181      module_error = NULL;
182      g_module_set_error (NULL);
183
184      module = g_new (GModule, 1);
185      module->file_name = g_strdup (file_name);
186      module->handle = handle;
187      module->ref_count = 1;
188      module->de_init = NULL;
189      module->next = modules;
190      modules = module;
191
192      /* check initialization */
193      if (g_module_symbol (module, "g_module_check_init", (gpointer) &check_init))
194	check_failed = check_init (module);
195
196      /* we don't call de_init() if the initialization check failed. */
197      if (!check_failed)
198	g_module_symbol (module, "g_module_de_init", (gpointer) &module->de_init);
199
200      if (check_failed)
201	{
202	  g_module_close (module);
203	  module = NULL;
204	  g_module_set_error ("GModule initialization check failed");
205	}
206      else
207	g_module_set_error (saved_error);
208      g_free (saved_error);
209    }
210
211  return module;
212}
213
214gboolean
215g_module_close (GModule	       *module)
216{
217  CHECK_ERROR (FALSE);
218
219  g_return_val_if_fail (module != NULL, FALSE);
220  g_return_val_if_fail (module->ref_count > 0, FALSE);
221
222  if (module != main_module)
223    module->ref_count--;
224
225  if (!module->ref_count && module->de_init)
226    module->de_init (module);
227  if (!module->ref_count)
228    {
229      GModule *last;
230      GModule *node;
231
232      last = NULL;
233      node = modules;
234      while (node)
235	{
236	  if (node == module)
237	    {
238	      if (last)
239		last->next = node->next;
240	      else
241		modules = node->next;
242	      break;
243	    }
244	  last = node;
245	  node = last->next;
246	}
247      module->next = NULL;
248
249      _g_module_close (module->handle, FALSE);
250      g_free (module->file_name);
251
252      g_free (module);
253    }
254
255  return module_error == NULL;
256}
257
258gchar*
259g_module_error (void)
260{
261  return module_error;
262}
263
264gboolean
265g_module_symbol (GModule	*module,
266		 const gchar	*symbol_name,
267		 gconstpointer	*symbol)
268{
269  if (symbol)
270    *symbol = NULL;
271  CHECK_ERROR (FALSE);
272
273  g_return_val_if_fail (module != NULL, FALSE);
274  g_return_val_if_fail (symbol_name != NULL, FALSE);
275  g_return_val_if_fail (symbol != NULL, FALSE);
276
277#ifdef	G_MODULE_NEED_USCORE
278  symbol_name = g_strconcat ("_", symbol_name, NULL);
279  *symbol = _g_module_symbol (module->handle, symbol_name);
280  g_free (symbol_name);
281#else	/* !G_MODULE_NEED_USCORE */
282  *symbol = _g_module_symbol (module->handle, symbol_name);
283#endif	/* !G_MODULE_NEED_USCORE */
284
285  if (module_error)
286    {
287      *symbol = NULL;
288      return FALSE;
289    }
290
291  return TRUE;
292}
293
294gchar*
295g_module_name (GModule *module)
296{
297  g_return_val_if_fail (module != NULL, NULL);
298
299  if (module == main_module)
300    return "main";
301
302  return module->file_name;
303}
304