source: roaraudio/libroar/roardl.c @ 5517:287ced72ce95

Last change on this file since 5517:287ced72ce95 was 5517:287ced72ce95, checked in by phi, 12 years ago

Fixed detection of dynamic loader on *BSD.

File size: 26.7 KB
Line 
1//roardl.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2012
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#ifdef ROAR_HAVE_H_DIRENT
39#include <dirent.h>
40#endif
41
42#if defined(ROAR_HAVE_H_DLFCN) && !defined(RTLD_NEXT)
43#define RTLD_NEXT ((void *) -1L)
44#endif
45
46#define RTF_RA_INITED       0x0001
47#define RTF_APPSCHED_INITED 0x0002
48#define RTF_APPSCHED_FREED  0x0004
49
50struct roar_dl_lhandle {
51 size_t refc; // currently unused.
52 int flags;
53 char * libname; // only used for ROAR_DL_FLAG_STATIC.
54 struct roar_dl_librarypara * para;
55 struct roar_dl_libraryinst * lib;
56 struct {
57  struct roar_error_state error_state;
58  void *  global_data;
59  void *  global_data_state;
60  struct roar_notify_core * notifycore;
61 } context;
62 unsigned int runtime_flags;
63#if defined(ROAR_HAVE_H_DLFCN)
64 void * handle;
65#elif defined(ROAR_TARGET_WIN32)
66 HMODULE handle;
67#endif
68};
69
70// TODO: this should be removed on next SONAME change.
71static struct roar_dl_lhandle * __currently_inited    = NULL;
72static int                      __currently_inited_fn = -1;
73
74struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv,
75                                              const char * appname, const char * abiversion) {
76 struct roar_dl_librarypara * ret = roar_mm_malloc(sizeof(struct roar_dl_librarypara));
77 ssize_t argc;
78 int err;
79
80 if ( ret == NULL )
81  return NULL;
82
83 memset(ret, 0, sizeof(struct roar_dl_librarypara));
84
85 ret->version    = ROAR_DL_LIBPARA_VERSION;
86 ret->len        = sizeof(struct roar_dl_librarypara);
87 ret->refc       = 1;
88 ret->argc       = 0;
89 ret->argv       = NULL;
90 ret->args_store = NULL;
91 ret->binargv    = binargv;
92 ret->appname    = appname;
93 ret->abiversion = abiversion;
94
95 if ( args != NULL ) {
96  ret->args_store = roar_mm_strdup(args);
97  if ( ret->args_store == NULL ) {
98   err = roar_error;
99   roar_mm_free(ret);
100   roar_error = err;
101   return NULL;
102  }
103
104  argc = roar_keyval_split(&(ret->argv), ret->args_store, NULL, NULL, 1);
105  if ( argc == -1 ) {
106   err = roar_error;
107   roar_mm_free(ret->args_store);
108   roar_mm_free(ret);
109   roar_error = err;
110   return NULL;
111  }
112
113  ret->argc = argc;
114 }
115
116 return ret;
117}
118
119int roar_dl_para_ref                    (struct roar_dl_librarypara * para) {
120 if ( para == NULL ) {
121  ROAR_DBG("roar_dl_para_ref(para=%p) = -1 // error=FAULT", para);
122  roar_err_set(ROAR_ERROR_FAULT);
123  return -1;
124 }
125
126 para->refc++;
127
128 ROAR_DBG("roar_dl_para_ref(para=%p) = 0", para);
129 return 0;
130}
131
132int roar_dl_para_unref                  (struct roar_dl_librarypara * para) {
133 if ( para == NULL ) {
134  ROAR_DBG("roar_dl_para_unref(para=%p) = -1 // error=FAULT", para);
135  roar_err_set(ROAR_ERROR_FAULT);
136  return -1;
137 }
138
139 para->refc--;
140
141 if ( para->refc ) {
142  ROAR_DBG("roar_dl_para_unref(para=%p) = 0", para);
143  return 0;
144 }
145
146 if ( para->notifycore != NULL )
147  roar_notify_core_unref(para->notifycore);
148
149 if ( para->args_store != NULL ) {
150  roar_mm_free(para->args_store);
151  roar_mm_free(para->argv);
152 }
153
154 roar_mm_free(para);
155
156 ROAR_DBG("roar_dl_para_unref(para=%p) = 0", para);
157 return 0;
158}
159int roar_dl_para_check_version          (struct roar_dl_librarypara * para,
160                                         const char * appname, const char * abiversion) {
161 if ( para == NULL ) {
162  roar_err_set(ROAR_ERROR_FAULT);
163  return -1;
164 }
165
166 // check if both appnames are NULL or non-NULL.
167 if ( (para->appname == NULL && appname != NULL) || (para->appname != NULL && appname == NULL) ) {
168  roar_err_set(ROAR_ERROR_BADHOST);
169  return -1;
170 }
171
172 // check if the appname matches if given.
173 if ( para->appname != NULL && !!strcmp(para->appname, appname) ) {
174  roar_err_set(ROAR_ERROR_BADHOST);
175  return -1;
176 }
177
178 // check if both ABI versions are NULL or non-NULL.
179 if ( (para->abiversion == NULL && abiversion != NULL) || (para->abiversion != NULL && abiversion == NULL) ) {
180  roar_err_set(ROAR_ERROR_BADVERSION);
181  return -1;
182 }
183
184 // check if the ABI versions matches if given.
185 if ( para->abiversion != NULL && !!strcmp(para->abiversion, abiversion) ) {
186  roar_err_set(ROAR_ERROR_BADVERSION);
187  return -1;
188 }
189
190 return 0;
191}
192
193
194#if defined(ROAR_HAVE_H_DLFCN)
195static void * _roardl2ldl (struct roar_dl_lhandle * lhandle) {
196 ROAR_DBG("_roardl2ldl(lhandle=%p) = ?", lhandle);
197
198 if ( (void*)lhandle < (void*)128 ) {
199  switch ((int)(void*)lhandle) {
200   case (int)(void*)ROAR_DL_HANDLE_DEFAULT:
201   case (int)(void*)ROAR_DL_HANDLE_LIBROAR:
202   case (int)(void*)ROAR_DL_HANDLE_APPLICATION:
203     ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_DEFAULT);
204     return RTLD_DEFAULT;
205    break;
206   case (int)(void*)ROAR_DL_HANDLE_NEXT:
207     ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)RTLD_NEXT);
208     return RTLD_NEXT;
209    break;
210  }
211 }
212
213 ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)(lhandle->handle));
214 return lhandle->handle;
215}
216#elif defined(ROAR_TARGET_WIN32)
217static HMODULE _roardl2winhandle(struct roar_dl_lhandle * lhandle) {
218 if ( (void*)lhandle < (void*)128 ) {
219  return NULL;
220 }
221 return lhandle->handle;
222}
223#endif
224
225#ifdef ROAR_HAVE_H_DIRENT
226// pvn = prefix, host vendor, host name
227static struct roar_dl_lhandle * _load_from_path_pvn(const char * name,
228                                                    int flags, int ra_init,
229                                                    struct roar_dl_librarypara * para,
230                                                    const char * prefix,
231                                                    const char * hostvendor,
232                                                    const char * hostname) {
233 struct roar_dl_lhandle * ret = NULL;
234 int i, j;
235 char path[1024];
236 const char * path_format[] = {"%s/%s/%s", "%s/%s/universal", "%s/universal/universal"};
237 DIR * dir;
238 struct dirent * dirent;
239 char file[1024];
240 const char * file_format[] = {"%s/%s/%s", "%s/%s/%s" ROAR_SHARED_SUFFIX, "%s/%s/lib%s" ROAR_SHARED_SUFFIX};
241//  cont->handle[idx] = roar_dl_open(name, ROAR_DL_FLAG_DEFAULTS, 1, para);
242//#vars: $PREFIX_PLUGINS, $hostvendor, $hostname, $name
243//#search order: $PREFIX_PLUGINS/{$hostvendor/{$hostname,universal},universal/universal}/*/{,lib}$name.so
244
245 for (i = 0; i < 3; i++) {
246  snprintf(path, sizeof(path), path_format[i], prefix, hostvendor, hostname);
247  dir = opendir(path);
248  if ( dir == NULL )
249   continue;
250
251  while ((dirent = readdir(dir)) != NULL) {
252   if ( !strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, "..") )
253    continue;
254
255   for (j = 0; j < 3; j++) {
256    snprintf(file, sizeof(file), file_format[j], path, dirent->d_name, name);
257    ret = roar_dl_open(file, flags, ra_init, para);
258    if ( ret != NULL ) {
259     closedir(dir);
260     return ret;
261    }
262   }
263  }
264
265  closedir(dir);
266 }
267
268 return NULL;
269}
270
271static struct roar_dl_lhandle * _load_from_path(const char * name, int flags, int ra_init,
272                                                struct roar_dl_librarypara * para) {
273 struct roar_dl_lhandle * ret = NULL;
274 char * host = NULL;
275 char * hostvendor_buffer = NULL;
276 char * hostvendor = NULL;
277 char * hostname = NULL;
278 char * c, * d;
279
280 if ( para != NULL && para->appname != NULL && para->appname[0] != 0 ) {
281  host = roar_mm_strdup(para->appname);
282
283  // if we are out of memory we will likely not pass the rest, so just return in error.
284  if ( host == NULL )
285   return NULL;
286
287  hostname = host;
288  c = strstr(host, "<");
289  if ( c != NULL ) {
290   while (c[-1] == ' ') c--;
291   *c = 0;
292   c++;
293   while (*c == ' ' || *c == '<') c++;
294   if ( *c ) {
295    d = strstr(c, ">");
296    if ( d != NULL )
297     *d = 0;
298
299    d = strstr(c, "/");
300    if ( d != NULL ) {
301     *d = '-';
302     hostvendor = c;
303    } else {
304     hostvendor_buffer = roar_mm_malloc(roar_mm_strlen(c) + 1 /* tailing \0 */ + 6 /* "unreg-" */);
305
306     // see above
307     if ( hostvendor_buffer == NULL ) {
308      roar_mm_free(host);
309      return NULL;
310     }
311
312     strcpy(hostvendor_buffer, "unreg-");
313     strcat(hostvendor_buffer, c);
314     hostvendor = hostvendor_buffer;
315    }
316   }
317  }
318 }
319
320 if ( hostvendor == NULL )
321  hostvendor = "universal";
322
323 if ( hostname == NULL )
324  hostname = "universal";
325
326 ret = _load_from_path_pvn(name, flags, ra_init, para, ROAR_PREFIX_PLUGINS, hostvendor, hostname);
327
328 if ( host != NULL )
329  roar_mm_free(host);
330 if ( hostvendor_buffer != NULL )
331  roar_mm_free(hostvendor_buffer);
332 return ret;
333}
334#endif
335
336static struct roar_dl_lhandle * _roar_dl_open_pluginpath(const char * filename, int flags,
337                                      int ra_init, struct roar_dl_librarypara * para) {
338 flags |= ROAR_DL_FLAG_PLUGINPATH;
339 flags -= ROAR_DL_FLAG_PLUGINPATH;
340
341#ifdef ROAR_HAVE_H_DIRENT
342 // do normal open for everything with a path name.
343 if ( strstr(filename, "/") != NULL )
344  return roar_dl_open(filename, flags, ra_init, para);
345
346 return _load_from_path(filename, flags, ra_init, para);
347#else
348 // fall back to system open function.
349 return roar_dl_open(filename, flags, ra_init, para);
350#endif
351}
352
353struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags,
354                                      int ra_init, struct roar_dl_librarypara * para) {
355 struct roar_dl_lhandle * ret = NULL;
356#if defined(ROAR_HAVE_H_DLFCN)
357#ifdef RTLD_DEEPBIND
358 int libdl_flags = RTLD_DEEPBIND;
359#else
360 int libdl_flags = 0;
361#endif
362#endif
363 int err;
364
365 switch (flags) {
366  case ROAR_DL_FLAG_DEFAULTS: flags = ROAR_DL_FLAG_NONE;       break;
367  case ROAR_DL_FLAG_PLUGIN:   flags = ROAR_DL_FLAG_PLUGINPATH; break;
368 }
369
370 if ( flags & ROAR_DL_FLAG_PLUGINPATH )
371  return _roar_dl_open_pluginpath(filename, flags, ra_init, para);
372
373#if defined(ROAR_HAVE_H_DLFCN)
374 if ( flags & ROAR_DL_FLAG_LAZY ) {
375  libdl_flags |= RTLD_LAZY;
376 } else {
377  libdl_flags |= RTLD_NOW;
378 }
379#endif
380
381 if ( (ret = roar_mm_malloc(sizeof(struct roar_dl_lhandle))) == NULL )
382  return NULL;
383
384 memset(ret, 0, sizeof(struct roar_dl_lhandle));
385
386 roar_err_initstore(&(ret->context.error_state));
387
388 ret->flags = flags;
389 ret->refc  = 1;
390
391 if ( flags & ROAR_DL_FLAG_STATIC ) {
392  if ( filename == NULL ) {
393   ret->libname = NULL;
394  } else {
395   ret->libname = roar_mm_strdup(filename);
396  }
397 } else {
398#if defined(ROAR_HAVE_H_DLFCN)
399  ret->handle = dlopen(filename, libdl_flags);
400
401  if ( ret->handle == NULL ) {
402   ROAR_DBG("roar_dl_open(filename='%s', flags=%i, ra_init=%i, para=%p): Can not load library: %s", filename, flags, ra_init, para, roar_dl_errstr(ret));
403   roar_mm_free(ret);
404   return NULL;
405  }
406#elif defined(ROAR_TARGET_WIN32)
407  ret->handle = LoadLibrary(filename);
408
409  if ( ret->handle == NULL ) {
410   roar_mm_free(ret);
411   return NULL;
412  }
413#else
414  roar_mm_free(ret);
415  roar_err_set(ROAR_ERROR_NOSYS);
416  return NULL;
417#endif
418 }
419
420 ret->para = para;
421
422 if ( ra_init ) {
423  if ( roar_dl_ra_init(ret, NULL, para) == -1 ) {
424   err = roar_error;
425   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));
426#if defined(ROAR_HAVE_H_DLFCN)
427   if ( ret->handle != NULL )
428    dlclose(ret->handle);
429#elif defined(ROAR_TARGET_WIN32)
430   if ( ret->handle != NULL )
431    FreeLibrary(ret->handle);
432#endif
433   roar_mm_free(ret);
434   roar_error = err;
435   return NULL;
436  }
437 }
438
439 if ( para != NULL )
440  roar_dl_para_ref(para);
441
442 return ret;
443}
444
445int                      roar_dl_ref    (struct roar_dl_lhandle * lhandle) {
446 if ( (void*)lhandle < (void*)128 ) {
447  ROAR_DBG("roar_dl_ref(lhandle=%p) = -1 // error=BADFH", lhandle);
448  roar_err_set(ROAR_ERROR_BADFH);
449  return -1;
450 }
451
452 lhandle->refc++;
453
454 ROAR_DBG("roar_dl_ref(lhandle=%p) = 0", lhandle);
455 return 0;
456}
457
458int                      roar_dl_unref  (struct roar_dl_lhandle * lhandle) {
459 int ret = -1;
460
461 if ( (void*)lhandle < (void*)128 ) {
462  ROAR_DBG("roar_dl_unref(lhandle=%p) = -1 // error=BADFH", lhandle);
463  roar_err_set(ROAR_ERROR_BADFH);
464  return -1;
465 }
466
467 lhandle->refc--;
468
469 if ( lhandle->refc ) {
470  ROAR_DBG("roar_dl_unref(lhandle=%p) = 0", lhandle);
471  return 0;
472 }
473
474 roar_dl_unregister_fn(lhandle);
475
476 if ( lhandle->lib != NULL && lhandle->lib->unload != NULL ) {
477  roar_dl_context_restore(lhandle);
478  lhandle->lib->unload(lhandle->para, lhandle->lib);
479  roar_dl_context_store(lhandle);
480 }
481
482#if defined(ROAR_HAVE_H_DLFCN)
483 if ( lhandle->handle == NULL ) {
484  ret = 0;
485 } else {
486  ret = dlclose(_roardl2ldl(lhandle));
487 }
488#elif defined(ROAR_TARGET_WIN32)
489 if ( lhandle->handle == NULL ) {
490  ret = 0;
491 } else {
492  if ( FreeLibrary(_roardl2winhandle(lhandle)) ) {
493   ret = 0;
494  } else {
495   ret = -1;
496  }
497 }
498#else
499 ret = -1;
500#endif
501
502 if ( lhandle->context.global_data != NULL )
503  roar_mm_free(lhandle->context.global_data);
504
505 if ( lhandle->para != NULL )
506  roar_dl_para_unref(lhandle->para);
507
508 if ( lhandle->libname != NULL )
509  roar_mm_free(lhandle->libname);
510
511 roar_mm_free(lhandle);
512
513 ROAR_DBG("roar_dl_unref(lhandle=%p) = %i", lhandle, ret);
514 return ret;
515}
516
517void                   * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type) {
518#if defined(ROAR_HAVE_H_DLFCN)
519 void * ret = dlsym(_roardl2ldl(lhandle), sym);
520
521 (void)type;
522
523 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i): errno=%s, dlerror()='%s'", lhandle, sym, type, ret, strerror(errno), dlerror());
524 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = %p", lhandle, sym, type, ret);
525
526 return ret;
527#elif defined(ROAR_TARGET_WIN32)
528 FARPROC ret = GetProcAddress(_roardl2winhandle(lhandle), sym);
529 return (void*)ret;
530#else
531 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = NULL // errno=NOSYS", lhandle, sym, type, ret);
532 roar_err_set(ROAR_ERROR_NOSYS);
533 return NULL;
534#endif
535}
536
537int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
538                                         const char * prefix,
539                                         struct roar_dl_librarypara * para) {
540 struct roar_dl_lhandle * old_init;
541 int old_fn;
542#define _SUFFIX "_roaraudio_library_init"
543 char name[80] = _SUFFIX;
544 struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para);
545 struct roar_dl_libraryinst * lib;
546 struct roar_dl_lhandle     * getsymhandle = lhandle;
547 void * global_data_state = NULL;
548 int i;
549
550 if ( (void*)lhandle < (void*)128 ) {
551  if ( prefix == NULL )
552   return -1;
553 } else {
554  if ( lhandle->runtime_flags & RTF_RA_INITED )
555   return 0;
556
557  if ( prefix == NULL )
558   prefix = lhandle->libname;
559
560  if ( para == NULL )
561   para = lhandle->para;
562
563  if ( lhandle->flags & ROAR_DL_FLAG_STATIC )
564   getsymhandle = ROAR_DL_HANDLE_DEFAULT;
565 }
566
567
568 if ( prefix != NULL ) {
569  roar_mm_strscpy(name, "_");
570  roar_mm_strscat(name, prefix);
571  roar_mm_strscat(name, _SUFFIX);
572 }
573
574 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): name='%s'", lhandle, prefix, name);
575
576 if ( (func = roar_dl_getsym(getsymhandle, name, -1)) == NULL ) {
577  ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s') = -1", lhandle, prefix);
578  return -1;
579 }
580
581 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): func=%p", lhandle, prefix, func);
582
583 roar_err_set(ROAR_ERROR_BADLIB); // set a default error in case it returns NULL but not set an error code.
584 lib = func(para);
585
586 if ( lib == NULL )
587  return -1;
588
589 if ( lib->version != ROAR_DL_LIBINST_VERSION )
590  return -1;
591
592 if ( sizeof(struct roar_dl_libraryinst) > lib->len )
593  return -1;
594
595 if ( lib->host_appname != NULL || lib->host_abiversion != NULL ) {
596  // check for correct host.
597  if ( para == NULL ) {
598   roar_err_set(ROAR_ERROR_INVAL);
599   return -1;
600  }
601  if ( roar_dl_para_check_version(para, lib->host_appname, lib->host_abiversion) == -1 )
602   return -1;
603 }
604
605 if ( (lib->libdep == NULL && lib->libdep_len) || (lib->libdep != NULL && !lib->libdep_len) ) {
606  roar_err_set(ROAR_ERROR_BADLIB);
607  return -1;
608 }
609
610 if ( lib->libdep != NULL && lib->libdep_len ) {
611  // dynamic loader infos are currently not supported.
612  roar_err_set(ROAR_ERROR_NOTSUP);
613  return -1;
614 }
615
616 if ( !((void*)lhandle < (void*)128) ) {
617  lhandle->lib = lib;
618
619  if ( lib->global_data_len ) {
620   lhandle->context.global_data = roar_mm_malloc(lib->global_data_len);
621   if ( lhandle->context.global_data == NULL )
622    return -1;
623
624   if ( lib->global_data_init == NULL ) {
625    memset(lhandle->context.global_data, 0, lib->global_data_len);
626   } else {
627    memcpy(lhandle->context.global_data, lib->global_data_init, lib->global_data_len);
628   }
629  }
630 }
631
632 if ( lib->global_data_pointer != NULL ) {
633  global_data_state = *(lib->global_data_pointer);
634  if ( (void*)lhandle < (void*)128 ) {
635   *(lib->global_data_pointer) = lib->global_data_init;
636  } else {
637   *(lib->global_data_pointer) = lhandle->context.global_data;
638  }
639 }
640
641 old_init = __currently_inited;
642 old_fn   = __currently_inited_fn;
643 __currently_inited = lhandle;
644 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
645  __currently_inited_fn = i;
646  if ( lib->func[i] != NULL )
647   lib->func[i](para, lib);
648 }
649 __currently_inited_fn = old_fn;
650 __currently_inited = old_init;
651
652
653 if ( lib->global_data_pointer != NULL ) {
654  if ( !((void*)lhandle < (void*)128) ) {
655   *(lib->global_data_pointer) = global_data_state;
656  }
657 }
658
659 if ( !((void*)lhandle < (void*)128) )
660  lhandle->runtime_flags |= RTF_RA_INITED;
661
662 return 0;
663}
664
665const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
666#if defined(ROAR_HAVE_H_DLFCN)
667 (void)lhandle;
668 return dlerror();
669#elif defined(ROAR_TARGET_WIN32)
670 roar_err_from_errno();
671 return roar_error2str(roar_error);
672#else
673 return NULL;
674#endif
675}
676
677struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
678 if ( (void*)lhandle < (void*)128 ) {
679  roar_err_set(ROAR_ERROR_NOTSUP);
680  return NULL;
681 }
682
683 if ( lhandle->para == NULL ) {
684  roar_err_set(ROAR_ERROR_NOENT);
685  return NULL;
686 }
687
688 if ( roar_dl_para_ref(lhandle->para) == -1 )
689  return NULL;
690
691 return lhandle->para;
692}
693
694const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
695 if ( (void*)lhandle < (void*)128 ) {
696  roar_err_set(ROAR_ERROR_NOTSUP);
697  return NULL;
698 }
699
700 if ( lhandle->lib == NULL ) {
701  roar_err_set(ROAR_ERROR_BADLIB);
702  return NULL;
703 }
704
705 if ( lhandle->lib->libname == NULL ) {
706  roar_err_set(ROAR_ERROR_NOENT);
707  return NULL;
708 }
709
710 if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
711  roar_err_set(ROAR_ERROR_BADVERSION);
712  return NULL;
713 }
714
715 if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
716  roar_err_set(ROAR_ERROR_HOLE);
717  return NULL;
718 }
719
720 return lhandle->lib->libname;
721}
722
723int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
724 struct roar_error_state error_state;
725
726 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = ?", lhandle);
727
728 if ( (void*)lhandle < (void*)128 ) {
729  ROAR_DBG("roar_dl_context_restore(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
730  roar_err_set(ROAR_ERROR_NOTSUP);
731  return -1;
732 }
733
734 roar_err_store(&error_state);
735 roar_err_restore(&(lhandle->context.error_state));
736 lhandle->context.error_state = error_state;
737
738 if ( lhandle->lib->global_data_pointer != NULL ) {
739  ROAR_DBG("roar_dl_context_restore(lhandle=%p): gptr(%p): %p -> %p", lhandle,
740           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data);
741  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
742  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
743 }
744
745 if ( lhandle->para->notifycore != NULL )
746  lhandle->context.notifycore = roar_notify_core_swap_global(lhandle->para->notifycore);
747
748 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = 0", lhandle);
749 return 0;
750}
751
752int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
753 struct roar_error_state error_state;
754
755 ROAR_DBG("roar_dl_context_store(lhandle=%p) = ?", lhandle);
756
757 if ( (void*)lhandle < (void*)128 ) {
758  ROAR_DBG("roar_dl_context_store(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
759  roar_err_set(ROAR_ERROR_NOTSUP);
760  return -1;
761 }
762
763 if ( lhandle->para->notifycore != NULL ) {
764  roar_notify_core_unref(roar_notify_core_swap_global(lhandle->context.notifycore));
765  roar_notify_core_unref(lhandle->context.notifycore);
766  lhandle->context.notifycore = NULL;
767 }
768
769 if ( lhandle->lib->global_data_pointer != NULL ) {
770  ROAR_DBG("roar_dl_context_store(lhandle=%p): gptr(%p): %p -> %p", lhandle,
771           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data_state);
772  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data_state;
773 }
774
775 roar_err_store(&error_state);
776 roar_err_restore(&(lhandle->context.error_state));
777 lhandle->context.error_state = error_state;
778
779 ROAR_DBG("roar_dl_context_store(lhandle=%p) = 0", lhandle);
780 return 0;
781}
782
783int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger) {
784 int (*func)  (struct roar_dl_librarypara * para) = NULL;
785 int ret;
786
787 if ( (void*)lhandle < (void*)128 ) {
788  roar_err_set(ROAR_ERROR_NOTSUP);
789  return -1;
790 }
791
792 if ( lhandle->lib == NULL ) {
793  roar_err_set(ROAR_ERROR_TYPEMM);
794  return -1;
795 }
796
797 if ( lhandle->lib->appsched == NULL ) {
798  roar_err_set(ROAR_ERROR_NOENT);
799  return -1;
800 }
801
802 switch (trigger) {
803#define _trig(lname,uname) \
804  case ROAR_DL_APPSCHED_ ## uname :             \
805    func = lhandle->lib->appsched->lname;       \
806   break;
807  _trig(init, INIT);
808  _trig(free, FREE);
809  _trig(update, UPDATE);
810  _trig(tick, TICK);
811  _trig(wait, WAIT);
812// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
813#ifndef DEBUG
814  default:
815    roar_err_set(ROAR_ERROR_BADRQC);
816    return -1;
817   break;
818#endif
819 }
820
821 if ( func == NULL ) {
822  if ( trigger == ROAR_DL_APPSCHED_INIT ) {
823   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
824   lhandle->runtime_flags -= RTF_APPSCHED_FREED;
825  } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
826   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
827   lhandle->runtime_flags -= RTF_APPSCHED_INITED;
828  }
829  roar_err_set(ROAR_ERROR_NOENT);
830  return -1;
831 }
832
833 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
834  if ( lhandle->runtime_flags & RTF_APPSCHED_INITED ) {
835   roar_err_set(ROAR_ERROR_BUSY);
836   return -1;
837  }
838 } else {
839  if ( !(lhandle->runtime_flags & RTF_APPSCHED_INITED) ) {
840   roar_err_set(ROAR_ERROR_BUSY);
841   return -1;
842  }
843 }
844
845 roar_dl_context_restore(lhandle);
846 ret = func(lhandle->para);
847 roar_dl_context_store(lhandle);
848
849 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
850  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
851  lhandle->runtime_flags -= RTF_APPSCHED_FREED;
852 } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
853  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
854  lhandle->runtime_flags -= RTF_APPSCHED_INITED;
855 }
856
857 return ret;
858}
859
860
861#define __MAX_FNREGS 24
862static struct __fnregs {
863 struct roar_dl_lhandle * lhandle;
864 int subtype;
865 const void * object;
866 size_t objectlen;
867 int version;
868 int options;
869} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
870
871static int  __fnreg_check_trigger(const struct __fnregs * handle) {
872 if ( handle->subtype != ROAR_DL_FNREG_SUBTYPE )
873  return -1;
874 if ( handle->version != ROAR_DL_FNREG_VERSION )
875  return -1;
876 if ( handle->objectlen != ROAR_DL_FNREG_SIZE )
877  return -1;
878
879 return 0;
880}
881
882static void __fnreg_trigger_if_match(const struct roar_dl_fnreg * callback,
883                                     const struct __fnregs * reg,
884                                     int fn,
885                                     enum roar_dl_fnreg_action action) {
886 if ( callback->fn != -1 && callback->fn != fn )
887  return;
888 if ( callback->subtype != -1 && callback->subtype != reg->subtype )
889  return;
890 if ( callback->version != -1 && callback->version != reg->version )
891  return;
892
893 if ( callback->callback == NULL )
894  return;
895
896 callback->callback(action, fn, reg->subtype, reg->object, reg->objectlen, reg->version, reg->options, callback->userdata, reg->lhandle);
897}
898
899static void __fnreg_trigger_by_reg(const struct __fnregs * reg, enum roar_dl_fnreg_action action, int fn) {
900 size_t j;
901
902 for (j = 0; j < __MAX_FNREGS; j++) {
903  if ( __fnrefs[ROAR_DL_FN_REGFN][j].lhandle != NULL ) {
904   if ( __fnreg_check_trigger(&(__fnrefs[ROAR_DL_FN_REGFN][j])) == -1 )
905    continue;
906   __fnreg_trigger_if_match(__fnrefs[ROAR_DL_FN_REGFN][j].object, reg, fn, action);
907  }
908 }
909}
910
911static void __fnreg_trigger_by_handler(const struct __fnregs * handle, enum roar_dl_fnreg_action action) {
912 size_t i, j;
913
914 if ( __fnreg_check_trigger(handle) == -1 )
915  return;
916
917 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
918  for (j = 0; j < __MAX_FNREGS; j++) {
919   if ( __fnrefs[i][j].lhandle != NULL ) {
920    __fnreg_trigger_if_match(handle->object, &(__fnrefs[i][j]), i, action);
921   }
922  }
923 }
924}
925
926int roar_dl_register_fn(struct roar_dl_lhandle * lhandle, int fn, int subtype, const void * object, size_t objectlen, int version, int options) {
927 struct __fnregs * c = NULL;
928 size_t i;
929
930 if ( lhandle == NULL )
931  lhandle = __currently_inited;
932
933 if ( fn == -1 )
934  fn = __currently_inited_fn;
935
936 if ( lhandle == NULL ) {
937  roar_err_set(ROAR_ERROR_FAULT);
938  return -1;
939 }
940
941 if ( fn < 0 || fn >= ROAR_DL_FN_MAX ) {
942  roar_err_set(ROAR_ERROR_RANGE);
943  return -1;
944 }
945
946 if ( object == NULL || objectlen == 0 ) {
947  roar_err_set(ROAR_ERROR_INVAL);
948  return -1;
949 }
950
951 for (i = 0; i < __MAX_FNREGS; i++) {
952  if ( __fnrefs[fn][i].lhandle != NULL )
953   continue;
954  c = &(__fnrefs[fn][i]);
955  break;
956 }
957
958 if ( c == NULL ) {
959  roar_err_set(ROAR_ERROR_NOSPC);
960  return -1;
961 }
962
963 c->lhandle   = lhandle;
964 c->subtype   = subtype;
965 c->object    = object;
966 c->objectlen = objectlen;
967 c->version   = version;
968
969 if ( fn == ROAR_DL_FN_REGFN ) {
970  __fnreg_trigger_by_handler(c, ROAR_DL_FNREG);
971 } else {
972  __fnreg_trigger_by_reg(c, ROAR_DL_FNREG, fn);
973 }
974
975 return 0;
976}
977
978int roar_dl_unregister_fn(struct roar_dl_lhandle * lhandle) {
979 size_t i, j;
980
981//} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
982
983 if ( lhandle == NULL ) {
984  roar_err_set(ROAR_ERROR_FAULT);
985  return -1;
986 }
987
988 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
989  for (j = 0; j < __MAX_FNREGS; j++) {
990   if ( __fnrefs[i][j].lhandle == lhandle ) {
991    if ( i == ROAR_DL_FN_REGFN ) {
992     __fnreg_trigger_by_handler(&(__fnrefs[i][j]), ROAR_DL_FNUNREG);
993    } else {
994     __fnreg_trigger_by_reg(&(__fnrefs[i][j]), ROAR_DL_FNUNREG, i);
995    }
996    memset(&(__fnrefs[i][j]), 0, sizeof(__fnrefs[i][j]));
997    __fnrefs[i][j].lhandle = NULL;
998   }
999  }
1000 }
1001
1002 return 0;
1003}
1004
1005//ll
Note: See TracBrowser for help on using the repository browser.