GCC Code Coverage Report


Directory: src/
File: src/plugins/plugin_manager.c
Date: 2025-11-21 10:34:40
Exec Total Coverage
Lines: 4 99 4.0%
Functions: 2 7 28.6%
Branches: 4 54 7.4%

Line Branch Exec Source
1 /*********************************************************************************/
2 /* Copyright 2009-2025 Barcelona Supercomputing Center */
3 /* */
4 /* This file is part of the DLB library. */
5 /* */
6 /* DLB is free software: you can redistribute it and/or modify */
7 /* it under the terms of the GNU Lesser General Public License as published by */
8 /* the Free Software Foundation, either version 3 of the License, or */
9 /* (at your option) any later version. */
10 /* */
11 /* DLB 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 */
14 /* GNU Lesser General Public License for more details. */
15 /* */
16 /* You should have received a copy of the GNU Lesser General Public License */
17 /* along with DLB. If not, see <https://www.gnu.org/licenses/>. */
18 /*********************************************************************************/
19
20 #include "plugins/plugin_manager.h"
21
22 #include "apis/dlb_errors.h"
23 #include "plugins/plugin.h"
24 #include "support/debug.h"
25 #include "support/gslist.h"
26
27 #include <dlfcn.h>
28 #include <libgen.h>
29 #include <limits.h>
30 #include <string.h>
31
32 // TODO: Some of the warning messages may actually be undesired if we are
33 // just trying to load a plugin, or silently ignore if error
34 // Consider a new --verbose=plugin option.
35
36
37 typedef struct plugin_t {
38 plugin_info_t info;
39 plugin_api_t *api;
40 void *handle;
41 } plugin_t;
42
43 GSList *loaded_plugins = NULL;
44
45 /* Obtain full path to libdlb.so (or whatever variant is loaded) */
46 static const char* get_dlb_lib_path(void) {
47
48 static char dlb_lib_path[PATH_MAX] = "";
49
50 // Note: we don't want to call dlsym twice, so just in case we want to load
51 // more than one plugin, make sure that this function is only called once.
52 if (dlb_lib_path[0] != '\0') return dlb_lib_path;
53
54 // Get the path to the current library
55 void *dlb_lib_handle = dlopen(NULL, RTLD_LAZY);
56 if (!dlb_lib_handle) {
57 debug_warning("dlopen failed to load the current library: %s", dlerror());
58 return NULL;
59 }
60
61 // Get the address of any symbol in the DLB library
62 void *dlb_init_fn = dlsym(dlb_lib_handle, "DLB_Init");
63 if (!dlb_init_fn) {
64 debug_warning("dlsym failed to look for DLB_Init address: %s", dlerror());
65 return NULL;
66 }
67
68 // Get information of the dlb shared object currently loaded
69 Dl_info info;
70 if (dladdr(dlb_init_fn, &info)) {
71 strncpy(dlb_lib_path, dirname((char*)info.dli_fname), PATH_MAX - 1);
72 dlb_lib_path[PATH_MAX - 1] = '\0';
73 } else {
74 debug_warning("dladdr failed to obtain information");
75 return NULL;
76 }
77
78 return dlb_lib_path;
79 }
80
81 /* Load exact plugin name, return error otherwise */
82 int load_plugin(const char* plugin_name) {
83
84 const char *dlb_lib_path = get_dlb_lib_path();
85 if (dlb_lib_path == NULL || dlb_lib_path[0] == '\0') {
86 return DLB_ERR_UNKNOWN;
87 }
88
89 // Load the plugin
90 char plugin_path[PATH_MAX];
91 int not_truncated_len = snprintf(plugin_path, PATH_MAX, "%s/libdlb_%s.so",
92 dlb_lib_path, plugin_name);
93 if (not_truncated_len >= PATH_MAX) {
94 // really unlikely, but avoids GCC's format-truncation warning
95 return DLB_ERR_UNKNOWN;
96 }
97 void *handle = dlopen(plugin_path, RTLD_LAZY);
98 if (!handle) {
99 debug_warning("Failed to load plugin %s: %s", plugin_name, dlerror());
100 return DLB_ERR_UNKNOWN;
101 }
102
103 // Load the plugin public function
104 plugin_get_api_func_t get_api = (plugin_get_api_func_t)dlsym(handle, "DLB_Get_Plugin_API");
105 if (!get_api) {
106 debug_warning("Failed to find function: %s", dlerror());
107 dlclose(handle);
108 return DLB_ERR_UNKNOWN;
109 }
110
111 // Allocate memory for keeping the plugin's data
112 plugin_t *plugin = malloc(sizeof(plugin_t));
113
114 // Initialize structure (call DLB_Get_Plugin_API)
115 *plugin = (const plugin_t) {
116 .api = get_api(),
117 .handle = handle,
118 };
119
120 // Init plugin
121 if (plugin->api->init(&plugin->info) == DLB_PLUGIN_ERROR) {
122 // deallocate failed plugin
123 free(plugin);
124 return DLB_ERR_UNKNOWN;
125 }
126
127 // Plugin must return its own name, for correct-checking and for unloading it later
128 if (strcmp(plugin->info.name, plugin_name) != 0) {
129 debug_warning("Plugin %s did not return an equivalent plugin name during initialization."
130 " Deactivating...", plugin_name);
131 plugin->api->finalize();
132 free(plugin);
133 return DLB_ERR_UNKNOWN;
134 }
135
136 // Add plugin to list for future reference
137 loaded_plugins = g_slist_prepend(loaded_plugins, plugin);
138
139 return DLB_SUCCESS;
140 }
141
142 int unload_plugin(const char* plugin_name) {
143
144 int error = DLB_ERR_UNKNOWN;
145 plugin_t *found_plugin = NULL;
146
147 for (GSList *node = loaded_plugins;
148 node != NULL;
149 node = node->next) {
150
151 plugin_t *plugin = node->data;
152 if (strcmp(plugin->info.name, plugin_name) == 0) {
153 /* found plugin, unload */
154 found_plugin = plugin;
155 error = plugin->api->finalize();
156 dlclose(plugin->handle);
157 break;
158 }
159 }
160
161 /* plugin was found in the list, remove it */
162 if (found_plugin != NULL) {
163 loaded_plugins = g_slist_remove(loaded_plugins, found_plugin);
164 }
165
166 return error == DLB_PLUGIN_SUCCESS ? DLB_SUCCESS : error;
167 }
168
169 90 void load_plugins(const char *plugin_list) {
170
171
2/4
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
90 if (plugin_list == NULL || plugin_list[0] == '\0') return;
172
173 /* Tokenize a copy of the input string and initialize each plugin */
174 size_t len = strlen(plugin_list) + 1;
175 char *plugin_list_copy = malloc(sizeof(char)*len);
176 strcpy(plugin_list_copy, plugin_list);
177 char *end = NULL;
178 char *token = strtok_r(plugin_list_copy, ",", &end);
179 while(token != NULL) {
180 if (load_plugin(token) != DLB_SUCCESS) {
181 warning("Plugin \"%s\" could not be loaded", token);
182 }
183 token = strtok_r(NULL, ",", &end);
184 }
185
186 free(plugin_list_copy);
187 }
188
189 90 void unload_plugins(const char *plugin_list) {
190
191
2/4
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
90 if (plugin_list == NULL || plugin_list[0] == '\0') return;
192
193 /* Tokenize a copy of the input string and initialize each plugin */
194 size_t len = strlen(plugin_list) + 1;
195 char *plugin_list_copy = malloc(sizeof(char)*len);
196 strcpy(plugin_list_copy, plugin_list);
197 char *end = NULL;
198 char *token = strtok_r(plugin_list_copy, ",", &end);
199 while(token != NULL) {
200 if (unload_plugin(token) != DLB_SUCCESS) {
201 warning("Plugin \"%s\" could not be unloaded", token);
202 }
203 token = strtok_r(NULL, ",", &end);
204 }
205
206 free(plugin_list_copy);
207 }
208
209 void plugin_get_gpu_affinity(char *buffer, size_t buffer_size, bool full_uuid) {
210
211 // check only first loaded plugin
212 plugin_t *plugin = loaded_plugins ? loaded_plugins->data : NULL;
213 if (plugin != NULL
214 && plugin->api->get_affinity) {
215 plugin->api->get_affinity(buffer, buffer_size, full_uuid);
216 }
217 }
218
219 void* plugin_get_symbol_from_plugin(const char *symbol, const char *plugin_name) {
220
221 void *symbol_addr = NULL;
222
223 for (GSList *node = loaded_plugins;
224 node != NULL;
225 node = node->next) {
226
227 plugin_t *plugin = node->data;
228 if (strcmp(plugin->info.name, plugin_name) == 0) {
229 /* found plugin, look for symbol */
230 symbol_addr = dlsym(plugin->handle, "rocprofiler_configure");
231 break;
232 }
233 }
234
235 return symbol_addr;
236 }
237