source: roaraudio/libroar/roardl.c @ 5692:0480fc56e68a

Last change on this file since 5692:0480fc56e68a was 5688:c7e8e3a700ec, checked in by phi, 12 years ago

avoid a warning on OpenBSD

File size: 26.8 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 size_t hostvendor_len;
279 char * c, * d;
280
281 if ( para != NULL && para->appname != NULL && para->appname[0] != 0 ) {
282  host = roar_mm_strdup(para->appname);
283
284  // if we are out of memory we will likely not pass the rest, so just return in error.
285  if ( host == NULL )
286   return NULL;
287
288  hostname = host;
289  c = strstr(host, "<");
290  if ( c != NULL ) {
291   while (c[-1] == ' ') c--;
292   *c = 0;
293   c++;
294   while (*c == ' ' || *c == '<') c++;
295   if ( *c ) {
296    d = strstr(c, ">");
297    if ( d != NULL )
298     *d = 0;
299
300    d = strstr(c, "/");
301    if ( d != NULL ) {
302     *d = '-';
303     hostvendor = c;
304    } else {
305     hostvendor_len = roar_mm_strlen(c) + 1 /* tailing \0 */ + 6 /* "unreg-" */;
306     hostvendor_buffer = roar_mm_malloc(hostvendor_len);
307
308     // see above
309     if ( hostvendor_buffer == NULL ) {
310      roar_mm_free(host);
311      return NULL;
312     }
313
314     roar_mm_strlcpy(hostvendor_buffer, "unreg-", hostvendor_len);
315     roar_mm_strlcat(hostvendor_buffer, c, hostvendor_len);
316     hostvendor = hostvendor_buffer;
317    }
318   }
319  }
320 }
321
322 if ( hostvendor == NULL )
323  hostvendor = "universal";
324
325 if ( hostname == NULL )
326  hostname = "universal";
327
328 ret = _load_from_path_pvn(name, flags, ra_init, para, ROAR_PREFIX_PLUGINS, hostvendor, hostname);
329
330 if ( host != NULL )
331  roar_mm_free(host);
332 if ( hostvendor_buffer != NULL )
333  roar_mm_free(hostvendor_buffer);
334 return ret;
335}
336#endif
337
338static struct roar_dl_lhandle * _roar_dl_open_pluginpath(const char * filename, int flags,
339                                      int ra_init, struct roar_dl_librarypara * para) {
340 flags |= ROAR_DL_FLAG_PLUGINPATH;
341 flags -= ROAR_DL_FLAG_PLUGINPATH;
342
343#ifdef ROAR_HAVE_H_DIRENT
344 // do normal open for everything with a path name.
345 if ( strstr(filename, "/") != NULL )
346  return roar_dl_open(filename, flags, ra_init, para);
347
348 return _load_from_path(filename, flags, ra_init, para);
349#else
350 // fall back to system open function.
351 return roar_dl_open(filename, flags, ra_init, para);
352#endif
353}
354
355struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags,
356                                      int ra_init, struct roar_dl_librarypara * para) {
357 struct roar_dl_lhandle * ret = NULL;
358#if defined(ROAR_HAVE_H_DLFCN)
359#ifdef RTLD_DEEPBIND
360 int libdl_flags = RTLD_DEEPBIND;
361#else
362 int libdl_flags = 0;
363#endif
364#endif
365 int err;
366
367 switch (flags) {
368  case ROAR_DL_FLAG_DEFAULTS: flags = ROAR_DL_FLAG_NONE;       break;
369  case ROAR_DL_FLAG_PLUGIN:   flags = ROAR_DL_FLAG_PLUGINPATH; break;
370 }
371
372 if ( flags & ROAR_DL_FLAG_PLUGINPATH )
373  return _roar_dl_open_pluginpath(filename, flags, ra_init, para);
374
375#if defined(ROAR_HAVE_H_DLFCN)
376 if ( flags & ROAR_DL_FLAG_LAZY ) {
377  libdl_flags |= RTLD_LAZY;
378 } else {
379  libdl_flags |= RTLD_NOW;
380 }
381#endif
382
383 if ( (ret = roar_mm_malloc(sizeof(struct roar_dl_lhandle))) == NULL )
384  return NULL;
385
386 memset(ret, 0, sizeof(struct roar_dl_lhandle));
387
388 roar_err_initstore(&(ret->context.error_state));
389
390 ret->flags = flags;
391 ret->refc  = 1;
392
393 if ( flags & ROAR_DL_FLAG_STATIC ) {
394  if ( filename == NULL ) {
395   ret->libname = NULL;
396  } else {
397   ret->libname = roar_mm_strdup(filename);
398  }
399 } else {
400#if defined(ROAR_HAVE_H_DLFCN)
401  ret->handle = dlopen(filename, libdl_flags);
402
403  if ( ret->handle == NULL ) {
404   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));
405   roar_mm_free(ret);
406   return NULL;
407  }
408#elif defined(ROAR_TARGET_WIN32)
409  ret->handle = LoadLibrary(filename);
410
411  if ( ret->handle == NULL ) {
412   roar_mm_free(ret);
413   return NULL;
414  }
415#else
416  roar_mm_free(ret);
417  roar_err_set(ROAR_ERROR_NOSYS);
418  return NULL;
419#endif
420 }
421
422 ret->para = para;
423
424 if ( ra_init ) {
425  if ( roar_dl_ra_init(ret, NULL, para) == -1 ) {
426   err = roar_error;
427   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));
428#if defined(ROAR_HAVE_H_DLFCN)
429   if ( ret->handle != NULL )
430    dlclose(ret->handle);
431#elif defined(ROAR_TARGET_WIN32)
432   if ( ret->handle != NULL )
433    FreeLibrary(ret->handle);
434#endif
435   roar_mm_free(ret);
436   roar_error = err;
437   return NULL;
438  }
439 }
440
441 if ( para != NULL )
442  roar_dl_para_ref(para);
443
444 return ret;
445}
446
447int                      roar_dl_ref    (struct roar_dl_lhandle * lhandle) {
448 if ( (void*)lhandle < (void*)128 ) {
449  ROAR_DBG("roar_dl_ref(lhandle=%p) = -1 // error=BADFH", lhandle);
450  roar_err_set(ROAR_ERROR_BADFH);
451  return -1;
452 }
453
454 lhandle->refc++;
455
456 ROAR_DBG("roar_dl_ref(lhandle=%p) = 0", lhandle);
457 return 0;
458}
459
460int                      roar_dl_unref  (struct roar_dl_lhandle * lhandle) {
461 int ret = -1;
462
463 if ( (void*)lhandle < (void*)128 ) {
464  ROAR_DBG("roar_dl_unref(lhandle=%p) = -1 // error=BADFH", lhandle);
465  roar_err_set(ROAR_ERROR_BADFH);
466  return -1;
467 }
468
469 lhandle->refc--;
470
471 if ( lhandle->refc ) {
472  ROAR_DBG("roar_dl_unref(lhandle=%p) = 0", lhandle);
473  return 0;
474 }
475
476 roar_dl_unregister_fn(lhandle);
477
478 if ( lhandle->lib != NULL && lhandle->lib->unload != NULL ) {
479  roar_dl_context_restore(lhandle);
480  lhandle->lib->unload(lhandle->para, lhandle->lib);
481  roar_dl_context_store(lhandle);
482 }
483
484#if defined(ROAR_HAVE_H_DLFCN)
485 if ( lhandle->handle == NULL ) {
486  ret = 0;
487 } else {
488  ret = dlclose(_roardl2ldl(lhandle));
489 }
490#elif defined(ROAR_TARGET_WIN32)
491 if ( lhandle->handle == NULL ) {
492  ret = 0;
493 } else {
494  if ( FreeLibrary(_roardl2winhandle(lhandle)) ) {
495   ret = 0;
496  } else {
497   ret = -1;
498  }
499 }
500#else
501 ret = -1;
502#endif
503
504 if ( lhandle->context.global_data != NULL )
505  roar_mm_free(lhandle->context.global_data);
506
507 if ( lhandle->para != NULL )
508  roar_dl_para_unref(lhandle->para);
509
510 if ( lhandle->libname != NULL )
511  roar_mm_free(lhandle->libname);
512
513 roar_mm_free(lhandle);
514
515 ROAR_DBG("roar_dl_unref(lhandle=%p) = %i", lhandle, ret);
516 return ret;
517}
518
519void                   * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type) {
520#if defined(ROAR_HAVE_H_DLFCN)
521 void * ret = dlsym(_roardl2ldl(lhandle), sym);
522
523 (void)type;
524
525 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i): ret=%p, errno=%s(%i), dlerror()='%s'", lhandle, sym, type, ret, strerror(errno), errno, dlerror());
526 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = %p", lhandle, sym, type, ret);
527
528 return ret;
529#elif defined(ROAR_TARGET_WIN32)
530 FARPROC ret = GetProcAddress(_roardl2winhandle(lhandle), sym);
531 return (void*)ret;
532#else
533 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = NULL // errno=NOSYS", lhandle, sym, type, ret);
534 roar_err_set(ROAR_ERROR_NOSYS);
535 return NULL;
536#endif
537}
538
539int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
540                                         const char * prefix,
541                                         struct roar_dl_librarypara * para) {
542 struct roar_dl_lhandle * old_init;
543 int old_fn;
544#define _SUFFIX "_roaraudio_library_init"
545 char name[80] = _SUFFIX;
546 struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para);
547 struct roar_dl_libraryinst * lib;
548 struct roar_dl_lhandle     * getsymhandle = lhandle;
549 void * global_data_state = NULL;
550 int i;
551
552 if ( (void*)lhandle < (void*)128 ) {
553  if ( prefix == NULL )
554   return -1;
555 } else {
556  if ( lhandle->runtime_flags & RTF_RA_INITED )
557   return 0;
558
559  if ( prefix == NULL )
560   prefix = lhandle->libname;
561
562  if ( para == NULL )
563   para = lhandle->para;
564
565  if ( lhandle->flags & ROAR_DL_FLAG_STATIC )
566   getsymhandle = ROAR_DL_HANDLE_DEFAULT;
567 }
568
569
570 if ( prefix != NULL ) {
571  roar_mm_strscpy(name, "_");
572  roar_mm_strscat(name, prefix);
573  roar_mm_strscat(name, _SUFFIX);
574 }
575
576 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): name='%s'", lhandle, prefix, name);
577
578 if ( (func = roar_dl_getsym(getsymhandle, name, -1)) == NULL ) {
579  ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s') = -1", lhandle, prefix);
580  return -1;
581 }
582
583 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): func=%p", lhandle, prefix, func);
584
585 roar_err_set(ROAR_ERROR_BADLIB); // set a default error in case it returns NULL but not set an error code.
586 lib = func(para);
587
588 if ( lib == NULL )
589  return -1;
590
591 if ( lib->version != ROAR_DL_LIBINST_VERSION )
592  return -1;
593
594 if ( sizeof(struct roar_dl_libraryinst) > lib->len )
595  return -1;
596
597 if ( lib->host_appname != NULL || lib->host_abiversion != NULL ) {
598  // check for correct host.
599  if ( para == NULL ) {
600   roar_err_set(ROAR_ERROR_INVAL);
601   return -1;
602  }
603  if ( roar_dl_para_check_version(para, lib->host_appname, lib->host_abiversion) == -1 )
604   return -1;
605 }
606
607 if ( (lib->libdep == NULL && lib->libdep_len) || (lib->libdep != NULL && !lib->libdep_len) ) {
608  roar_err_set(ROAR_ERROR_BADLIB);
609  return -1;
610 }
611
612 if ( lib->libdep != NULL && lib->libdep_len ) {
613  // dynamic loader infos are currently not supported.
614  roar_err_set(ROAR_ERROR_NOTSUP);
615  return -1;
616 }
617
618 if ( !((void*)lhandle < (void*)128) ) {
619  lhandle->lib = lib;
620
621  if ( lib->global_data_len ) {
622   lhandle->context.global_data = roar_mm_malloc(lib->global_data_len);
623   if ( lhandle->context.global_data == NULL )
624    return -1;
625
626   if ( lib->global_data_init == NULL ) {
627    memset(lhandle->context.global_data, 0, lib->global_data_len);
628   } else {
629    memcpy(lhandle->context.global_data, lib->global_data_init, lib->global_data_len);
630   }
631  }
632 }
633
634 if ( lib->global_data_pointer != NULL ) {
635  global_data_state = *(lib->global_data_pointer);
636  if ( (void*)lhandle < (void*)128 ) {
637   *(lib->global_data_pointer) = lib->global_data_init;
638  } else {
639   *(lib->global_data_pointer) = lhandle->context.global_data;
640  }
641 }
642
643 old_init = __currently_inited;
644 old_fn   = __currently_inited_fn;
645 __currently_inited = lhandle;
646 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
647  __currently_inited_fn = i;
648  if ( lib->func[i] != NULL )
649   lib->func[i](para, lib);
650 }
651 __currently_inited_fn = old_fn;
652 __currently_inited = old_init;
653
654
655 if ( lib->global_data_pointer != NULL ) {
656  if ( !((void*)lhandle < (void*)128) ) {
657   *(lib->global_data_pointer) = global_data_state;
658  }
659 }
660
661 if ( !((void*)lhandle < (void*)128) )
662  lhandle->runtime_flags |= RTF_RA_INITED;
663
664 return 0;
665}
666
667const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
668#if defined(ROAR_HAVE_H_DLFCN)
669 (void)lhandle;
670 return dlerror();
671#elif defined(ROAR_TARGET_WIN32)
672 roar_err_from_errno();
673 return roar_error2str(roar_error);
674#else
675 return NULL;
676#endif
677}
678
679struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
680 if ( (void*)lhandle < (void*)128 ) {
681  roar_err_set(ROAR_ERROR_NOTSUP);
682  return NULL;
683 }
684
685 if ( lhandle->para == NULL ) {
686  roar_err_set(ROAR_ERROR_NOENT);
687  return NULL;
688 }
689
690 if ( roar_dl_para_ref(lhandle->para) == -1 )
691  return NULL;
692
693 return lhandle->para;
694}
695
696const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
697 if ( (void*)lhandle < (void*)128 ) {
698  roar_err_set(ROAR_ERROR_NOTSUP);
699  return NULL;
700 }
701
702 if ( lhandle->lib == NULL ) {
703  roar_err_set(ROAR_ERROR_BADLIB);
704  return NULL;
705 }
706
707 if ( lhandle->lib->libname == NULL ) {
708  roar_err_set(ROAR_ERROR_NOENT);
709  return NULL;
710 }
711
712 if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
713  roar_err_set(ROAR_ERROR_BADVERSION);
714  return NULL;
715 }
716
717 if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
718  roar_err_set(ROAR_ERROR_HOLE);
719  return NULL;
720 }
721
722 return lhandle->lib->libname;
723}
724
725int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
726 struct roar_error_state error_state;
727
728 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = ?", lhandle);
729
730 if ( (void*)lhandle < (void*)128 ) {
731  ROAR_DBG("roar_dl_context_restore(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
732  roar_err_set(ROAR_ERROR_NOTSUP);
733  return -1;
734 }
735
736 roar_err_store(&error_state);
737 roar_err_restore(&(lhandle->context.error_state));
738 lhandle->context.error_state = error_state;
739
740 if ( lhandle->lib->global_data_pointer != NULL ) {
741  ROAR_DBG("roar_dl_context_restore(lhandle=%p): gptr(%p): %p -> %p", lhandle,
742           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data);
743  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
744  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
745 }
746
747 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL )
748  lhandle->context.notifycore = roar_notify_core_swap_global(lhandle->para->notifycore);
749
750 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = 0", lhandle);
751 return 0;
752}
753
754int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
755 struct roar_error_state error_state;
756
757 ROAR_DBG("roar_dl_context_store(lhandle=%p) = ?", lhandle);
758
759 if ( (void*)lhandle < (void*)128 ) {
760  ROAR_DBG("roar_dl_context_store(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
761  roar_err_set(ROAR_ERROR_NOTSUP);
762  return -1;
763 }
764
765 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL ) {
766  roar_notify_core_unref(roar_notify_core_swap_global(lhandle->context.notifycore));
767  roar_notify_core_unref(lhandle->context.notifycore);
768  lhandle->context.notifycore = NULL;
769 }
770
771 if ( lhandle->lib->global_data_pointer != NULL ) {
772  ROAR_DBG("roar_dl_context_store(lhandle=%p): gptr(%p): %p -> %p", lhandle,
773           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data_state);
774  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data_state;
775 }
776
777 roar_err_store(&error_state);
778 roar_err_restore(&(lhandle->context.error_state));
779 lhandle->context.error_state = error_state;
780
781 ROAR_DBG("roar_dl_context_store(lhandle=%p) = 0", lhandle);
782 return 0;
783}
784
785int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger) {
786 int (*func)  (struct roar_dl_librarypara * para) = NULL;
787 int ret;
788
789 if ( (void*)lhandle < (void*)128 ) {
790  roar_err_set(ROAR_ERROR_NOTSUP);
791  return -1;
792 }
793
794 if ( lhandle->lib == NULL ) {
795  roar_err_set(ROAR_ERROR_TYPEMM);
796  return -1;
797 }
798
799 if ( lhandle->lib->appsched == NULL ) {
800  roar_err_set(ROAR_ERROR_NOENT);
801  return -1;
802 }
803
804 switch (trigger) {
805#define _trig(lname,uname) \
806  case ROAR_DL_APPSCHED_ ## uname :             \
807    func = lhandle->lib->appsched->lname;       \
808   break;
809  _trig(init, INIT);
810  _trig(free, FREE);
811  _trig(update, UPDATE);
812  _trig(tick, TICK);
813  _trig(wait, WAIT);
814// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
815#ifndef DEBUG
816  default:
817    roar_err_set(ROAR_ERROR_BADRQC);
818    return -1;
819   break;
820#endif
821 }
822
823 if ( func == NULL ) {
824  if ( trigger == ROAR_DL_APPSCHED_INIT ) {
825   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
826   lhandle->runtime_flags -= RTF_APPSCHED_FREED;
827  } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
828   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
829   lhandle->runtime_flags -= RTF_APPSCHED_INITED;
830  }
831  roar_err_set(ROAR_ERROR_NOENT);
832  return -1;
833 }
834
835 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
836  if ( lhandle->runtime_flags & RTF_APPSCHED_INITED ) {
837   roar_err_set(ROAR_ERROR_BUSY);
838   return -1;
839  }
840 } else {
841  if ( !(lhandle->runtime_flags & RTF_APPSCHED_INITED) ) {
842   roar_err_set(ROAR_ERROR_BUSY);
843   return -1;
844  }
845 }
846
847 roar_dl_context_restore(lhandle);
848 ret = func(lhandle->para);
849 roar_dl_context_store(lhandle);
850
851 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
852  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
853  lhandle->runtime_flags -= RTF_APPSCHED_FREED;
854 } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
855  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
856  lhandle->runtime_flags -= RTF_APPSCHED_INITED;
857 }
858
859 return ret;
860}
861
862
863#define __MAX_FNREGS 24
864static struct __fnregs {
865 struct roar_dl_lhandle * lhandle;
866 int subtype;
867 const void * object;
868 size_t objectlen;
869 int version;
870 int options;
871} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
872
873static int  __fnreg_check_trigger(const struct __fnregs * handle) {
874 if ( handle->subtype != ROAR_DL_FNREG_SUBTYPE )
875  return -1;
876 if ( handle->version != ROAR_DL_FNREG_VERSION )
877  return -1;
878 if ( handle->objectlen != ROAR_DL_FNREG_SIZE )
879  return -1;
880
881 return 0;
882}
883
884static void __fnreg_trigger_if_match(const struct roar_dl_fnreg * callback,
885                                     const struct __fnregs * reg,
886                                     int fn,
887                                     enum roar_dl_fnreg_action action) {
888 if ( callback->fn != -1 && callback->fn != fn )
889  return;
890 if ( callback->subtype != -1 && callback->subtype != reg->subtype )
891  return;
892 if ( callback->version != -1 && callback->version != reg->version )
893  return;
894
895 if ( callback->callback == NULL )
896  return;
897
898 callback->callback(action, fn, reg->subtype, reg->object, reg->objectlen, reg->version, reg->options, callback->userdata, reg->lhandle);
899}
900
901static void __fnreg_trigger_by_reg(const struct __fnregs * reg, enum roar_dl_fnreg_action action, int fn) {
902 size_t j;
903
904 for (j = 0; j < __MAX_FNREGS; j++) {
905  if ( __fnrefs[ROAR_DL_FN_REGFN][j].lhandle != NULL ) {
906   if ( __fnreg_check_trigger(&(__fnrefs[ROAR_DL_FN_REGFN][j])) == -1 )
907    continue;
908   __fnreg_trigger_if_match(__fnrefs[ROAR_DL_FN_REGFN][j].object, reg, fn, action);
909  }
910 }
911}
912
913static void __fnreg_trigger_by_handler(const struct __fnregs * handle, enum roar_dl_fnreg_action action) {
914 size_t i, j;
915
916 if ( __fnreg_check_trigger(handle) == -1 )
917  return;
918
919 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
920  for (j = 0; j < __MAX_FNREGS; j++) {
921   if ( __fnrefs[i][j].lhandle != NULL ) {
922    __fnreg_trigger_if_match(handle->object, &(__fnrefs[i][j]), i, action);
923   }
924  }
925 }
926}
927
928int roar_dl_register_fn(struct roar_dl_lhandle * lhandle, int fn, int subtype, const void * object, size_t objectlen, int version, int options) {
929 struct __fnregs * c = NULL;
930 size_t i;
931
932 if ( lhandle == NULL )
933  lhandle = __currently_inited;
934
935 if ( fn == -1 )
936  fn = __currently_inited_fn;
937
938 if ( lhandle == NULL ) {
939  roar_err_set(ROAR_ERROR_FAULT);
940  return -1;
941 }
942
943 if ( fn < 0 || fn >= ROAR_DL_FN_MAX ) {
944  roar_err_set(ROAR_ERROR_RANGE);
945  return -1;
946 }
947
948 if ( object == NULL || objectlen == 0 ) {
949  roar_err_set(ROAR_ERROR_INVAL);
950  return -1;
951 }
952
953 for (i = 0; i < __MAX_FNREGS; i++) {
954  if ( __fnrefs[fn][i].lhandle != NULL )
955   continue;
956  c = &(__fnrefs[fn][i]);
957  break;
958 }
959
960 if ( c == NULL ) {
961  roar_err_set(ROAR_ERROR_NOSPC);
962  return -1;
963 }
964
965 c->lhandle   = lhandle;
966 c->subtype   = subtype;
967 c->object    = object;
968 c->objectlen = objectlen;
969 c->version   = version;
970
971 if ( fn == ROAR_DL_FN_REGFN ) {
972  __fnreg_trigger_by_handler(c, ROAR_DL_FNREG);
973 } else {
974  __fnreg_trigger_by_reg(c, ROAR_DL_FNREG, fn);
975 }
976
977 return 0;
978}
979
980int roar_dl_unregister_fn(struct roar_dl_lhandle * lhandle) {
981 size_t i, j;
982
983//} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
984
985 if ( lhandle == NULL ) {
986  roar_err_set(ROAR_ERROR_FAULT);
987  return -1;
988 }
989
990 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
991  for (j = 0; j < __MAX_FNREGS; j++) {
992   if ( __fnrefs[i][j].lhandle == lhandle ) {
993    if ( i == ROAR_DL_FN_REGFN ) {
994     __fnreg_trigger_by_handler(&(__fnrefs[i][j]), ROAR_DL_FNUNREG);
995    } else {
996     __fnreg_trigger_by_reg(&(__fnrefs[i][j]), ROAR_DL_FNUNREG, i);
997    }
998    memset(&(__fnrefs[i][j]), 0, sizeof(__fnrefs[i][j]));
999    __fnrefs[i][j].lhandle = NULL;
1000   }
1001  }
1002 }
1003
1004 return 0;
1005}
1006
1007//ll
Note: See TracBrowser for help on using the repository browser.