source: roaraudio/libroar/roardl.c @ 5312:27ec111dc8c5

Last change on this file since 5312:27ec111dc8c5 was 5312:27ec111dc8c5, checked in by phi, 12 years ago

added support for seperate contextes for roardl/plugins. Currently incudes error state and a global per handle data segment. This does not work for statically linked librarys (yet). support for per-context notify core needs to be added/completed.

File size: 11.0 KB
Line 
1//roardl.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
5 *
6 *  This file is part of libroar a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  libroar is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 *  NOTE for everyone want's to change something and send patches:
25 *  read README and HACKING! There a addition information on
26 *  the license of this document you need to read before you send
27 *  any patches.
28 *
29 *  NOTE for uses of non-GPL (LGPL,...) software using libesd, libartsc
30 *  or libpulse*:
31 *  The libs libroaresd, libroararts and libroarpulse link this lib
32 *  and are therefore GPL. Because of this it may be illigal to use
33 *  them with any software that uses libesd, libartsc or libpulse*.
34 */
35
36#include "libroar.h"
37
38#if defined(ROAR_HAVE_LIBDL) && !defined(RTLD_NEXT)
39#define RTLD_NEXT ((void *) -1L)
40#endif
41
42struct roar_dl_lhandle {
43 struct roar_dl_librarypara * para;
44 struct roar_dl_libraryinst * lib;
45 struct {
46  struct roar_error_state error_state;
47  void *  global_data;
48  void *  global_data_state;
49 } context;
50#if defined(ROAR_HAVE_LIBDL)
51 void * handle;
52#endif
53};
54
55
56struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv,
57                                              const char * appname, const char * abiversion) {
58 struct roar_dl_librarypara * ret = roar_mm_malloc(sizeof(struct roar_dl_librarypara));
59 ssize_t argc;
60 int err;
61
62 if ( ret == NULL )
63  return NULL;
64
65 memset(ret, 0, sizeof(struct roar_dl_librarypara));
66
67 ret->version    = ROAR_DL_LIBPARA_VERSION;
68 ret->len        = sizeof(struct roar_dl_librarypara);
69 ret->refc       = 1;
70 ret->argc       = 0;
71 ret->argv       = NULL;
72 ret->args_store = NULL;
73 ret->binargv    = binargv;
74 ret->appname    = appname;
75 ret->abiversion = abiversion;
76
77 if ( args != NULL ) {
78  ret->args_store = roar_mm_strdup(args);
79  if ( ret->args_store == NULL ) {
80   err = roar_error;
81   roar_mm_free(ret);
82   roar_error = err;
83   return NULL;
84  }
85
86  argc = roar_keyval_split(&(ret->argv), ret->args_store, NULL, NULL, 0);
87  if ( argc == -1 ) {
88   err = roar_error;
89   roar_mm_free(ret->args_store);
90   roar_mm_free(ret);
91   roar_error = err;
92   return NULL;
93  }
94
95  ret->argc = argc;
96 }
97
98 return ret;
99}
100
101int roar_dl_para_ref                    (struct roar_dl_librarypara * para) {
102 if ( para == NULL ) {
103  roar_err_set(ROAR_ERROR_FAULT);
104  return -1;
105 }
106
107 para->refc++;
108
109 return 0;
110}
111
112int roar_dl_para_unref                  (struct roar_dl_librarypara * para) {
113 if ( para == NULL ) {
114  roar_err_set(ROAR_ERROR_FAULT);
115  return -1;
116 }
117
118 para->refc--;
119
120 if ( para->refc == 0 ) {
121  if ( para->args_store != NULL ) {
122   roar_mm_free(para->args_store);
123   roar_mm_free(para->argv);
124  }
125  roar_mm_free(para);
126 }
127
128 return 0;
129}
130int roar_dl_para_check_version          (struct roar_dl_librarypara * para,
131                                         const char * appname, const char * abiversion) {
132 if ( para == NULL ) {
133  roar_err_set(ROAR_ERROR_FAULT);
134  return -1;
135 }
136
137 // check if both appnames are NULL or non-NULL.
138 if ( (para->appname == NULL && appname != NULL) || (para->appname != NULL && appname == NULL) ) {
139  roar_err_set(ROAR_ERROR_BADVERSION);
140  return -1;
141 }
142
143 // check if the appname matches if given.
144 if ( para->appname != NULL && !!strcmp(para->appname, appname) ) {
145  roar_err_set(ROAR_ERROR_BADVERSION);
146  return -1;
147 }
148
149 // check if both ABI versions are NULL or non-NULL.
150 if ( (para->abiversion == NULL && abiversion != NULL) || (para->abiversion != NULL && abiversion == NULL) ) {
151  roar_err_set(ROAR_ERROR_BADVERSION);
152  return -1;
153 }
154
155 // check if the ABI versions matches if given.
156 if ( para->abiversion != NULL && !!strcmp(para->abiversion, abiversion) ) {
157  roar_err_set(ROAR_ERROR_BADVERSION);
158  return -1;
159 }
160
161 return 0;
162}
163
164
165#if defined(ROAR_HAVE_LIBDL)
166static void * _roardl2ldl (struct roar_dl_lhandle * lhandle) {
167 if ( lhandle == ROAR_DL_HANDLE_DEFAULT )
168  return RTLD_DEFAULT;
169
170 if ( lhandle == ROAR_DL_HANDLE_NEXT )
171  return RTLD_NEXT;
172
173 return lhandle->handle;
174}
175#endif
176
177struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags,
178                                      int ra_init, struct roar_dl_librarypara * para) {
179 struct roar_dl_lhandle * ret = NULL;
180 int err;
181
182 // early errors just return.
183
184 if ( flags != ROAR_DL_FLAG_DEFAUTS ) {
185  roar_err_set(ROAR_ERROR_NOTSUP);
186  return NULL;
187 }
188
189 if ( (ret = roar_mm_malloc(sizeof(struct roar_dl_lhandle))) == NULL )
190  return NULL;
191
192 memset(ret, 0, sizeof(struct roar_dl_lhandle));
193
194 roar_err_initstore(&(ret->context.error_state));
195
196#if defined(ROAR_HAVE_LIBDL)
197 flags  = RTLD_NOW;
198
199#ifdef RTLD_DEEPBIND
200 flags |= RTLD_DEEPBIND;
201#endif
202
203 ret->handle = dlopen(filename, flags);
204
205 if ( ret->handle == NULL ) {
206  roar_mm_free(ret);
207  return NULL;
208 }
209#else
210 roar_mm_free(ret);
211 roar_err_set(ROAR_ERROR_NOSYS);
212 return NULL;
213#endif
214
215 ret->para = para;
216
217 if ( ra_init ) {
218  if ( roar_dl_ra_init(ret, NULL, para) == -1 ) {
219   err = roar_error;
220   ROAR_WARN("roar_dl_open(filename='%s', flags=%i, ra_init=%i, para=%p): Can not init RA lib: %s", filename, flags, ra_init, para, roar_error2str(err));
221#if defined(ROAR_HAVE_LIBDL)
222   dlclose(ret->handle);
223#endif
224   roar_mm_free(ret);
225   roar_error = err;
226   return NULL;
227  }
228 }
229
230 if ( para != NULL )
231  roar_dl_para_ref(para);
232
233 return ret;
234}
235
236int                      roar_dl_close(struct roar_dl_lhandle * lhandle) {
237 int ret = -1;
238
239 if ( lhandle == ROAR_DL_HANDLE_DEFAULT || lhandle == ROAR_DL_HANDLE_NEXT ) {
240  roar_err_set(ROAR_ERROR_BADFH);
241  return -1;
242 }
243
244 if ( lhandle->lib != NULL && lhandle->lib->unload != NULL )
245  lhandle->lib->unload(lhandle->para, lhandle->lib);
246
247#if defined(ROAR_HAVE_LIBDL)
248 ret = dlclose(_roardl2ldl(lhandle));
249#else
250 ret = -1;
251#endif
252
253 if ( lhandle->context.global_data != NULL )
254  roar_mm_free(lhandle->context.global_data);
255
256 if ( lhandle->para != NULL )
257  roar_dl_para_unref(lhandle->para);
258
259 roar_mm_free(lhandle);
260
261 return ret;
262}
263
264void                   * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type) {
265#if defined(ROAR_HAVE_LIBDL)
266 void * ret = dlsym(_roardl2ldl(lhandle), sym);
267
268 (void)type;
269
270 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = %p", lhandle, sym, type, ret);
271
272 return ret;
273#else
274 return NULL;
275#endif
276}
277
278int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
279                                         const char * prefix,
280                                         struct roar_dl_librarypara * para) {
281#define _SUFFIX "_roaraudio_library_init"
282 char name[80] = _SUFFIX;
283 struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para);
284 struct roar_dl_libraryinst * lib;
285 void * global_data_state = NULL;
286 int i;
287
288 if ( (void*)lhandle < (void*)128 ) {
289  if ( prefix == NULL )
290   return -1;
291 } else {
292  if ( para == NULL )
293   para = lhandle->para;
294 }
295
296
297 if ( prefix != NULL ) {
298  roar_mm_strscpy(name, "_");
299  roar_mm_strscat(name, prefix);
300  roar_mm_strscat(name, _SUFFIX);
301 }
302
303 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): name='%s'", lhandle, prefix, name);
304
305 if ( (func = roar_dl_getsym(lhandle, name, -1)) == NULL )
306  return -1;
307
308 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): func=%p", lhandle, prefix, func);
309
310 lib = func(para);
311
312 if ( lib == NULL )
313  return -1;
314
315 if ( lib->version != ROAR_DL_LIBINST_VERSION )
316  return -1;
317
318 if ( sizeof(struct roar_dl_libraryinst) > lib->len )
319  return -1;
320
321 if ( !((void*)lhandle < (void*)128) ) {
322  lhandle->lib = lib;
323
324  if ( lib->global_data_len ) {
325   lhandle->context.global_data = roar_mm_malloc(lib->global_data_len);
326   if ( lhandle->context.global_data == NULL )
327    return -1;
328
329   if ( lib->global_data_init == NULL ) {
330    memset(lhandle->context.global_data, 0, lib->global_data_len);
331   } else {
332    memcpy(lhandle->context.global_data, lib->global_data_init, lib->global_data_len);
333   }
334  }
335 }
336
337 if ( lib->global_data_pointer != NULL ) {
338  global_data_state = *(lib->global_data_pointer);
339  if ( !((void*)lhandle < (void*)128) ) {
340   *(lib->global_data_pointer) = lib->global_data_init;
341  } else {
342   *(lib->global_data_pointer) = lhandle->context.global_data;
343  }
344 }
345
346 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
347  if ( lib->func[i] != NULL )
348   lib->func[i](para, lib);
349 }
350
351 if ( lib->global_data_pointer != NULL ) {
352  *(lib->global_data_pointer) = global_data_state;
353 }
354
355 return 0;
356}
357
358const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
359#if defined(ROAR_HAVE_LIBDL)
360 (void)lhandle;
361 return dlerror();
362#else
363 return NULL;
364#endif
365}
366
367struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
368 if ( (void*)lhandle < (void*)128 ) {
369  roar_err_set(ROAR_ERROR_NOTSUP);
370  return NULL;
371 }
372
373 if ( lhandle->para == NULL ) {
374  roar_err_set(ROAR_ERROR_NOENT);
375  return NULL;
376 }
377
378 if ( roar_dl_para_ref(lhandle->para) == -1 )
379  return NULL;
380
381 return lhandle->para;
382}
383
384const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
385 if ( (void*)lhandle < (void*)128 ) {
386  roar_err_set(ROAR_ERROR_NOTSUP);
387  return NULL;
388 }
389
390 if ( lhandle->lib == NULL ) {
391  roar_err_set(ROAR_ERROR_BADLIB);
392  return NULL;
393 }
394
395 if ( lhandle->lib->libname == NULL ) {
396  roar_err_set(ROAR_ERROR_NOENT);
397  return NULL;
398 }
399
400 if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
401  roar_err_set(ROAR_ERROR_BADVERSION);
402  return NULL;
403 }
404
405 if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
406  roar_err_set(ROAR_ERROR_HOLE);
407  return NULL;
408 }
409
410 return lhandle->lib->libname;
411}
412
413int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
414 struct roar_error_state error_state;
415
416 if ( (void*)lhandle < (void*)128 ) {
417  roar_err_set(ROAR_ERROR_NOTSUP);
418  return -1;
419 }
420
421 roar_err_store(&error_state);
422 roar_err_restore(&(lhandle->context.error_state));
423 lhandle->context.error_state = error_state;
424
425 if ( lhandle->lib->global_data_pointer != NULL ) {
426  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
427  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
428 }
429
430 return 0;
431}
432
433int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
434 struct roar_error_state error_state;
435
436 if ( (void*)lhandle < (void*)128 ) {
437  roar_err_set(ROAR_ERROR_NOTSUP);
438  return -1;
439 }
440
441 if ( lhandle->lib->global_data_pointer != NULL ) {
442  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data_state;
443 }
444
445 roar_err_store(&error_state);
446 roar_err_restore(&(lhandle->context.error_state));
447 lhandle->context.error_state = error_state;
448
449 return 0;
450}
451
452//ll
Note: See TracBrowser for help on using the repository browser.