3 * \brief dynamic loader helpers
4 * \author Jaroslav Kysela <perex@perex.cz>
7 * Dynamic loader helpers
10 * Dynamic loader helpers
11 * Copyright (c) 2000 by Jaroslav Kysela <perex@perex.cz>
14 * This library is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License as
16 * published by the Free Software Foundation; either version 2.1 of
17 * the License, or (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #ifdef HAVE_LIBPTHREAD
38 struct snd_dlsym_link *snd_dlsym_start = NULL;
43 * \brief Opens a dynamic library - ALSA wrapper for \c dlopen.
44 * \param name name of the library, similar to \c dlopen.
45 * \param mode mode flags, similar to \c dlopen.
46 * \return Library handle if successful, otherwise \c NULL.
48 * This function can emulate dynamic linking for the static build of
49 * the alsa-lib library. In that case, \p name is set to \c NULL.
51 void *snd_dlopen(const char *name, int mode)
55 return &snd_dlsym_start;
59 static const char * self = NULL;
62 if (dladdr(snd_dlopen, &dlinfo) > 0)
63 self = dlinfo.dli_fname;
70 return dlopen(name, mode);
77 * \brief Closes a dynamic library - ALSA wrapper for \c dlclose.
78 * \param handle Library handle, similar to \c dlclose.
79 * \return Zero if successful, otherwise an error code.
81 * This function can emulate dynamic linking for the static build of
82 * the alsa-lib library.
84 int snd_dlclose(void *handle)
87 if (handle == &snd_dlsym_start)
91 return dlclose(handle);
98 * \brief Verifies a dynamically loaded symbol.
99 * \param handle Library handle, similar to \c dlsym.
100 * \param name Symbol name.
101 * \param version Version of the symbol.
102 * \return Zero is successful, otherwise a negative error code.
104 * This function checks that the symbol with the version appended to its name
105 * does exist in the library.
107 static int snd_dlsym_verify(void *handle, const char *name, const char *version)
115 vname = alloca(1 + strlen(name) + strlen(version) + 1);
119 strcpy(vname + 1, name);
120 strcat(vname, version);
121 res = dlsym(handle, vname) == NULL ? -ENOENT : 0;
122 // printf("dlsym verify: %i, vname = '%s'\n", res, vname);
124 SNDERR("unable to verify version for symbol %s", name);
132 * \brief Resolves a symbol from a dynamic library - ALSA wrapper for \c dlsym.
133 * \param handle Library handle, similar to \c dlsym.
134 * \param name Symbol name.
135 * \param version Version of the symbol.
137 * This function can emulate dynamic linking for the static build of
138 * the alsa-lib library.
140 * This special version of the \c dlsym function checks also the version
141 * of the symbol. A versioned symbol should be defined using the
142 * #SND_DLSYM_BUILD_VERSION macro.
144 void *snd_dlsym(void *handle, const char *name, const char *version)
149 if (handle == &snd_dlsym_start) {
150 /* it's the funny part: */
151 /* we are looking for a symbol in a static library */
152 struct snd_dlsym_link *link = snd_dlsym_start;
154 if (!strcmp(name, link->dlsym_name))
155 return (void *)link->dlsym_ptr;
163 err = snd_dlsym_verify(handle, name, version);
167 return dlsym(handle, name);
184 struct list_head list;
187 #ifdef HAVE_LIBPTHREAD
188 static pthread_mutex_t snd_dlobj_mutex = PTHREAD_MUTEX_INITIALIZER;
190 static inline void snd_dlobj_lock(void)
192 pthread_mutex_lock(&snd_dlobj_mutex);
195 static inline void snd_dlobj_unlock(void)
197 pthread_mutex_unlock(&snd_dlobj_mutex);
200 static inline void snd_dlobj_lock(void) {}
201 static inline void snd_dlobj_unlock(void) {}
204 static LIST_HEAD(pcm_dlobj_list);
206 void *snd_dlobj_cache_get(const char *lib, const char *name,
207 const char *version, int verbose)
210 struct dlobj_cache *c;
211 void *func, *dlobj = NULL;
215 list_for_each(p, &pcm_dlobj_list) {
216 c = list_entry(p, struct dlobj_cache, list);
217 if (c->lib && lib && strcmp(c->lib, lib) != 0)
224 if (strcmp(c->name, name) == 0) {
232 dlobj = snd_dlopen(lib, RTLD_NOW);
235 SNDERR("Cannot open shared library %s",
236 lib ? lib : "[builtin]");
242 func = snd_dlsym(dlobj, name, version);
245 SNDERR("symbol %s is not defined inside %s",
246 name, lib ? lib : "[builtin]");
249 c = malloc(sizeof(*c));
253 c->lib = lib ? strdup(lib) : NULL;
254 c->name = strdup(name);
255 if ((lib && ! c->lib) || ! c->name) {
256 free((void *)c->name);
257 free((void *)c->lib);
267 list_add_tail(&c->list, &pcm_dlobj_list);
272 int snd_dlobj_cache_put(void *func)
275 struct dlobj_cache *c;
279 list_for_each(p, &pcm_dlobj_list) {
280 c = list_entry(p, struct dlobj_cache, list);
281 if (c->func == func) {
286 return refcnt == 1 ? 0 : -EINVAL;
293 void snd_dlobj_cache_cleanup(void)
295 struct list_head *p, *npos;
296 struct dlobj_cache *c;
299 list_for_each_safe(p, npos, &pcm_dlobj_list) {
300 c = list_entry(p, struct dlobj_cache, list);
301 if (c->refcnt == 0) {
303 snd_dlclose(c->dlobj);
304 free((void *)c->name); /* shut up gcc warning */
305 free((void *)c->lib); /* shut up gcc warning */