Branch data Line data Source code
1 : : /* GObject - GLib Type, Object, Parameter and Signal Library
2 : : * Copyright (C) 2000 Red Hat, Inc.
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 : : */
19 : :
20 : : #include "config.h"
21 : :
22 : : #include <stdlib.h>
23 : :
24 : : #include "gtypeplugin.h"
25 : : #include "gtypemodule.h"
26 : :
27 : :
28 : : /**
29 : : * GTypeModule:
30 : : * @name: the name of the module
31 : : *
32 : : * `GTypeModule` provides a simple implementation of the `GTypePlugin`
33 : : * interface.
34 : : *
35 : : * The model of `GTypeModule` is a dynamically loaded module which
36 : : * implements some number of types and interface implementations.
37 : : *
38 : : * When the module is loaded, it registers its types and interfaces
39 : : * using [method@GObject.TypeModule.register_type] and
40 : : * [method@GObject.TypeModule.add_interface].
41 : : * As long as any instances of these types and interface implementations
42 : : * are in use, the module is kept loaded. When the types and interfaces
43 : : * are gone, the module may be unloaded. If the types and interfaces
44 : : * become used again, the module will be reloaded. Note that the last
45 : : * reference cannot be released from within the module code, since that
46 : : * would lead to the caller's code being unloaded before `g_object_unref()`
47 : : * returns to it.
48 : : *
49 : : * Keeping track of whether the module should be loaded or not is done by
50 : : * using a use count - it starts at zero, and whenever it is greater than
51 : : * zero, the module is loaded. The use count is maintained internally by
52 : : * the type system, but also can be explicitly controlled by
53 : : * [method@GObject.TypeModule.use] and [method@GObject.TypeModule.unuse].
54 : : * Typically, when loading a module for the first type, `g_type_module_use()`
55 : : * will be used to load it so that it can initialize its types. At some later
56 : : * point, when the module no longer needs to be loaded except for the type
57 : : * implementations it contains, `g_type_module_unuse()` is called.
58 : : *
59 : : * `GTypeModule` does not actually provide any implementation of module
60 : : * loading and unloading. To create a particular module type you must
61 : : * derive from `GTypeModule` and implement the load and unload functions
62 : : * in `GTypeModuleClass`.
63 : : */
64 : :
65 : : typedef struct _ModuleTypeInfo ModuleTypeInfo;
66 : : typedef struct _ModuleInterfaceInfo ModuleInterfaceInfo;
67 : :
68 : : struct _ModuleTypeInfo
69 : : {
70 : : gboolean loaded;
71 : : GType type;
72 : : GType parent_type;
73 : : GTypeInfo info;
74 : : };
75 : :
76 : : struct _ModuleInterfaceInfo
77 : : {
78 : : gboolean loaded;
79 : : GType instance_type;
80 : : GType interface_type;
81 : : GInterfaceInfo info;
82 : : };
83 : :
84 : : static void g_type_module_use_plugin (GTypePlugin *plugin);
85 : : static void g_type_module_complete_type_info (GTypePlugin *plugin,
86 : : GType g_type,
87 : : GTypeInfo *info,
88 : : GTypeValueTable *value_table);
89 : : static void g_type_module_complete_interface_info (GTypePlugin *plugin,
90 : : GType instance_type,
91 : : GType interface_type,
92 : : GInterfaceInfo *info);
93 : :
94 : : static gpointer parent_class = NULL;
95 : :
96 : : static void
97 : 2 : g_type_module_dispose (GObject *object)
98 : : {
99 : 2 : GTypeModule *module = G_TYPE_MODULE (object);
100 : :
101 [ + - - + ]: 2 : if (module->type_infos || module->interface_infos)
102 : : {
103 : 0 : g_critical (G_STRLOC ": unsolicitated invocation of g_object_run_dispose() on GTypeModule");
104 : :
105 : 0 : g_object_ref (object);
106 : : }
107 : :
108 : 2 : G_OBJECT_CLASS (parent_class)->dispose (object);
109 : 2 : }
110 : :
111 : : static void
112 : 2 : g_type_module_finalize (GObject *object)
113 : : {
114 : 2 : GTypeModule *module = G_TYPE_MODULE (object);
115 : :
116 : 2 : g_free (module->name);
117 : :
118 : 2 : G_OBJECT_CLASS (parent_class)->finalize (object);
119 : 2 : }
120 : :
121 : : static void
122 : 7 : g_type_module_class_init (GTypeModuleClass *class)
123 : : {
124 : 7 : GObjectClass *gobject_class = G_OBJECT_CLASS (class);
125 : :
126 : 7 : parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (class));
127 : :
128 : 7 : gobject_class->dispose = g_type_module_dispose;
129 : 7 : gobject_class->finalize = g_type_module_finalize;
130 : 7 : }
131 : :
132 : : static void
133 : 7 : g_type_module_iface_init (GTypePluginClass *iface)
134 : : {
135 : 7 : iface->use_plugin = g_type_module_use_plugin;
136 : 7 : iface->unuse_plugin = (void (*) (GTypePlugin *))g_type_module_unuse;
137 : 7 : iface->complete_type_info = g_type_module_complete_type_info;
138 : 7 : iface->complete_interface_info = g_type_module_complete_interface_info;
139 : 7 : }
140 : :
141 : : GType
142 : 69 : g_type_module_get_type (void)
143 : : {
144 : : static GType type_module_type = 0;
145 : :
146 [ + + ]: 69 : if (!type_module_type)
147 : : {
148 : 7 : const GTypeInfo type_module_info = {
149 : : sizeof (GTypeModuleClass),
150 : : NULL, /* base_init */
151 : : NULL, /* base_finalize */
152 : : (GClassInitFunc) g_type_module_class_init,
153 : : NULL, /* class_finalize */
154 : : NULL, /* class_data */
155 : : sizeof (GTypeModule),
156 : : 0, /* n_preallocs */
157 : : NULL, /* instance_init */
158 : : NULL, /* value_table */
159 : : };
160 : 7 : const GInterfaceInfo iface_info = {
161 : : (GInterfaceInitFunc) g_type_module_iface_init,
162 : : NULL, /* interface_finalize */
163 : : NULL, /* interface_data */
164 : : };
165 : :
166 : 7 : type_module_type = g_type_register_static (G_TYPE_OBJECT, g_intern_static_string ("GTypeModule"), &type_module_info, G_TYPE_FLAG_ABSTRACT);
167 : :
168 : 7 : g_type_add_interface_static (type_module_type, G_TYPE_TYPE_PLUGIN, &iface_info);
169 : : }
170 : :
171 : 69 : return type_module_type;
172 : : }
173 : :
174 : : /**
175 : : * g_type_module_set_name:
176 : : * @module: a #GTypeModule.
177 : : * @name: a human-readable name to use in error messages.
178 : : *
179 : : * Sets the name for a #GTypeModule
180 : : */
181 : : void
182 : 0 : g_type_module_set_name (GTypeModule *module,
183 : : const gchar *name)
184 : : {
185 : 0 : g_return_if_fail (G_IS_TYPE_MODULE (module));
186 : :
187 : 0 : g_free (module->name);
188 : 0 : module->name = g_strdup (name);
189 : : }
190 : :
191 : : static ModuleTypeInfo *
192 : 8 : g_type_module_find_type_info (GTypeModule *module,
193 : : GType type)
194 : : {
195 : 8 : GSList *tmp_list = module->type_infos;
196 [ + - ]: 8 : while (tmp_list)
197 : : {
198 : 8 : ModuleTypeInfo *type_info = tmp_list->data;
199 [ + - ]: 8 : if (type_info->type == type)
200 : 8 : return type_info;
201 : :
202 : 0 : tmp_list = tmp_list->next;
203 : : }
204 : :
205 : 0 : return NULL;
206 : : }
207 : :
208 : : static ModuleInterfaceInfo *
209 : 4 : g_type_module_find_interface_info (GTypeModule *module,
210 : : GType instance_type,
211 : : GType interface_type)
212 : : {
213 : 4 : GSList *tmp_list = module->interface_infos;
214 [ + - ]: 4 : while (tmp_list)
215 : : {
216 : 4 : ModuleInterfaceInfo *interface_info = tmp_list->data;
217 [ + - ]: 4 : if (interface_info->instance_type == instance_type &&
218 [ + - ]: 4 : interface_info->interface_type == interface_type)
219 : 4 : return interface_info;
220 : :
221 : 0 : tmp_list = tmp_list->next;
222 : : }
223 : :
224 : 0 : return NULL;
225 : : }
226 : :
227 : : /**
228 : : * g_type_module_use:
229 : : * @module: a #GTypeModule
230 : : *
231 : : * Increases the use count of a #GTypeModule by one. If the
232 : : * use count was zero before, the plugin will be loaded.
233 : : * If loading the plugin fails, the use count is reset to
234 : : * its prior value.
235 : : *
236 : : * Returns: %FALSE if the plugin needed to be loaded and
237 : : * loading the plugin failed.
238 : : */
239 : : gboolean
240 : 14 : g_type_module_use (GTypeModule *module)
241 : : {
242 : 14 : g_return_val_if_fail (G_IS_TYPE_MODULE (module), FALSE);
243 : :
244 : 14 : module->use_count++;
245 [ + + ]: 14 : if (module->use_count == 1)
246 : : {
247 : : GSList *tmp_list;
248 : :
249 [ - + ]: 12 : if (!G_TYPE_MODULE_GET_CLASS (module)->load (module))
250 : : {
251 : 0 : module->use_count--;
252 : 0 : return FALSE;
253 : : }
254 : :
255 : 12 : tmp_list = module->type_infos;
256 [ + + ]: 20 : while (tmp_list)
257 : : {
258 : 8 : ModuleTypeInfo *type_info = tmp_list->data;
259 [ - + ]: 8 : if (!type_info->loaded)
260 : : {
261 [ # # ]: 0 : g_critical ("plugin '%s' failed to register type '%s'",
262 : : module->name ? module->name : "(unknown)",
263 : : g_type_name (type_info->type));
264 : 0 : module->use_count--;
265 : 0 : return FALSE;
266 : : }
267 : :
268 : 8 : tmp_list = tmp_list->next;
269 : : }
270 : : }
271 : :
272 : 14 : return TRUE;
273 : : }
274 : :
275 : : /**
276 : : * g_type_module_unuse:
277 : : * @module: a #GTypeModule
278 : : *
279 : : * Decreases the use count of a #GTypeModule by one. If the
280 : : * result is zero, the module will be unloaded. (However, the
281 : : * #GTypeModule will not be freed, and types associated with the
282 : : * #GTypeModule are not unregistered. Once a #GTypeModule is
283 : : * initialized, it must exist forever.)
284 : : */
285 : : void
286 : 8 : g_type_module_unuse (GTypeModule *module)
287 : : {
288 : 8 : g_return_if_fail (G_IS_TYPE_MODULE (module));
289 : 8 : g_return_if_fail (module->use_count > 0);
290 : :
291 : 8 : module->use_count--;
292 : :
293 [ + - ]: 8 : if (module->use_count == 0)
294 : : {
295 : : GSList *tmp_list;
296 : :
297 : 8 : G_TYPE_MODULE_GET_CLASS (module)->unload (module);
298 : :
299 : 8 : tmp_list = module->type_infos;
300 [ + + ]: 12 : while (tmp_list)
301 : : {
302 : 4 : ModuleTypeInfo *type_info = tmp_list->data;
303 : 4 : type_info->loaded = FALSE;
304 : :
305 : 4 : tmp_list = tmp_list->next;
306 : : }
307 : : }
308 : : }
309 : :
310 : : static void
311 : 6 : g_type_module_use_plugin (GTypePlugin *plugin)
312 : : {
313 : 6 : GTypeModule *module = G_TYPE_MODULE (plugin);
314 : :
315 [ - + ]: 6 : if (!g_type_module_use (module))
316 : : {
317 [ # # ]: 0 : g_error ("Fatal error - Could not reload previously loaded plugin '%s'",
318 : : module->name ? module->name : "(unknown)");
319 : : }
320 : 6 : }
321 : :
322 : : static void
323 : 4 : g_type_module_complete_type_info (GTypePlugin *plugin,
324 : : GType g_type,
325 : : GTypeInfo *info,
326 : : GTypeValueTable *value_table)
327 : : {
328 : 4 : GTypeModule *module = G_TYPE_MODULE (plugin);
329 : 4 : ModuleTypeInfo *module_type_info = g_type_module_find_type_info (module, g_type);
330 : :
331 : 4 : *info = module_type_info->info;
332 : :
333 [ - + ]: 4 : if (module_type_info->info.value_table)
334 : 0 : *value_table = *module_type_info->info.value_table;
335 : 4 : }
336 : :
337 : : static void
338 : 2 : g_type_module_complete_interface_info (GTypePlugin *plugin,
339 : : GType instance_type,
340 : : GType interface_type,
341 : : GInterfaceInfo *info)
342 : : {
343 : 2 : GTypeModule *module = G_TYPE_MODULE (plugin);
344 : 2 : ModuleInterfaceInfo *module_interface_info = g_type_module_find_interface_info (module, instance_type, interface_type);
345 : :
346 : 2 : *info = module_interface_info->info;
347 : 2 : }
348 : :
349 : : /**
350 : : * g_type_module_register_type:
351 : : * @module: (nullable): a #GTypeModule
352 : : * @parent_type: the type for the parent class
353 : : * @type_name: name for the type
354 : : * @type_info: type information structure
355 : : * @flags: flags field providing details about the type
356 : : *
357 : : * Looks up or registers a type that is implemented with a particular
358 : : * type plugin. If a type with name @type_name was previously registered,
359 : : * the #GType identifier for the type is returned, otherwise the type
360 : : * is newly registered, and the resulting #GType identifier returned.
361 : : *
362 : : * When reregistering a type (typically because a module is unloaded
363 : : * then reloaded, and reinitialized), @module and @parent_type must
364 : : * be the same as they were previously.
365 : : *
366 : : * As long as any instances of the type exist, the type plugin will
367 : : * not be unloaded.
368 : : *
369 : : * Since 2.56 if @module is %NULL this will call g_type_register_static()
370 : : * instead. This can be used when making a static build of the module.
371 : : *
372 : : * Returns: the new or existing type ID
373 : : */
374 : : GType
375 : 8 : g_type_module_register_type (GTypeModule *module,
376 : : GType parent_type,
377 : : const gchar *type_name,
378 : : const GTypeInfo *type_info,
379 : : GTypeFlags flags)
380 : : {
381 : 8 : ModuleTypeInfo *module_type_info = NULL;
382 : : GType type;
383 : :
384 : 8 : g_return_val_if_fail (type_name != NULL, 0);
385 : 8 : g_return_val_if_fail (type_info != NULL, 0);
386 : :
387 [ - + ]: 8 : if (module == NULL)
388 : : {
389 : : /* Cannot pass type_info directly to g_type_register_static() here because
390 : : * it has class_finalize != NULL and that's forbidden for static types */
391 : 0 : return g_type_register_static_simple (parent_type,
392 : : type_name,
393 : 0 : type_info->class_size,
394 : 0 : type_info->class_init,
395 : 0 : type_info->instance_size,
396 : 0 : type_info->instance_init,
397 : : flags);
398 : : }
399 : :
400 : 8 : type = g_type_from_name (type_name);
401 [ + + ]: 8 : if (type)
402 : : {
403 : 4 : GTypePlugin *old_plugin = g_type_get_plugin (type);
404 : :
405 [ - + ]: 4 : if (old_plugin != G_TYPE_PLUGIN (module))
406 : : {
407 : 0 : g_critical ("Two different plugins tried to register '%s'.", type_name);
408 : 0 : return 0;
409 : : }
410 : : }
411 : :
412 [ + + ]: 8 : if (type)
413 : : {
414 : 4 : module_type_info = g_type_module_find_type_info (module, type);
415 : :
416 [ - + ]: 4 : if (module_type_info->parent_type != parent_type)
417 : : {
418 : 0 : const gchar *parent_type_name = g_type_name (parent_type);
419 : :
420 [ # # ]: 0 : g_critical ("Type '%s' recreated with different parent type."
421 : : "(was '%s', now '%s')", type_name,
422 : : g_type_name (module_type_info->parent_type),
423 : : parent_type_name ? parent_type_name : "(unknown)");
424 : 0 : return 0;
425 : : }
426 : :
427 [ - + ]: 4 : if (module_type_info->info.value_table)
428 : 0 : g_free ((GTypeValueTable *) module_type_info->info.value_table);
429 : : }
430 : : else
431 : : {
432 : 4 : module_type_info = g_new (ModuleTypeInfo, 1);
433 : :
434 : 4 : module_type_info->parent_type = parent_type;
435 : 4 : module_type_info->type = g_type_register_dynamic (parent_type, type_name, G_TYPE_PLUGIN (module), flags);
436 : :
437 : 4 : module->type_infos = g_slist_prepend (module->type_infos, module_type_info);
438 : : }
439 : :
440 : 8 : module_type_info->loaded = TRUE;
441 : 8 : module_type_info->info = *type_info;
442 [ - + ]: 8 : if (type_info->value_table)
443 : 0 : module_type_info->info.value_table = g_memdup2 (type_info->value_table,
444 : : sizeof (GTypeValueTable));
445 : :
446 : 8 : return module_type_info->type;
447 : : }
448 : :
449 : : /**
450 : : * g_type_module_add_interface:
451 : : * @module: (nullable): a #GTypeModule
452 : : * @instance_type: type to which to add the interface.
453 : : * @interface_type: interface type to add
454 : : * @interface_info: type information structure
455 : : *
456 : : * Registers an additional interface for a type, whose interface lives
457 : : * in the given type plugin. If the interface was already registered
458 : : * for the type in this plugin, nothing will be done.
459 : : *
460 : : * As long as any instances of the type exist, the type plugin will
461 : : * not be unloaded.
462 : : *
463 : : * Since 2.56 if @module is %NULL this will call g_type_add_interface_static()
464 : : * instead. This can be used when making a static build of the module.
465 : : */
466 : : void
467 : 4 : g_type_module_add_interface (GTypeModule *module,
468 : : GType instance_type,
469 : : GType interface_type,
470 : : const GInterfaceInfo *interface_info)
471 : : {
472 : 4 : ModuleInterfaceInfo *module_interface_info = NULL;
473 : :
474 : 4 : g_return_if_fail (interface_info != NULL);
475 : :
476 [ - + ]: 4 : if (module == NULL)
477 : : {
478 : 0 : g_type_add_interface_static (instance_type, interface_type, interface_info);
479 : 0 : return;
480 : : }
481 : :
482 [ + - + + ]: 4 : if (g_type_is_a (instance_type, interface_type))
483 : 2 : {
484 : 2 : GTypePlugin *old_plugin = g_type_interface_get_plugin (instance_type,
485 : : interface_type);
486 : :
487 [ - + ]: 2 : if (!old_plugin)
488 : : {
489 : 0 : g_critical ("Interface '%s' for '%s' was previously registered statically or for a parent type.",
490 : : g_type_name (interface_type), g_type_name (instance_type));
491 : 0 : return;
492 : : }
493 [ - + ]: 2 : else if (old_plugin != G_TYPE_PLUGIN (module))
494 : : {
495 : 0 : g_critical ("Two different plugins tried to register interface '%s' for '%s'.",
496 : : g_type_name (interface_type), g_type_name (instance_type));
497 : 0 : return;
498 : : }
499 : :
500 : 2 : module_interface_info = g_type_module_find_interface_info (module, instance_type, interface_type);
501 : :
502 : 2 : g_assert (module_interface_info);
503 : : }
504 : : else
505 : : {
506 : 2 : module_interface_info = g_new (ModuleInterfaceInfo, 1);
507 : :
508 : 2 : module_interface_info->instance_type = instance_type;
509 : 2 : module_interface_info->interface_type = interface_type;
510 : :
511 : 2 : g_type_add_interface_dynamic (instance_type, interface_type, G_TYPE_PLUGIN (module));
512 : :
513 : 2 : module->interface_infos = g_slist_prepend (module->interface_infos, module_interface_info);
514 : : }
515 : :
516 : 4 : module_interface_info->loaded = TRUE;
517 : 4 : module_interface_info->info = *interface_info;
518 : : }
519 : :
520 : : /**
521 : : * g_type_module_register_enum:
522 : : * @module: (nullable): a #GTypeModule
523 : : * @name: name for the type
524 : : * @const_static_values: an array of #GEnumValue structs for the
525 : : * possible enumeration values. The array is
526 : : * terminated by a struct with all members being
527 : : * 0.
528 : : *
529 : : * Looks up or registers an enumeration that is implemented with a particular
530 : : * type plugin. If a type with name @type_name was previously registered,
531 : : * the #GType identifier for the type is returned, otherwise the type
532 : : * is newly registered, and the resulting #GType identifier returned.
533 : : *
534 : : * As long as any instances of the type exist, the type plugin will
535 : : * not be unloaded.
536 : : *
537 : : * Since 2.56 if @module is %NULL this will call g_type_register_static()
538 : : * instead. This can be used when making a static build of the module.
539 : : *
540 : : * Since: 2.6
541 : : *
542 : : * Returns: the new or existing type ID
543 : : */
544 : : GType
545 : 0 : g_type_module_register_enum (GTypeModule *module,
546 : : const gchar *name,
547 : : const GEnumValue *const_static_values)
548 : : {
549 : 0 : GTypeInfo enum_type_info = { 0, };
550 : :
551 : 0 : g_return_val_if_fail (module == NULL || G_IS_TYPE_MODULE (module), 0);
552 : 0 : g_return_val_if_fail (name != NULL, 0);
553 : 0 : g_return_val_if_fail (const_static_values != NULL, 0);
554 : :
555 : 0 : g_enum_complete_type_info (G_TYPE_ENUM,
556 : : &enum_type_info, const_static_values);
557 : :
558 : 0 : return g_type_module_register_type (G_TYPE_MODULE (module),
559 : : G_TYPE_ENUM, name, &enum_type_info, 0);
560 : : }
561 : :
562 : : /**
563 : : * g_type_module_register_flags:
564 : : * @module: (nullable): a #GTypeModule
565 : : * @name: name for the type
566 : : * @const_static_values: an array of #GFlagsValue structs for the
567 : : * possible flags values. The array is
568 : : * terminated by a struct with all members being
569 : : * 0.
570 : : *
571 : : * Looks up or registers a flags type that is implemented with a particular
572 : : * type plugin. If a type with name @type_name was previously registered,
573 : : * the #GType identifier for the type is returned, otherwise the type
574 : : * is newly registered, and the resulting #GType identifier returned.
575 : : *
576 : : * As long as any instances of the type exist, the type plugin will
577 : : * not be unloaded.
578 : : *
579 : : * Since 2.56 if @module is %NULL this will call g_type_register_static()
580 : : * instead. This can be used when making a static build of the module.
581 : : *
582 : : * Since: 2.6
583 : : *
584 : : * Returns: the new or existing type ID
585 : : */
586 : : GType
587 : 0 : g_type_module_register_flags (GTypeModule *module,
588 : : const gchar *name,
589 : : const GFlagsValue *const_static_values)
590 : : {
591 : 0 : GTypeInfo flags_type_info = { 0, };
592 : :
593 : 0 : g_return_val_if_fail (module == NULL || G_IS_TYPE_MODULE (module), 0);
594 : 0 : g_return_val_if_fail (name != NULL, 0);
595 : 0 : g_return_val_if_fail (const_static_values != NULL, 0);
596 : :
597 : 0 : g_flags_complete_type_info (G_TYPE_FLAGS,
598 : : &flags_type_info, const_static_values);
599 : :
600 : 0 : return g_type_module_register_type (G_TYPE_MODULE (module),
601 : : G_TYPE_FLAGS, name, &flags_type_info, 0);
602 : : }
|