source: roaraudio/libroar/roardl.c @ 5816:6c593d184ef2

Last change on this file since 5816:6c593d184ef2 was 5816:6c593d184ef2, checked in by phi, 11 years ago

improved service interface even more, allow creation of a simple interface object to access functions.

File size: 29.4 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 roar_dl_context_restore(lhandle);
644
645 old_init = __currently_inited;
646 old_fn   = __currently_inited_fn;
647 __currently_inited = lhandle;
648 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
649  __currently_inited_fn = i;
650  if ( lib->func[i] != NULL )
651   lib->func[i](para, lib);
652 }
653 __currently_inited_fn = old_fn;
654 __currently_inited = old_init;
655
656 roar_dl_context_store(lhandle);
657
658 if ( lib->global_data_pointer != NULL ) {
659  if ( !((void*)lhandle < (void*)128) ) {
660   *(lib->global_data_pointer) = global_data_state;
661  }
662 }
663
664 if ( !((void*)lhandle < (void*)128) )
665  lhandle->runtime_flags |= RTF_RA_INITED;
666
667 return 0;
668}
669
670const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
671#if defined(ROAR_HAVE_H_DLFCN)
672 (void)lhandle;
673 return dlerror();
674#elif defined(ROAR_TARGET_WIN32)
675 roar_err_from_errno();
676 return roar_error2str(roar_error);
677#else
678 return NULL;
679#endif
680}
681
682struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
683 if ( (void*)lhandle < (void*)128 ) {
684  roar_err_set(ROAR_ERROR_NOTSUP);
685  return NULL;
686 }
687
688 if ( lhandle->para == NULL ) {
689  roar_err_set(ROAR_ERROR_NOENT);
690  return NULL;
691 }
692
693 if ( roar_dl_para_ref(lhandle->para) == -1 )
694  return NULL;
695
696 return lhandle->para;
697}
698
699const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
700 if ( (void*)lhandle < (void*)128 ) {
701  roar_err_set(ROAR_ERROR_NOTSUP);
702  return NULL;
703 }
704
705 if ( lhandle->lib == NULL ) {
706  roar_err_set(ROAR_ERROR_BADLIB);
707  return NULL;
708 }
709
710 if ( lhandle->lib->libname == NULL ) {
711  roar_err_set(ROAR_ERROR_NOENT);
712  return NULL;
713 }
714
715 if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
716  roar_err_set(ROAR_ERROR_BADVERSION);
717  return NULL;
718 }
719
720 if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
721  roar_err_set(ROAR_ERROR_HOLE);
722  return NULL;
723 }
724
725 return lhandle->lib->libname;
726}
727
728int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
729 struct roar_error_state error_state;
730
731 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = ?", lhandle);
732
733 if ( (void*)lhandle < (void*)128 ) {
734  ROAR_DBG("roar_dl_context_restore(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
735  roar_err_set(ROAR_ERROR_NOTSUP);
736  return -1;
737 }
738
739 roar_err_store(&error_state);
740 roar_err_restore(&(lhandle->context.error_state));
741 lhandle->context.error_state = error_state;
742
743 if ( lhandle->lib->global_data_pointer != NULL ) {
744  ROAR_DBG("roar_dl_context_restore(lhandle=%p): gptr(%p): %p -> %p", lhandle,
745           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data);
746  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
747  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
748 }
749
750 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL )
751  lhandle->context.notifycore = roar_notify_core_swap_global(lhandle->para->notifycore);
752
753 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = 0", lhandle);
754 return 0;
755}
756
757int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
758 struct roar_error_state error_state;
759
760 ROAR_DBG("roar_dl_context_store(lhandle=%p) = ?", lhandle);
761
762 if ( (void*)lhandle < (void*)128 ) {
763  ROAR_DBG("roar_dl_context_store(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
764  roar_err_set(ROAR_ERROR_NOTSUP);
765  return -1;
766 }
767
768 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL ) {
769  roar_notify_core_unref(roar_notify_core_swap_global(lhandle->context.notifycore));
770  roar_notify_core_unref(lhandle->context.notifycore);
771  lhandle->context.notifycore = NULL;
772 }
773
774 if ( lhandle->lib->global_data_pointer != NULL ) {
775  ROAR_DBG("roar_dl_context_store(lhandle=%p): gptr(%p): %p -> %p", lhandle,
776           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data_state);
777  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data_state;
778 }
779
780 roar_err_store(&error_state);
781 roar_err_restore(&(lhandle->context.error_state));
782 lhandle->context.error_state = error_state;
783
784 ROAR_DBG("roar_dl_context_store(lhandle=%p) = 0", lhandle);
785 return 0;
786}
787
788int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger) {
789 int (*func)  (struct roar_dl_librarypara * para) = NULL;
790 int ret;
791
792 if ( (void*)lhandle < (void*)128 ) {
793  roar_err_set(ROAR_ERROR_NOTSUP);
794  return -1;
795 }
796
797 if ( lhandle->lib == NULL ) {
798  roar_err_set(ROAR_ERROR_TYPEMM);
799  return -1;
800 }
801
802 if ( lhandle->lib->appsched == NULL ) {
803  roar_err_set(ROAR_ERROR_NOENT);
804  return -1;
805 }
806
807 switch (trigger) {
808#define _trig(lname,uname) \
809  case ROAR_DL_APPSCHED_ ## uname :             \
810    func = lhandle->lib->appsched->lname;       \
811   break;
812  _trig(init, INIT);
813  _trig(free, FREE);
814  _trig(update, UPDATE);
815  _trig(tick, TICK);
816  _trig(wait, WAIT);
817// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
818#ifndef DEBUG
819  default:
820    roar_err_set(ROAR_ERROR_BADRQC);
821    return -1;
822   break;
823#endif
824 }
825
826 if ( func == NULL ) {
827  if ( trigger == ROAR_DL_APPSCHED_INIT ) {
828   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
829   lhandle->runtime_flags -= RTF_APPSCHED_FREED;
830  } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
831   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
832   lhandle->runtime_flags -= RTF_APPSCHED_INITED;
833  }
834  roar_err_set(ROAR_ERROR_NOENT);
835  return -1;
836 }
837
838 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
839  if ( lhandle->runtime_flags & RTF_APPSCHED_INITED ) {
840   roar_err_set(ROAR_ERROR_BUSY);
841   return -1;
842  }
843 } else {
844  if ( !(lhandle->runtime_flags & RTF_APPSCHED_INITED) ) {
845   roar_err_set(ROAR_ERROR_BUSY);
846   return -1;
847  }
848 }
849
850 roar_dl_context_restore(lhandle);
851 ret = func(lhandle->para);
852 roar_dl_context_store(lhandle);
853
854 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
855  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
856  lhandle->runtime_flags -= RTF_APPSCHED_FREED;
857 } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
858  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
859  lhandle->runtime_flags -= RTF_APPSCHED_INITED;
860 }
861
862 return ret;
863}
864
865
866#define __MAX_FNREGS 24
867static struct __fnregs {
868 struct roar_dl_lhandle * lhandle;
869 int subtype;
870 const void * object;
871 size_t objectlen;
872 int version;
873 int options;
874} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
875
876static int  __fnreg_check_trigger(const struct __fnregs * handle) {
877 if ( handle->subtype != ROAR_DL_FNREG_SUBTYPE )
878  return -1;
879 if ( handle->version != ROAR_DL_FNREG_VERSION )
880  return -1;
881 if ( handle->objectlen != ROAR_DL_FNREG_SIZE )
882  return -1;
883
884 return 0;
885}
886
887static void __fnreg_trigger_if_match(const struct roar_dl_fnreg * callback,
888                                     const struct __fnregs * reg,
889                                     int fn,
890                                     enum roar_dl_fnreg_action action) {
891 if ( callback->fn != -1 && callback->fn != fn )
892  return;
893 if ( callback->subtype != -1 && callback->subtype != reg->subtype )
894  return;
895 if ( callback->version != -1 && callback->version != reg->version )
896  return;
897
898 if ( callback->callback == NULL )
899  return;
900
901 callback->callback(action, fn, reg->subtype, reg->object, reg->objectlen, reg->version, reg->options, callback->userdata, reg->lhandle);
902}
903
904static void __fnreg_trigger_by_reg(const struct __fnregs * reg, enum roar_dl_fnreg_action action, int fn) {
905 size_t j;
906
907 for (j = 0; j < __MAX_FNREGS; j++) {
908  if ( __fnrefs[ROAR_DL_FN_REGFN][j].lhandle != NULL ) {
909   if ( __fnreg_check_trigger(&(__fnrefs[ROAR_DL_FN_REGFN][j])) == -1 )
910    continue;
911   __fnreg_trigger_if_match(__fnrefs[ROAR_DL_FN_REGFN][j].object, reg, fn, action);
912  }
913 }
914}
915
916static void __fnreg_trigger_by_handler(const struct __fnregs * handle, enum roar_dl_fnreg_action action) {
917 size_t i, j;
918
919 if ( __fnreg_check_trigger(handle) == -1 )
920  return;
921
922 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
923  for (j = 0; j < __MAX_FNREGS; j++) {
924   if ( __fnrefs[i][j].lhandle != NULL ) {
925    __fnreg_trigger_if_match(handle->object, &(__fnrefs[i][j]), i, action);
926   }
927  }
928 }
929}
930
931int roar_dl_register_fn(struct roar_dl_lhandle * lhandle, int fn, int subtype, const void * object, size_t objectlen, int version, int options) {
932 struct __fnregs * c = NULL;
933 size_t i;
934
935 if ( lhandle == NULL )
936  lhandle = __currently_inited;
937
938 if ( fn == -1 )
939  fn = __currently_inited_fn;
940
941 if ( lhandle == NULL ) {
942  roar_err_set(ROAR_ERROR_FAULT);
943  return -1;
944 }
945
946 if ( fn < 0 || fn >= ROAR_DL_FN_MAX ) {
947  roar_err_set(ROAR_ERROR_RANGE);
948  return -1;
949 }
950
951 if ( object == NULL || objectlen == 0 ) {
952  roar_err_set(ROAR_ERROR_INVAL);
953  return -1;
954 }
955
956 for (i = 0; i < __MAX_FNREGS; i++) {
957  if ( __fnrefs[fn][i].lhandle != NULL )
958   continue;
959  c = &(__fnrefs[fn][i]);
960  break;
961 }
962
963 if ( c == NULL ) {
964  roar_err_set(ROAR_ERROR_NOSPC);
965  return -1;
966 }
967
968 c->lhandle   = lhandle;
969 c->subtype   = subtype;
970 c->object    = object;
971 c->objectlen = objectlen;
972 c->version   = version;
973
974 if ( fn == ROAR_DL_FN_REGFN ) {
975  __fnreg_trigger_by_handler(c, ROAR_DL_FNREG);
976 } else {
977  __fnreg_trigger_by_reg(c, ROAR_DL_FNREG, fn);
978 }
979
980 return 0;
981}
982
983int                      roar_dl_unregister_fn2(struct roar_dl_lhandle * lhandle, int fn, int subtype, const void * object, size_t objectlen, int version, int options) {
984 struct __fnregs * c = NULL;
985 size_t i, j;
986
987 if ( lhandle == NULL ) {
988  roar_err_set(ROAR_ERROR_FAULT);
989  return -1;
990 }
991
992 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
993  if ( fn != -1 && fn != i )
994   continue;
995
996  for (j = 0; j < __MAX_FNREGS; j++) {
997   c = &(__fnrefs[i][j]);
998
999   if ( c->lhandle != lhandle )
1000    continue;
1001
1002   if ( subtype != -1 && subtype != c->subtype )
1003    continue;
1004   if ( object != NULL && object != c->object )
1005    continue;
1006   if ( objectlen != (size_t)-1 && objectlen != c->objectlen )
1007    continue;
1008   if ( version != -1 && version != c->version )
1009    continue;
1010   if ( options != -1 && options != c->options )
1011    continue;
1012
1013   if ( i == ROAR_DL_FN_REGFN ) {
1014    __fnreg_trigger_by_handler(&(__fnrefs[i][j]), ROAR_DL_FNUNREG);
1015   } else {
1016    __fnreg_trigger_by_reg(&(__fnrefs[i][j]), ROAR_DL_FNUNREG, i);
1017   }
1018   memset(&(__fnrefs[i][j]), 0, sizeof(__fnrefs[i][j]));
1019   __fnrefs[i][j].lhandle = NULL;
1020  }
1021 }
1022
1023 return 0;
1024}
1025
1026int roar_dl_unregister_fn(struct roar_dl_lhandle * lhandle) {
1027 return roar_dl_unregister_fn2(lhandle, -1, -1, NULL, (size_t)-1, -1, -1);
1028}
1029
1030int libroar_dl_service_get_api_real(struct roar_dl_librarypara * para, const char * appname, const char * appabi, const char * servicename, const char * serviceabi, int universal, struct roar_dl_service_api * api) {
1031 const struct roar_dl_service * s;
1032 struct __fnregs * c = NULL;
1033 size_t i;
1034 int err;
1035
1036 if ( para == NULL || servicename == NULL || serviceabi == NULL || api == NULL ) {
1037  roar_err_set(ROAR_ERROR_FAULT);
1038  return -1;
1039 }
1040
1041 memset(api, 0, sizeof(struct roar_dl_service_api));
1042
1043 for (i = 0; i < __MAX_FNREGS; i++) {
1044  c = &(__fnrefs[ROAR_DL_FN_SERVICE][i]);
1045  s = c->object;
1046
1047  if ( c->lhandle == NULL )
1048   continue;
1049
1050  if ( c->subtype != ROAR_DL_SERVICE_SUBTYPE )
1051   continue;
1052  if ( c->objectlen != ROAR_DL_SERVICE_SIZE )
1053   continue;
1054  if ( c->version != ROAR_DL_SERVICE_VERSION )
1055   continue;
1056
1057  if ( !universal && s->appname == NULL )
1058   continue;
1059  if ( s->appname != NULL && !!strcmp(s->appname, appname) )
1060   continue;
1061  if ( (s->appabi == NULL && appabi != NULL) || (s->appabi != NULL && appabi == NULL) ||
1062       (s->appabi != NULL && appabi != NULL && !!strcmp(s->appabi, appabi) ) )
1063   continue;
1064  if ( s->servicename == NULL || !!strcmp(s->servicename, servicename) )
1065   continue;
1066  if ( s->serviceabi == NULL || !!strcmp(s->serviceabi, serviceabi) )
1067   continue;
1068
1069  if ( s->get_api == NULL )
1070   continue;
1071
1072  if ( roar_dl_ref(c->lhandle) != 0 )
1073   continue;
1074
1075  api->lhandle = c->lhandle;
1076
1077  api->api = s->get_api(s, para);
1078  if ( api->api == NULL ) {
1079   err = roar_error;
1080   roar_dl_unref(c->lhandle);
1081   api->lhandle = NULL;
1082   roar_error = err;
1083   return -1;
1084  }
1085
1086  return 0;
1087 }
1088
1089 roar_err_set(ROAR_ERROR_NOENT);
1090 return -1;
1091}
1092
1093int libroar_dl_service_free_api_real(struct roar_dl_service_api * api) {
1094 if ( api == NULL ) {
1095  roar_err_set(ROAR_ERROR_FAULT);
1096  return -1;
1097 }
1098
1099 roar_dl_unref(api->lhandle);
1100
1101 memset(api, 0, sizeof(struct roar_dl_service_api));
1102
1103 return 0;
1104}
1105
1106//ll
Note: See TracBrowser for help on using the repository browser.