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 : : /* in case a subclass does not chain-up to parent in dispose() */
119 : 2 : g_assert (module->type_infos == NULL);
120 : 2 : g_assert (module->interface_infos == NULL);
121 : :
122 : 2 : G_OBJECT_CLASS (parent_class)->finalize (object);
123 : 2 : }
124 : :
125 : : static void
126 : 9 : g_type_module_class_init (GTypeModuleClass *class)
127 : : {
128 : 9 : GObjectClass *gobject_class = G_OBJECT_CLASS (class);
129 : :
130 : 9 : parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (class));
131 : :
132 : 9 : gobject_class->dispose = g_type_module_dispose;
133 : 9 : gobject_class->finalize = g_type_module_finalize;
134 : 9 : }
135 : :
136 : : static void
137 : 9 : g_type_module_iface_init (GTypePluginClass *iface)
138 : : {
139 : 9 : iface->use_plugin = g_type_module_use_plugin;
140 : 9 : iface->unuse_plugin = (void (*) (GTypePlugin *))g_type_module_unuse;
141 : 9 : iface->complete_type_info = g_type_module_complete_type_info;
142 : 9 : iface->complete_interface_info = g_type_module_complete_interface_info;
143 : 9 : }
144 : :
145 : : GType
146 : 72 : g_type_module_get_type (void)
147 : : {
148 : : static GType type_module_type = 0;
149 : :
150 : 72 : if (!type_module_type)
151 : : {
152 : 9 : const GTypeInfo type_module_info = {
153 : : sizeof (GTypeModuleClass),
154 : : NULL, /* base_init */
155 : : NULL, /* base_finalize */
156 : : (GClassInitFunc) g_type_module_class_init,
157 : : NULL, /* class_finalize */
158 : : NULL, /* class_data */
159 : : sizeof (GTypeModule),
160 : : 0, /* n_preallocs */
161 : : NULL, /* instance_init */
162 : : NULL, /* value_table */
163 : : };
164 : 9 : const GInterfaceInfo iface_info = {
165 : : (GInterfaceInitFunc) g_type_module_iface_init,
166 : : NULL, /* interface_finalize */
167 : : NULL, /* interface_data */
168 : : };
169 : :
170 : 9 : type_module_type = g_type_register_static (G_TYPE_OBJECT, g_intern_static_string ("GTypeModule"), &type_module_info, G_TYPE_FLAG_ABSTRACT);
171 : :
172 : 9 : g_type_add_interface_static (type_module_type, G_TYPE_TYPE_PLUGIN, &iface_info);
173 : : }
174 : :
175 : 72 : return type_module_type;
176 : : }
177 : :
178 : : /**
179 : : * g_type_module_set_name:
180 : : * @module: a #GTypeModule.
181 : : * @name: a human-readable name to use in error messages.
182 : : *
183 : : * Sets the name for a #GTypeModule
184 : : */
185 : : void
186 : 0 : g_type_module_set_name (GTypeModule *module,
187 : : const gchar *name)
188 : : {
189 : 0 : g_return_if_fail (G_IS_TYPE_MODULE (module));
190 : :
191 : 0 : g_free (module->name);
192 : 0 : module->name = g_strdup (name);
193 : : }
194 : :
195 : : static ModuleTypeInfo *
196 : 8 : g_type_module_find_type_info (GTypeModule *module,
197 : : GType type)
198 : : {
199 : 8 : GSList *tmp_list = module->type_infos;
200 : 8 : while (tmp_list)
201 : : {
202 : 8 : ModuleTypeInfo *type_info = tmp_list->data;
203 : 8 : if (type_info->type == type)
204 : 8 : return type_info;
205 : :
206 : 0 : tmp_list = tmp_list->next;
207 : : }
208 : :
209 : 0 : return NULL;
210 : : }
211 : :
212 : : static ModuleInterfaceInfo *
213 : 4 : g_type_module_find_interface_info (GTypeModule *module,
214 : : GType instance_type,
215 : : GType interface_type)
216 : : {
217 : 4 : GSList *tmp_list = module->interface_infos;
218 : 4 : while (tmp_list)
219 : : {
220 : 4 : ModuleInterfaceInfo *interface_info = tmp_list->data;
221 : 4 : if (interface_info->instance_type == instance_type &&
222 : 4 : interface_info->interface_type == interface_type)
223 : 4 : return interface_info;
224 : :
225 : 0 : tmp_list = tmp_list->next;
226 : : }
227 : :
228 : 0 : return NULL;
229 : : }
230 : :
231 : : /**
232 : : * g_type_module_use:
233 : : * @module: a #GTypeModule
234 : : *
235 : : * Increases the use count of a #GTypeModule by one. If the
236 : : * use count was zero before, the plugin will be loaded.
237 : : * If loading the plugin fails, the use count is reset to
238 : : * its prior value.
239 : : *
240 : : * Returns: %FALSE if the plugin needed to be loaded and
241 : : * loading the plugin failed.
242 : : */
243 : : gboolean
244 : 14 : g_type_module_use (GTypeModule *module)
245 : : {
246 : 14 : g_return_val_if_fail (G_IS_TYPE_MODULE (module), FALSE);
247 : :
248 : 14 : module->use_count++;
249 : 14 : if (module->use_count == 1)
250 : : {
251 : : GSList *tmp_list;
252 : :
253 : 12 : if (!G_TYPE_MODULE_GET_CLASS (module)->load (module))
254 : : {
255 : 0 : module->use_count--;
256 : 0 : return FALSE;
257 : : }
258 : :
259 : 12 : tmp_list = module->type_infos;
260 : 20 : while (tmp_list)
261 : : {
262 : 8 : ModuleTypeInfo *type_info = tmp_list->data;
263 : 8 : if (!type_info->loaded)
264 : : {
265 : 0 : g_critical ("plugin '%s' failed to register type '%s'",
266 : : module->name ? module->name : "(unknown)",
267 : : g_type_name (type_info->type));
268 : 0 : module->use_count--;
269 : 0 : return FALSE;
270 : : }
271 : :
272 : 8 : tmp_list = tmp_list->next;
273 : : }
274 : : }
275 : :
276 : 14 : return TRUE;
277 : : }
278 : :
279 : : /**
280 : : * g_type_module_unuse:
281 : : * @module: a #GTypeModule
282 : : *
283 : : * Decreases the use count of a #GTypeModule by one. If the
284 : : * result is zero, the module will be unloaded. (However, the
285 : : * #GTypeModule will not be freed, and types associated with the
286 : : * #GTypeModule are not unregistered. Once a #GTypeModule is
287 : : * initialized, it must exist forever.)
288 : : */
289 : : void
290 : 8 : g_type_module_unuse (GTypeModule *module)
291 : : {
292 : 8 : g_return_if_fail (G_IS_TYPE_MODULE (module));
293 : 8 : g_return_if_fail (module->use_count > 0);
294 : :
295 : 8 : module->use_count--;
296 : :
297 : 8 : if (module->use_count == 0)
298 : : {
299 : : GSList *tmp_list;
300 : :
301 : 8 : G_TYPE_MODULE_GET_CLASS (module)->unload (module);
302 : :
303 : 8 : tmp_list = module->type_infos;
304 : 12 : while (tmp_list)
305 : : {
306 : 4 : ModuleTypeInfo *type_info = tmp_list->data;
307 : 4 : type_info->loaded = FALSE;
308 : :
309 : 4 : tmp_list = tmp_list->next;
310 : : }
311 : : }
312 : : }
313 : :
314 : : static void
315 : 6 : g_type_module_use_plugin (GTypePlugin *plugin)
316 : : {
317 : 6 : GTypeModule *module = G_TYPE_MODULE (plugin);
318 : :
319 : 6 : if (!g_type_module_use (module))
320 : : {
321 : 0 : g_error ("Fatal error - Could not reload previously loaded plugin '%s'",
322 : : module->name ? module->name : "(unknown)");
323 : : }
324 : 6 : }
325 : :
326 : : static void
327 : 4 : g_type_module_complete_type_info (GTypePlugin *plugin,
328 : : GType g_type,
329 : : GTypeInfo *info,
330 : : GTypeValueTable *value_table)
331 : : {
332 : 4 : GTypeModule *module = G_TYPE_MODULE (plugin);
333 : 4 : ModuleTypeInfo *module_type_info = g_type_module_find_type_info (module, g_type);
334 : :
335 : 4 : *info = module_type_info->info;
336 : :
337 : 4 : if (module_type_info->info.value_table)
338 : 0 : *value_table = *module_type_info->info.value_table;
339 : 4 : }
340 : :
341 : : static void
342 : 2 : g_type_module_complete_interface_info (GTypePlugin *plugin,
343 : : GType instance_type,
344 : : GType interface_type,
345 : : GInterfaceInfo *info)
346 : : {
347 : 2 : GTypeModule *module = G_TYPE_MODULE (plugin);
348 : 2 : ModuleInterfaceInfo *module_interface_info = g_type_module_find_interface_info (module, instance_type, interface_type);
349 : :
350 : 2 : *info = module_interface_info->info;
351 : 2 : }
352 : :
353 : : /**
354 : : * g_type_module_register_type:
355 : : * @module: (nullable): a #GTypeModule
356 : : * @parent_type: the type for the parent class
357 : : * @type_name: name for the type
358 : : * @type_info: type information structure
359 : : * @flags: flags field providing details about the type
360 : : *
361 : : * Looks up or registers a type that is implemented with a particular
362 : : * type plugin. If a type with name @type_name was previously registered,
363 : : * the #GType identifier for the type is returned, otherwise the type
364 : : * is newly registered, and the resulting #GType identifier returned.
365 : : *
366 : : * When reregistering a type (typically because a module is unloaded
367 : : * then reloaded, and reinitialized), @module and @parent_type must
368 : : * be the same as they were previously.
369 : : *
370 : : * As long as any instances of the type exist, the type plugin will
371 : : * not be unloaded.
372 : : *
373 : : * Since 2.56 if @module is %NULL this will call g_type_register_static()
374 : : * instead. This can be used when making a static build of the module.
375 : : *
376 : : * Returns: the new or existing type ID
377 : : */
378 : : GType
379 : 8 : g_type_module_register_type (GTypeModule *module,
380 : : GType parent_type,
381 : : const gchar *type_name,
382 : : const GTypeInfo *type_info,
383 : : GTypeFlags flags)
384 : : {
385 : 8 : ModuleTypeInfo *module_type_info = NULL;
386 : : GType type;
387 : :
388 : 8 : g_return_val_if_fail (type_name != NULL, 0);
389 : 8 : g_return_val_if_fail (type_info != NULL, 0);
390 : :
391 : 8 : if (module == NULL)
392 : : {
393 : : /* Cannot pass type_info directly to g_type_register_static() here because
394 : : * it has class_finalize != NULL and that's forbidden for static types */
395 : 0 : return g_type_register_static_simple (parent_type,
396 : : type_name,
397 : 0 : type_info->class_size,
398 : 0 : type_info->class_init,
399 : 0 : type_info->instance_size,
400 : 0 : type_info->instance_init,
401 : : flags);
402 : : }
403 : :
404 : 8 : type = g_type_from_name (type_name);
405 : 8 : if (type)
406 : : {
407 : 4 : GTypePlugin *old_plugin = g_type_get_plugin (type);
408 : :
409 : 4 : if (old_plugin != G_TYPE_PLUGIN (module))
410 : : {
411 : 0 : g_critical ("Two different plugins tried to register '%s'.", type_name);
412 : 0 : return 0;
413 : : }
414 : : }
415 : :
416 : 8 : if (type)
417 : : {
418 : 4 : module_type_info = g_type_module_find_type_info (module, type);
419 : :
420 : 4 : if (module_type_info->parent_type != parent_type)
421 : : {
422 : 0 : const gchar *parent_type_name = g_type_name (parent_type);
423 : :
424 : 0 : g_critical ("Type '%s' recreated with different parent type."
425 : : "(was '%s', now '%s')", type_name,
426 : : g_type_name (module_type_info->parent_type),
427 : : parent_type_name ? parent_type_name : "(unknown)");
428 : 0 : return 0;
429 : : }
430 : :
431 : 4 : if (module_type_info->info.value_table)
432 : 0 : g_free ((GTypeValueTable *) module_type_info->info.value_table);
433 : : }
434 : : else
435 : : {
436 : 4 : module_type_info = g_new (ModuleTypeInfo, 1);
437 : :
438 : 4 : module_type_info->parent_type = parent_type;
439 : 4 : module_type_info->type = g_type_register_dynamic (parent_type, type_name, G_TYPE_PLUGIN (module), flags);
440 : :
441 : 4 : module->type_infos = g_slist_prepend (module->type_infos, module_type_info);
442 : : }
443 : :
444 : 8 : module_type_info->loaded = TRUE;
445 : 8 : module_type_info->info = *type_info;
446 : 8 : if (type_info->value_table)
447 : 0 : module_type_info->info.value_table = g_memdup2 (type_info->value_table,
448 : : sizeof (GTypeValueTable));
449 : :
450 : 8 : return module_type_info->type;
451 : : }
452 : :
453 : : /**
454 : : * g_type_module_add_interface:
455 : : * @module: (nullable): a #GTypeModule
456 : : * @instance_type: type to which to add the interface.
457 : : * @interface_type: interface type to add
458 : : * @interface_info: type information structure
459 : : *
460 : : * Registers an additional interface for a type, whose interface lives
461 : : * in the given type plugin. If the interface was already registered
462 : : * for the type in this plugin, nothing will be done.
463 : : *
464 : : * As long as any instances of the type exist, the type plugin will
465 : : * not be unloaded.
466 : : *
467 : : * Since 2.56 if @module is %NULL this will call g_type_add_interface_static()
468 : : * instead. This can be used when making a static build of the module.
469 : : */
470 : : void
471 : 4 : g_type_module_add_interface (GTypeModule *module,
472 : : GType instance_type,
473 : : GType interface_type,
474 : : const GInterfaceInfo *interface_info)
475 : : {
476 : 4 : ModuleInterfaceInfo *module_interface_info = NULL;
477 : :
478 : 4 : g_return_if_fail (interface_info != NULL);
479 : :
480 : 4 : if (module == NULL)
481 : : {
482 : 0 : g_type_add_interface_static (instance_type, interface_type, interface_info);
483 : 0 : return;
484 : : }
485 : :
486 : 4 : if (g_type_is_a (instance_type, interface_type))
487 : 2 : {
488 : 2 : GTypePlugin *old_plugin = g_type_interface_get_plugin (instance_type,
489 : : interface_type);
490 : :
491 : 2 : if (!old_plugin)
492 : : {
493 : 0 : g_critical ("Interface '%s' for '%s' was previously registered statically or for a parent type.",
494 : : g_type_name (interface_type), g_type_name (instance_type));
495 : 0 : return;
496 : : }
497 : 2 : else if (old_plugin != G_TYPE_PLUGIN (module))
498 : : {
499 : 0 : g_critical ("Two different plugins tried to register interface '%s' for '%s'.",
500 : : g_type_name (interface_type), g_type_name (instance_type));
501 : 0 : return;
502 : : }
503 : :
504 : 2 : module_interface_info = g_type_module_find_interface_info (module, instance_type, interface_type);
505 : :
506 : 2 : g_assert (module_interface_info);
507 : : }
508 : : else
509 : : {
510 : 2 : module_interface_info = g_new (ModuleInterfaceInfo, 1);
511 : :
512 : 2 : module_interface_info->instance_type = instance_type;
513 : 2 : module_interface_info->interface_type = interface_type;
514 : :
515 : 2 : g_type_add_interface_dynamic (instance_type, interface_type, G_TYPE_PLUGIN (module));
516 : :
517 : 2 : module->interface_infos = g_slist_prepend (module->interface_infos, module_interface_info);
518 : : }
519 : :
520 : 4 : module_interface_info->loaded = TRUE;
521 : 4 : module_interface_info->info = *interface_info;
522 : : }
523 : :
524 : : /**
525 : : * g_type_module_register_enum:
526 : : * @module: (nullable): a #GTypeModule
527 : : * @name: name for the type
528 : : * @const_static_values: an array of #GEnumValue structs for the
529 : : * possible enumeration values. The array is
530 : : * terminated by a struct with all members being
531 : : * 0.
532 : : *
533 : : * Looks up or registers an enumeration that is implemented with a particular
534 : : * type plugin. If a type with name @type_name was previously registered,
535 : : * the #GType identifier for the type is returned, otherwise the type
536 : : * is newly registered, and the resulting #GType identifier returned.
537 : : *
538 : : * As long as any instances of the type exist, the type plugin will
539 : : * not be unloaded.
540 : : *
541 : : * Since 2.56 if @module is %NULL this will call g_type_register_static()
542 : : * instead. This can be used when making a static build of the module.
543 : : *
544 : : * Since: 2.6
545 : : *
546 : : * Returns: the new or existing type ID
547 : : */
548 : : GType
549 : 0 : g_type_module_register_enum (GTypeModule *module,
550 : : const gchar *name,
551 : : const GEnumValue *const_static_values)
552 : : {
553 : 0 : GTypeInfo enum_type_info = { 0, };
554 : :
555 : 0 : g_return_val_if_fail (module == NULL || G_IS_TYPE_MODULE (module), 0);
556 : 0 : g_return_val_if_fail (name != NULL, 0);
557 : 0 : g_return_val_if_fail (const_static_values != NULL, 0);
558 : :
559 : 0 : g_enum_complete_type_info (G_TYPE_ENUM,
560 : : &enum_type_info, const_static_values);
561 : :
562 : 0 : return g_type_module_register_type (G_TYPE_MODULE (module),
563 : : G_TYPE_ENUM, name, &enum_type_info, 0);
564 : : }
565 : :
566 : : /**
567 : : * g_type_module_register_flags:
568 : : * @module: (nullable): a #GTypeModule
569 : : * @name: name for the type
570 : : * @const_static_values: an array of #GFlagsValue structs for the
571 : : * possible flags values. The array is
572 : : * terminated by a struct with all members being
573 : : * 0.
574 : : *
575 : : * Looks up or registers a flags type that is implemented with a particular
576 : : * type plugin. If a type with name @type_name was previously registered,
577 : : * the #GType identifier for the type is returned, otherwise the type
578 : : * is newly registered, and the resulting #GType identifier returned.
579 : : *
580 : : * As long as any instances of the type exist, the type plugin will
581 : : * not be unloaded.
582 : : *
583 : : * Since 2.56 if @module is %NULL this will call g_type_register_static()
584 : : * instead. This can be used when making a static build of the module.
585 : : *
586 : : * Since: 2.6
587 : : *
588 : : * Returns: the new or existing type ID
589 : : */
590 : : GType
591 : 0 : g_type_module_register_flags (GTypeModule *module,
592 : : const gchar *name,
593 : : const GFlagsValue *const_static_values)
594 : : {
595 : 0 : GTypeInfo flags_type_info = { 0, };
596 : :
597 : 0 : g_return_val_if_fail (module == NULL || G_IS_TYPE_MODULE (module), 0);
598 : 0 : g_return_val_if_fail (name != NULL, 0);
599 : 0 : g_return_val_if_fail (const_static_values != NULL, 0);
600 : :
601 : 0 : g_flags_complete_type_info (G_TYPE_FLAGS,
602 : : &flags_type_info, const_static_values);
603 : :
604 : 0 : return g_type_module_register_type (G_TYPE_MODULE (module),
605 : : G_TYPE_FLAGS, name, &flags_type_info, 0);
606 : : }
|