Decouple component class from plugin subsystem, remove component factory
[babeltrace.git] / lib / plugin / plugin.c
CommitLineData
33b34c43
PP
1/*
2 * plugin.c
3 *
4 * Babeltrace Plugin
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
8 *
9 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 */
29
30#include <babeltrace/compiler.h>
31#include <babeltrace/ref.h>
32#include <babeltrace/plugin/plugin-dev.h>
33#include <babeltrace/plugin/plugin-internal.h>
34#include <babeltrace/component/component-class-internal.h>
35#include <string.h>
36#include <stdbool.h>
37#include <glib.h>
38#include <gmodule.h>
39#include <unistd.h>
40#include <stdlib.h>
41#include <sys/stat.h>
42#include <dirent.h>
43
44#define PLUGIN_SYMBOL_NAME "__bt_plugin_name"
45#define PLUGIN_SYMBOL_AUTHOR "__bt_plugin_author"
46#define PLUGIN_SYMBOL_LICENSE "__bt_plugin_license"
47#define PLUGIN_SYMBOL_INIT "__bt_plugin_init"
48#define PLUGIN_SYMBOL_EXIT "__bt_plugin_exit"
49#define PLUGIN_SYMBOL_DESCRIPTION "__bt_plugin_description"
50#define NATIVE_PLUGIN_SUFFIX ".so"
51#define NATIVE_PLUGIN_SUFFIX_LEN sizeof(NATIVE_PLUGIN_SUFFIX)
52#define LIBTOOL_PLUGIN_SUFFIX ".la"
53#define LIBTOOL_PLUGIN_SUFFIX_LEN sizeof(LIBTOOL_PLUGIN_SUFFIX)
54
55#define PLUGIN_SUFFIX_LEN max_t(size_t, sizeof(NATIVE_PLUGIN_SUFFIX), \
56 sizeof(LIBTOOL_PLUGIN_SUFFIX))
57
58#define SECTION_BEGIN(_name) &__start_##_name
59#define SECTION_END(_name) &__stop_##_name
60#define SECTION_ELEMENT_COUNT(_name) (SECTION_END(_name) - SECTION_BEGIN(_name))
61
62#define DECLARE_SECTION(_type, _name) \
63 extern _type const __start_##_name __attribute((weak)); \
64 extern _type const __stop_##_name __attribute((weak))
65
66DECLARE_SECTION(bt_plugin_init_func, __bt_plugin_init_funcs);
67DECLARE_SECTION(bt_plugin_exit_func, __bt_plugin_exit_funcs);
68DECLARE_SECTION(const char *, __bt_plugin_names);
69DECLARE_SECTION(const char *, __bt_plugin_authors);
70DECLARE_SECTION(const char *, __bt_plugin_licenses);
71DECLARE_SECTION(const char *, __bt_plugin_descriptions);
72
73#define PRINT_SECTION(_printer, _name) \
74 do { \
75 _printer("Section " #_name " [%p - %p], (%zu elements)\n", \
76 SECTION_BEGIN(_name), SECTION_END(_name), \
77 SECTION_ELEMENT_COUNT(_name)); \
78 } while (0)
79
80#define PRINT_PLUG_IN_SECTIONS(_printer) \
81 do { \
82 PRINT_SECTION(_printer, __bt_plugin_init_funcs); \
83 PRINT_SECTION(_printer, __bt_plugin_exit_funcs); \
84 PRINT_SECTION(_printer, __bt_plugin_names); \
85 PRINT_SECTION(_printer, __bt_plugin_authors); \
86 PRINT_SECTION(_printer, __bt_plugin_licenses); \
87 PRINT_SECTION(_printer, __bt_plugin_descriptions); \
88 } while (0)
89
90/*
91 * This hash table, global to the library, maps component class pointers
92 * to shared library handles.
93 *
94 * The keys (component classes) are NOT owned by this hash table, whereas
95 * the values (shared library handles) are owned by this hash table.
96 *
97 * The keys are the component classes created with
98 * bt_plugin_add_component_class(). They keep the shared library handle
99 * object created by their plugin alive so that the plugin's code is
100 * not discarded when it could still be in use by living components
101 * created from those component classes:
102 *
103 * [component] --ref-> [component class] --through this HT-> [shlib handle]
104 *
105 * This hash table exists for two reasons:
106 *
107 * 1. To allow this application:
108 *
109 * my_plugin = bt_plugin_create_from_file("/path/to/my-plugin.so");
110 * // instantiate components from the plugin's component classes
111 * BT_PUT(my_plugin);
112 * // user code of instantiated components still exists
113 *
114 * 2. To decouple the plugin subsystem from the component subsystem:
115 * while plugins objects need to know component class objects, the
116 * opposite is not necessary, thus it makes no sense for a component
117 * class to keep a reference to the plugin object from which it was
118 * created.
119 *
120 * An entry is removed from this HT when a component class is destroyed
121 * thanks to a custom destroy listener. When the entry is removed, the
122 * GLib function calls the value destroy notifier of the HT, which is
123 * bt_put(). This decreases the reference count of the mapped shared
124 * library handle. Assuming the original plugin object which contained
125 * some component classes is put first, when the last component class is
126 * removed from this HT, the shared library handle object's reference
127 * count falls to zero and the shared library is finally closed.
128 */
129static
130GHashTable *comp_classes_to_shlib_handles;
131
132__attribute__((constructor)) static
133void init_comp_classes_to_shlib_handles(void) {
134 comp_classes_to_shlib_handles = g_hash_table_new_full(g_direct_hash,
135 g_direct_equal, NULL, bt_put);
136 assert(comp_classes_to_shlib_handles);
137}
138
139__attribute__((destructor)) static
140void fini_comp_classes_to_shlib_handles(void) {
141 if (comp_classes_to_shlib_handles) {
142 g_hash_table_destroy(comp_classes_to_shlib_handles);
143 }
144}
145
146static
147void bt_plugin_shared_lib_handle_destroy(struct bt_object *obj)
148{
149 struct bt_plugin_shared_lib_handle *shared_lib_handle;
150
151 assert(obj);
152 shared_lib_handle = container_of(obj,
153 struct bt_plugin_shared_lib_handle, base);
154
155 if (shared_lib_handle->init_called && shared_lib_handle->exit) {
156 enum bt_plugin_status status = shared_lib_handle->exit();
157
158 if (status < 0) {
159 printf_verbose("Plugin `%s` exited with error %d\n",
160 shared_lib_handle->name, status);
161 }
162 }
163
164 if (shared_lib_handle->module) {
165 if (!g_module_close(shared_lib_handle->module)) {
166 printf_error("Module close error: %s\n",
167 g_module_error());
168 }
169 }
170
171 if (shared_lib_handle->path) {
172 g_string_free(shared_lib_handle->path, TRUE);
173 }
174
175 g_free(shared_lib_handle);
176}
177
178static
179struct bt_plugin_shared_lib_handle *bt_plugin_shared_lib_handle_create(
180 const char *path)
181{
182 struct bt_plugin_shared_lib_handle *shared_lib_handle = NULL;
183 gpointer symbol = NULL;
184
185 shared_lib_handle = g_new0(struct bt_plugin_shared_lib_handle, 1);
186 if (!shared_lib_handle) {
187 goto error;
188 }
189
190 bt_object_init(shared_lib_handle, bt_plugin_shared_lib_handle_destroy);
191
192 if (!path) {
193 goto end;
194 }
195
196 shared_lib_handle->path = g_string_new(path);
197 if (!shared_lib_handle->path) {
198 goto error;
199 }
200
201 shared_lib_handle->module = g_module_open(path, 0);
202 if (!shared_lib_handle->module) {
203 printf_verbose("Module open error: %s\n", g_module_error());
204 goto error;
205 }
206
207 if (!g_module_symbol(shared_lib_handle->module, PLUGIN_SYMBOL_NAME,
208 (gpointer *) &shared_lib_handle->name)) {
209 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
210 PLUGIN_SYMBOL_NAME,
211 g_module_name(shared_lib_handle->module));
212 goto error;
213 }
214
215 if (!g_module_symbol(shared_lib_handle->module, PLUGIN_SYMBOL_LICENSE,
216 (gpointer *) &shared_lib_handle->license)) {
217 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
218 PLUGIN_SYMBOL_LICENSE,
219 g_module_name(shared_lib_handle->module));
220 goto error;
221 }
222
223 if (!g_module_symbol(shared_lib_handle->module, PLUGIN_SYMBOL_AUTHOR,
224 (gpointer *) &shared_lib_handle->author)) {
225 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
226 PLUGIN_SYMBOL_AUTHOR,
227 g_module_name(shared_lib_handle->module));
228 goto error;
229 }
230
231 if (!g_module_symbol(shared_lib_handle->module, PLUGIN_SYMBOL_DESCRIPTION,
232 (gpointer *) &shared_lib_handle->description)) {
233 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
234 PLUGIN_SYMBOL_DESCRIPTION,
235 g_module_name(shared_lib_handle->module));
236 goto error;
237 }
238
239 if (!g_module_symbol(shared_lib_handle->module, PLUGIN_SYMBOL_INIT,
240 &symbol)) {
241 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
242 PLUGIN_SYMBOL_INIT,
243 g_module_name(shared_lib_handle->module));
244 goto error;
245 } else {
246 shared_lib_handle->init = *((bt_plugin_init_func *) symbol);
247 if (!shared_lib_handle->init) {
248 printf_verbose("NULL %s symbol target\n",
249 PLUGIN_SYMBOL_INIT);
250 goto error;
251 }
252 }
253
254 if (!g_module_symbol(shared_lib_handle->module, PLUGIN_SYMBOL_EXIT,
255 &symbol)) {
256 printf_verbose("Unable to resolve plugin symbol %s from %s\n",
257 PLUGIN_SYMBOL_EXIT,
258 g_module_name(shared_lib_handle->module));
259 goto error;
260 } else {
261 shared_lib_handle->exit = *((bt_plugin_exit_func *) symbol);
262 if (!shared_lib_handle->exit) {
263 printf_verbose("NULL %s symbol target\n",
264 PLUGIN_SYMBOL_EXIT);
265 goto error;
266 }
267 }
268
269 goto end;
270
271error:
272 BT_PUT(shared_lib_handle);
273
274end:
275 return shared_lib_handle;
276}
277
278static
279void bt_plugin_destroy(struct bt_object *obj)
280{
281 struct bt_plugin *plugin;
282
283 assert(obj);
284 plugin = container_of(obj, struct bt_plugin, base);
285
286 BT_PUT(plugin->shared_lib_handle);
287
288 if (plugin->comp_classes) {
289 g_ptr_array_free(plugin->comp_classes, TRUE);
290 }
291
292 g_free(plugin);
293}
294
295static
296enum bt_plugin_status init_plugin(struct bt_plugin *plugin)
297{
298 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
299
300 if (plugin->shared_lib_handle->init) {
301 status = plugin->shared_lib_handle->init(plugin);
302
303 if (status < 0) {
304 printf_verbose("Plugin `%s` initialization error: %d\n",
305 plugin->shared_lib_handle->name, status);
306 goto end;
307 }
308 }
309
310 plugin->shared_lib_handle->init_called = true;
311
312 /*
313 * The initialization function should have added the component
314 * classes at this point. We freeze the plugin so that it's not
315 * possible to add component classes to this plugin object after
316 * this stage (plugin object becomes immutable).
317 */
318 plugin->frozen = true;
319
320end:
321 return status;
322}
323
324struct bt_plugin *bt_plugin_create_from_file(const char *path)
325{
326 size_t path_len;
327 struct bt_plugin *plugin = NULL;
328 bool is_libtool_wrapper = false, is_shared_object = false;
329
330 if (!path) {
331 goto error;
332 }
333
334 path_len = strlen(path);
335 if (path_len <= PLUGIN_SUFFIX_LEN) {
336 goto error;
337 }
338
339 path_len++;
340 /*
341 * Check if the file ends with a known plugin file type suffix (i.e. .so
342 * or .la on Linux).
343 */
344 is_libtool_wrapper = !strncmp(LIBTOOL_PLUGIN_SUFFIX,
345 path + path_len - LIBTOOL_PLUGIN_SUFFIX_LEN,
346 LIBTOOL_PLUGIN_SUFFIX_LEN);
347 is_shared_object = !strncmp(NATIVE_PLUGIN_SUFFIX,
348 path + path_len - NATIVE_PLUGIN_SUFFIX_LEN,
349 NATIVE_PLUGIN_SUFFIX_LEN);
350 if (!is_shared_object && !is_libtool_wrapper) {
351 /* Name indicates that this is not a plugin file. */
352 goto error;
353 }
354
355 plugin = g_new0(struct bt_plugin, 1);
356 if (!plugin) {
357 goto error;
358 }
359
360 bt_object_init(plugin, bt_plugin_destroy);
361
362 /* Create shared lib handle */
363 plugin->shared_lib_handle = bt_plugin_shared_lib_handle_create(path);
364 if (!plugin->shared_lib_handle) {
365 printf_verbose("Failed to create a shared library handle (path `%s`)\n",
366 path);
367 goto error;
368 }
369
370 /* Create empty array of component classes */
371 plugin->comp_classes =
372 g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
373 if (!plugin->comp_classes) {
374 goto error;
375 }
376
377 /* Initialize plugin */
378 if (init_plugin(plugin) < 0) {
379 goto error;
380 }
381
382 goto end;
383
384error:
385 BT_PUT(plugin);
386
387end:
388 return plugin;
389}
390
391/* Allocate dirent as recommended by READDIR(3), NOTES on readdir_r */
392static
393struct dirent *alloc_dirent(const char *path)
394{
395 size_t len;
396 long name_max;
397 struct dirent *entry;
398
399 name_max = pathconf(path, _PC_NAME_MAX);
400 if (name_max == -1) {
401 name_max = PATH_MAX;
402 }
403 len = offsetof(struct dirent, d_name) + name_max + 1;
404 entry = zmalloc(len);
405 return entry;
406}
407
408static
409enum bt_plugin_status bt_plugin_create_append_all_from_dir(
410 GPtrArray *plugins, const char *path, bool recurse)
411{
412 DIR *directory = NULL;
413 struct dirent *entry = NULL, *result = NULL;
414 char *file_path = NULL;
415 size_t path_len = strlen(path);
416 enum bt_plugin_status ret = BT_PLUGIN_STATUS_OK;
417
418 if (path_len >= PATH_MAX) {
419 ret = BT_PLUGIN_STATUS_ERROR;
420 goto end;
421 }
422
423 entry = alloc_dirent(path);
424 if (!entry) {
425 ret = BT_PLUGIN_STATUS_ERROR;
426 goto end;
427 }
428
429 file_path = zmalloc(PATH_MAX);
430 if (!file_path) {
431 ret = BT_PLUGIN_STATUS_NOMEM;
432 goto end;
433 }
434
435 strncpy(file_path, path, path_len);
436 /* Append a trailing '/' to the path */
437 if (file_path[path_len - 1] != '/') {
438 file_path[path_len++] = '/';
439 }
440
441 directory = opendir(file_path);
442 if (!directory) {
443 perror("Failed to open plug-in directory");
444 ret = BT_PLUGIN_STATUS_ERROR;
445 goto end;
446 }
447
448 /* Recursively walk directory */
449 while (!readdir_r(directory, entry, &result) && result) {
450 struct stat st;
451 int stat_ret;
452 size_t file_name_len;
453
454 if (result->d_name[0] == '.') {
455 /* Skip hidden files, . and .. */
456 continue;
457 }
458
459 file_name_len = strlen(result->d_name);
460
461 if (path_len + file_name_len >= PATH_MAX) {
462 continue;
463 }
464
465 strncpy(file_path + path_len, result->d_name, file_name_len);
466 file_path[path_len + file_name_len] = '\0';
467
468 stat_ret = stat(file_path, &st);
469 if (stat_ret < 0) {
470 /* Continue to next file / directory. */
471 printf_perror("Failed to stat() plugin file\n");
472 continue;
473 }
474
475 if (S_ISDIR(st.st_mode) && recurse) {
476 ret = bt_plugin_create_append_all_from_dir(plugins,
477 file_path, true);
478 if (ret < 0) {
479 goto end;
480 }
481 } else if (S_ISREG(st.st_mode)) {
482 struct bt_plugin *plugin = bt_plugin_create_from_file(file_path);
483
484 if (plugin) {
485 /* Transfer ownership to array */
486 g_ptr_array_add(plugins, plugin);
487 }
488 }
489 }
490end:
491 if (directory) {
492 if (closedir(directory)) {
493 /*
494 * We don't want to override the error since there is
495 * nothing could do.
496 */
497 perror("Failed to close plug-in directory");
498 }
499 }
500 free(entry);
501 free(file_path);
502 return ret;
503}
504
505struct bt_plugin **bt_plugin_create_all_from_dir(const char *path,
506 bool recurse)
507{
508 GPtrArray *plugins_array = NULL;
509 struct bt_plugin **plugins = NULL;
510 enum bt_plugin_status status;
511
512 if (!path) {
513 goto error;
514 }
515
516 plugins_array = g_ptr_array_new();
517 if (!plugins_array) {
518 goto error;
519 }
520
521 /* Append found plugins to array */
522 status = bt_plugin_create_append_all_from_dir(plugins_array, path,
523 recurse);
524 if (status < 0) {
525 goto error;
526 }
527
528 /* Add sentinel to array */
529 g_ptr_array_add(plugins_array, NULL);
530 plugins = (struct bt_plugin **) plugins_array->pdata;
531 goto end;
532
533error:
534 if (plugins_array) {
535 g_ptr_array_free(plugins_array, TRUE);
536 plugins_array = NULL;
537 }
538
539end:
540 if (plugins_array) {
541 g_ptr_array_free(plugins_array, FALSE);
542 }
543
544 return plugins;
545}
546
547static
548struct bt_plugin *bt_plugin_create_from_static_at_index(size_t i)
549{
550 struct bt_plugin *plugin = NULL;
551
552 plugin = g_new0(struct bt_plugin, 1);
553 if (!plugin) {
554 goto error;
555 }
556
557 bt_object_init(plugin, bt_plugin_destroy);
558
559 /* Create shared lib handle */
560 plugin->shared_lib_handle = bt_plugin_shared_lib_handle_create(NULL);
561 if (!plugin->shared_lib_handle) {
562 goto error;
563 }
564
565 /* Fill shared lib handle */
566 plugin->shared_lib_handle->init =
567 (SECTION_BEGIN(__bt_plugin_init_funcs))[i];
568 if (!plugin->shared_lib_handle->init) {
569 goto error;
570 }
571
572 plugin->shared_lib_handle->exit =
573 (SECTION_BEGIN(__bt_plugin_exit_funcs))[i];
574 if (!plugin->shared_lib_handle->exit) {
575 goto error;
576 }
577
578 plugin->shared_lib_handle->name = (SECTION_BEGIN(__bt_plugin_names))[i];
579 plugin->shared_lib_handle->author =
580 (SECTION_BEGIN(__bt_plugin_authors))[i];
581 plugin->shared_lib_handle->license =
582 (SECTION_BEGIN(__bt_plugin_licenses))[i];
583 plugin->shared_lib_handle->description =
584 (SECTION_BEGIN(__bt_plugin_descriptions))[i];
585
586 /* Create empty array of component classes */
587 plugin->comp_classes =
588 g_ptr_array_new_with_free_func((GDestroyNotify) bt_put);
589 if (!plugin->comp_classes) {
590 goto error;
591 }
592
593 /* Initialize plugin */
594 if (init_plugin(plugin) < 0) {
595 goto error;
596 }
597
598 goto end;
599
600error:
601 BT_PUT(plugin);
602
603end:
604 return plugin;
605}
606
607struct bt_plugin **bt_plugin_create_all_from_static(void)
608{
609 size_t count, i;
610 struct bt_plugin **plugins = NULL;
611
612 PRINT_PLUG_IN_SECTIONS(printf_verbose);
613 count = SECTION_ELEMENT_COUNT(__bt_plugin_init_funcs);
614 if (SECTION_ELEMENT_COUNT(__bt_plugin_exit_funcs) != count ||
615 SECTION_ELEMENT_COUNT(__bt_plugin_names) != count ||
616 SECTION_ELEMENT_COUNT(__bt_plugin_authors) != count ||
617 SECTION_ELEMENT_COUNT(__bt_plugin_licenses) != count ||
618 SECTION_ELEMENT_COUNT(__bt_plugin_descriptions) != count) {
619 printf_error("Some statically-linked plug-ins do not define all the mandatory symbols\n");
620 goto error;
621 }
622
623 printf_verbose("Detected %zu statically-linked plug-ins\n", count);
624 plugins = g_new0(struct bt_plugin *, count + 1);
625 if (!plugins) {
626 goto error;
627 }
628
629 for (i = 0; i < count; i++) {
630 struct bt_plugin *plugin =
631 bt_plugin_create_from_static_at_index(i);
632
633 if (!plugin) {
634 printf_error("Cannot create statically-linked plug-in at index %zu\n",
635 i);
636 goto error;
637 }
638
639 /* Transfer ownership to the array */
640 plugins[i] = plugin;
641 }
642
643 goto end;
644
645error:
646 g_free(plugins);
647
648end:
649 return plugins;
650}
651
652const char *bt_plugin_get_name(struct bt_plugin *plugin)
653{
654 return plugin ? plugin->shared_lib_handle->name : NULL;
655}
656
657const char *bt_plugin_get_author(struct bt_plugin *plugin)
658{
659 return plugin ? plugin->shared_lib_handle->author : NULL;
660}
661
662const char *bt_plugin_get_license(struct bt_plugin *plugin)
663{
664 return plugin ? plugin->shared_lib_handle->license : NULL;
665}
666
667const char *bt_plugin_get_path(struct bt_plugin *plugin)
668{
669 return (plugin && plugin->shared_lib_handle->path) ?
670 plugin->shared_lib_handle->path->str : NULL;
671}
672
673const char *bt_plugin_get_description(struct bt_plugin *plugin)
674{
675 return plugin ? plugin->shared_lib_handle->description : NULL;
676}
677
678int bt_plugin_get_component_class_count(struct bt_plugin *plugin)
679{
680 return plugin ? plugin->comp_classes->len : -1;
681}
682
683struct bt_component_class *bt_plugin_get_component_class(
684 struct bt_plugin *plugin, size_t index)
685{
686 struct bt_component_class *comp_class = NULL;
687
688 if (!plugin || index >= plugin->comp_classes->len) {
689 goto error;
690 }
691
692 comp_class = g_ptr_array_index(plugin->comp_classes, index);
693 bt_get(comp_class);
694 goto end;
695
696error:
697 BT_PUT(comp_class);
698
699end:
700 return comp_class;
701}
702
703struct bt_component_class *bt_plugin_get_component_class_by_name_and_type(
704 struct bt_plugin *plugin, const char *name,
705 enum bt_component_type type)
706{
707 struct bt_component_class *comp_class = NULL;
708 size_t i;
709
710 if (!plugin || !name) {
711 goto error;
712 }
713
714 for (i = 0; i < plugin->comp_classes->len; i++) {
715 struct bt_component_class *comp_class_candidate =
716 g_ptr_array_index(plugin->comp_classes, i);
717 const char *comp_class_cand_name =
718 bt_component_class_get_name(comp_class_candidate);
719 enum bt_component_type comp_class_cand_type =
720 bt_component_class_get_type(comp_class_candidate);
721
722 assert(comp_class_cand_name);
723 assert(comp_class_cand_type >= 0);
724
725 if (strcmp(name, comp_class_cand_name) == 0 &&
726 comp_class_cand_type == type) {
727 comp_class = bt_get(comp_class_candidate);
728 break;
729 }
730 }
731
732 goto end;
733
734error:
735 BT_PUT(comp_class);
736
737end:
738 return comp_class;
739}
740
741static
742void plugin_comp_class_destroy_listener(struct bt_component_class *comp_class,
743 void *data)
744{
745 gboolean exists = g_hash_table_remove(comp_classes_to_shlib_handles,
746 comp_class);
747 assert(exists);
748}
749
750enum bt_plugin_status bt_plugin_add_component_class(
751 struct bt_plugin *plugin, struct bt_component_class *comp_class)
752{
753 enum bt_plugin_status status = BT_PLUGIN_STATUS_OK;
754 struct bt_component_class *comp_class_dup = NULL;
755 int ret;
756 int comp_class_index = -1;
757
758 if (!plugin || !comp_class || plugin->frozen) {
759 goto error;
760 }
761
762 /* Check for duplicate */
763 comp_class_dup = bt_plugin_get_component_class_by_name_and_type(plugin,
764 bt_component_class_get_name(comp_class),
765 bt_component_class_get_type(comp_class));
766 if (comp_class_dup) {
767 printf_verbose("Plugin `%s`: adding component class with existing name `%s` and type %d\n",
768 plugin->shared_lib_handle->name,
769 bt_component_class_get_name(comp_class),
770 bt_component_class_get_type(comp_class));
771 goto error;
772 }
773
774 /* Add new component class */
775 comp_class_index = plugin->comp_classes->len;
776 g_ptr_array_add(plugin->comp_classes, bt_get(comp_class));
777
778 /* Map component class pointer to shared lib handle in global HT */
779 g_hash_table_insert(comp_classes_to_shlib_handles, comp_class,
780 bt_get(plugin->shared_lib_handle));
781
782 /* Add our custom destroy listener */
783 ret = bt_component_class_add_destroy_listener(comp_class,
784 plugin_comp_class_destroy_listener, NULL);
785 if (ret) {
786 goto error;
787 }
788
789 goto end;
790
791error:
792 /* Remove entry from global hash table (if exists) */
793 g_hash_table_remove(comp_classes_to_shlib_handles,
794 comp_class);
795
796 /* Remove entry from plugin's component classes (if added) */
797 if (comp_class_index >= 0) {
798 g_ptr_array_remove_index(plugin->comp_classes,
799 comp_class_index);
800 }
801
802 status = BT_PLUGIN_STATUS_ERROR;
803
804end:
805 bt_put(comp_class_dup);
806 return status;
807}
This page took 0.050352 seconds and 4 git commands to generate.