source: roaraudio/libroar/roardl.c @ 5818:993d96fc5e9c

Last change on this file since 5818:993d96fc5e9c was 5818:993d96fc5e9c, checked in by phi, 11 years ago

also return pointer to service

File size: 29.4 KB
RevLine 
[3297]1//roardl.c:
2
3/*
[5381]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2012
[3297]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
[3517]21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
[3297]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
[5427]38#ifdef ROAR_HAVE_H_DIRENT
39#include <dirent.h>
40#endif
41
[5517]42#if defined(ROAR_HAVE_H_DLFCN) && !defined(RTLD_NEXT)
[3367]43#define RTLD_NEXT ((void *) -1L)
44#endif
45
[5503]46#define RTF_RA_INITED       0x0001
47#define RTF_APPSCHED_INITED 0x0002
48#define RTF_APPSCHED_FREED  0x0004
49
[5275]50struct roar_dl_lhandle {
[5317]51 size_t refc; // currently unused.
52 int flags;
53 char * libname; // only used for ROAR_DL_FLAG_STATIC.
[5275]54 struct roar_dl_librarypara * para;
55 struct roar_dl_libraryinst * lib;
[5312]56 struct {
57  struct roar_error_state error_state;
58  void *  global_data;
59  void *  global_data_state;
[5317]60  struct roar_notify_core * notifycore;
[5312]61 } context;
[5503]62 unsigned int runtime_flags;
[5517]63#if defined(ROAR_HAVE_H_DLFCN)
[5275]64 void * handle;
[5481]65#elif defined(ROAR_TARGET_WIN32)
66 HMODULE handle;
[5275]67#endif
68};
69
[5511]70// TODO: this should be removed on next SONAME change.
[5514]71static struct roar_dl_lhandle * __currently_inited    = NULL;
72static int                      __currently_inited_fn = -1;
[5275]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
[5482]104  argc = roar_keyval_split(&(ret->argv), ret->args_store, NULL, NULL, 1);
[5275]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 ) {
[5438]121  ROAR_DBG("roar_dl_para_ref(para=%p) = -1 // error=FAULT", para);
[5275]122  roar_err_set(ROAR_ERROR_FAULT);
123  return -1;
124 }
125
126 para->refc++;
127
[5438]128 ROAR_DBG("roar_dl_para_ref(para=%p) = 0", para);
[5275]129 return 0;
130}
131
132int roar_dl_para_unref                  (struct roar_dl_librarypara * para) {
133 if ( para == NULL ) {
[5438]134  ROAR_DBG("roar_dl_para_unref(para=%p) = -1 // error=FAULT", para);
[5275]135  roar_err_set(ROAR_ERROR_FAULT);
136  return -1;
137 }
138
139 para->refc--;
140
[5438]141 if ( para->refc ) {
142  ROAR_DBG("roar_dl_para_unref(para=%p) = 0", para);
[5317]143  return 0;
[5438]144 }
[5317]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);
[5275]152 }
153
[5317]154 roar_mm_free(para);
155
[5438]156 ROAR_DBG("roar_dl_para_unref(para=%p) = 0", para);
[5275]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) ) {
[5371]168  roar_err_set(ROAR_ERROR_BADHOST);
[5275]169  return -1;
170 }
171
172 // check if the appname matches if given.
173 if ( para->appname != NULL && !!strcmp(para->appname, appname) ) {
[5371]174  roar_err_set(ROAR_ERROR_BADHOST);
[5275]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
[5517]194#if defined(ROAR_HAVE_H_DLFCN)
[3297]195static void * _roardl2ldl (struct roar_dl_lhandle * lhandle) {
[5317]196 ROAR_DBG("_roardl2ldl(lhandle=%p) = ?", lhandle);
197
[5511]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  }
[5317]211 }
[3297]212
[5317]213 ROAR_DBG("_roardl2ldl(lhandle=%p) = %p", lhandle, (void*)(lhandle->handle));
[3297]214 return lhandle->handle;
215}
[5481]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}
[3297]223#endif
224
[5427]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;
[5688]278 size_t hostvendor_len;
[5427]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 {
[5688]305     hostvendor_len = roar_mm_strlen(c) + 1 /* tailing \0 */ + 6 /* "unreg-" */;
306     hostvendor_buffer = roar_mm_malloc(hostvendor_len);
[5427]307
308     // see above
309     if ( hostvendor_buffer == NULL ) {
310      roar_mm_free(host);
311      return NULL;
312     }
313
[5688]314     roar_mm_strlcpy(hostvendor_buffer, "unreg-", hostvendor_len);
315     roar_mm_strlcat(hostvendor_buffer, c, hostvendor_len);
[5427]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
[5430]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
[5427]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
[5275]355struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags,
356                                      int ra_init, struct roar_dl_librarypara * para) {
[3298]357 struct roar_dl_lhandle * ret = NULL;
[5517]358#if defined(ROAR_HAVE_H_DLFCN)
[5317]359#ifdef RTLD_DEEPBIND
[5344]360 int libdl_flags = RTLD_DEEPBIND;
[5317]361#else
[5344]362 int libdl_flags = 0;
[5317]363#endif
364#endif
[5275]365 int err;
[3298]366
[5427]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);
[3304]374
[5517]375#if defined(ROAR_HAVE_H_DLFCN)
[5344]376 if ( flags & ROAR_DL_FLAG_LAZY ) {
377  libdl_flags |= RTLD_LAZY;
378 } else {
379  libdl_flags |= RTLD_NOW;
380 }
381#endif
382
[3304]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
[5312]388 roar_err_initstore(&(ret->context.error_state));
389
[5317]390 ret->flags = flags;
[5321]391 ret->refc  = 1;
[3366]392
[5317]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 {
[5517]400#if defined(ROAR_HAVE_H_DLFCN)
[5317]401  ret->handle = dlopen(filename, libdl_flags);
[3304]402
[5317]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  }
[5481]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  }
[3304]415#else
[5317]416  roar_mm_free(ret);
417  roar_err_set(ROAR_ERROR_NOSYS);
418  return NULL;
[3304]419#endif
[5317]420 }
[3304]421
[5275]422 ret->para = para;
[3298]423
424 if ( ra_init ) {
[5275]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));
[5517]428#if defined(ROAR_HAVE_H_DLFCN)
[5317]429   if ( ret->handle != NULL )
430    dlclose(ret->handle);
[5481]431#elif defined(ROAR_TARGET_WIN32)
432   if ( ret->handle != NULL )
433    FreeLibrary(ret->handle);
[5275]434#endif
435   roar_mm_free(ret);
436   roar_error = err;
437   return NULL;
438  }
[3298]439 }
440
[5275]441 if ( para != NULL )
442  roar_dl_para_ref(para);
443
[3298]444 return ret;
[3297]445}
446
[5321]447int                      roar_dl_ref    (struct roar_dl_lhandle * lhandle) {
448 if ( (void*)lhandle < (void*)128 ) {
[5438]449  ROAR_DBG("roar_dl_ref(lhandle=%p) = -1 // error=BADFH", lhandle);
[5275]450  roar_err_set(ROAR_ERROR_BADFH);
[3301]451  return -1;
[5275]452 }
[3301]453
[5321]454 lhandle->refc++;
455
[5438]456 ROAR_DBG("roar_dl_ref(lhandle=%p) = 0", lhandle);
[5321]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 ) {
[5438]464  ROAR_DBG("roar_dl_unref(lhandle=%p) = -1 // error=BADFH", lhandle);
[5321]465  roar_err_set(ROAR_ERROR_BADFH);
466  return -1;
467 }
468
[5438]469 lhandle->refc--;
[5321]470
[5438]471 if ( lhandle->refc ) {
472  ROAR_DBG("roar_dl_unref(lhandle=%p) = 0", lhandle);
[5321]473  return 0;
[5438]474 }
[5321]475
[5511]476 roar_dl_unregister_fn(lhandle);
477
[5317]478 if ( lhandle->lib != NULL && lhandle->lib->unload != NULL ) {
479  roar_dl_context_restore(lhandle);
[3301]480  lhandle->lib->unload(lhandle->para, lhandle->lib);
[5317]481  roar_dl_context_store(lhandle);
482 }
[3301]483
[5517]484#if defined(ROAR_HAVE_H_DLFCN)
[5317]485 if ( lhandle->handle == NULL ) {
486  ret = 0;
487 } else {
488  ret = dlclose(_roardl2ldl(lhandle));
489 }
[5481]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 }
[3297]500#else
[3304]501 ret = -1;
[3297]502#endif
[3304]503
[5312]504 if ( lhandle->context.global_data != NULL )
505  roar_mm_free(lhandle->context.global_data);
506
[5275]507 if ( lhandle->para != NULL )
508  roar_dl_para_unref(lhandle->para);
509
[5317]510 if ( lhandle->libname != NULL )
511  roar_mm_free(lhandle->libname);
512
[3304]513 roar_mm_free(lhandle);
514
[5438]515 ROAR_DBG("roar_dl_unref(lhandle=%p) = %i", lhandle, ret);
[3304]516 return ret;
[3297]517}
518
519void                   * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type) {
[5517]520#if defined(ROAR_HAVE_H_DLFCN)
[3776]521 void * ret = dlsym(_roardl2ldl(lhandle), sym);
522
[5270]523 (void)type;
524
[5651]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());
[3776]526 ROAR_DBG("roar_dl_getsym(lhandle=%p, sym='%s', type=%i) = %p", lhandle, sym, type, ret);
527
528 return ret;
[5481]529#elif defined(ROAR_TARGET_WIN32)
530 FARPROC ret = GetProcAddress(_roardl2winhandle(lhandle), sym);
531 return (void*)ret;
[3297]532#else
[5317]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);
[3297]535 return NULL;
536#endif
537}
538
[5275]539int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
540                                         const char * prefix,
541                                         struct roar_dl_librarypara * para) {
[5511]542 struct roar_dl_lhandle * old_init;
[5514]543 int old_fn;
[3297]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;
[5317]548 struct roar_dl_lhandle     * getsymhandle = lhandle;
[5312]549 void * global_data_state = NULL;
[3300]550 int i;
[3297]551
[3305]552 if ( (void*)lhandle < (void*)128 ) {
553  if ( prefix == NULL )
554   return -1;
555 } else {
[5503]556  if ( lhandle->runtime_flags & RTF_RA_INITED )
[5431]557   return 0;
558
[5317]559  if ( prefix == NULL )
560   prefix = lhandle->libname;
561
[5275]562  if ( para == NULL )
563   para = lhandle->para;
[5317]564
565  if ( lhandle->flags & ROAR_DL_FLAG_STATIC )
566   getsymhandle = ROAR_DL_HANDLE_DEFAULT;
[3305]567 }
568
[3297]569
570 if ( prefix != NULL ) {
[5008]571  roar_mm_strscpy(name, "_");
572  roar_mm_strscat(name, prefix);
573  roar_mm_strscat(name, _SUFFIX);
[3297]574 }
575
[3307]576 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): name='%s'", lhandle, prefix, name);
577
[5317]578 if ( (func = roar_dl_getsym(getsymhandle, name, -1)) == NULL ) {
579  ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s') = -1", lhandle, prefix);
[3297]580  return -1;
[5317]581 }
[3297]582
[3307]583 ROAR_DBG("roar_dl_ra_init(lhandle=%p, prefix='%s'): func=%p", lhandle, prefix, func);
584
[5512]585 roar_err_set(ROAR_ERROR_BADLIB); // set a default error in case it returns NULL but not set an error code.
[3300]586 lib = func(para);
[3297]587
588 if ( lib == NULL )
589  return -1;
590
[3300]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
[5353]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
[5347]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
[3361]618 if ( !((void*)lhandle < (void*)128) ) {
619  lhandle->lib = lib;
[5312]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);
[5313]636  if ( (void*)lhandle < (void*)128 ) {
[5312]637   *(lib->global_data_pointer) = lib->global_data_init;
638  } else {
639   *(lib->global_data_pointer) = lhandle->context.global_data;
640  }
[3361]641 }
642
[5761]643 roar_dl_context_restore(lhandle);
644
[5511]645 old_init = __currently_inited;
[5514]646 old_fn   = __currently_inited_fn;
[5511]647 __currently_inited = lhandle;
[3300]648 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
[5514]649  __currently_inited_fn = i;
[3300]650  if ( lib->func[i] != NULL )
651   lib->func[i](para, lib);
652 }
[5514]653 __currently_inited_fn = old_fn;
[5511]654 __currently_inited = old_init;
655
[5761]656 roar_dl_context_store(lhandle);
[3300]657
[5312]658 if ( lib->global_data_pointer != NULL ) {
[5313]659  if ( !((void*)lhandle < (void*)128) ) {
660   *(lib->global_data_pointer) = global_data_state;
661  }
[5312]662 }
663
[5431]664 if ( !((void*)lhandle < (void*)128) )
[5503]665  lhandle->runtime_flags |= RTF_RA_INITED;
[5431]666
[3302]667 return 0;
[3297]668}
669
[5275]670const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
[5517]671#if defined(ROAR_HAVE_H_DLFCN)
[5270]672 (void)lhandle;
[3364]673 return dlerror();
[5481]674#elif defined(ROAR_TARGET_WIN32)
675 roar_err_from_errno();
676 return roar_error2str(roar_error);
[3364]677#else
678 return NULL;
679#endif
680}
681
[5275]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
[5312]728int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
729 struct roar_error_state error_state;
730
[5317]731 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = ?", lhandle);
732
[5312]733 if ( (void*)lhandle < (void*)128 ) {
[5317]734  ROAR_DBG("roar_dl_context_restore(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
[5312]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 ) {
[5317]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);
[5312]746  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
747  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
748 }
749
[5583]750 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL )
[5317]751  lhandle->context.notifycore = roar_notify_core_swap_global(lhandle->para->notifycore);
752
753 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = 0", lhandle);
[5312]754 return 0;
755}
756
757int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
758 struct roar_error_state error_state;
759
[5317]760 ROAR_DBG("roar_dl_context_store(lhandle=%p) = ?", lhandle);
761
[5312]762 if ( (void*)lhandle < (void*)128 ) {
[5317]763  ROAR_DBG("roar_dl_context_store(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
[5312]764  roar_err_set(ROAR_ERROR_NOTSUP);
765  return -1;
766 }
767
[5583]768 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL ) {
[5317]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
[5312]774 if ( lhandle->lib->global_data_pointer != NULL ) {
[5317]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);
[5312]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
[5317]784 ROAR_DBG("roar_dl_context_store(lhandle=%p) = 0", lhandle);
[5312]785 return 0;
786}
787
[5317]788int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger) {
[5335]789 int (*func)  (struct roar_dl_librarypara * para) = NULL;
[5317]790 int ret;
791
792 if ( (void*)lhandle < (void*)128 ) {
793  roar_err_set(ROAR_ERROR_NOTSUP);
794  return -1;
795 }
796
[5446]797 if ( lhandle->lib == NULL ) {
798  roar_err_set(ROAR_ERROR_TYPEMM);
799  return -1;
800 }
801
[5317]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 :             \
[5335]810    func = lhandle->lib->appsched->lname;       \
[5317]811   break;
812  _trig(init, INIT);
813  _trig(free, FREE);
814  _trig(update, UPDATE);
[5335]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
[5317]824 }
825
[5335]826 if ( func == NULL ) {
[5503]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  }
[5335]834  roar_err_set(ROAR_ERROR_NOENT);
835  return -1;
836 }
837
[5503]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
[5335]850 roar_dl_context_restore(lhandle);
851 ret = func(lhandle->para);
852 roar_dl_context_store(lhandle);
[5503]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
[5335]862 return ret;
[5317]863}
864
[5511]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
[5514]938 if ( fn == -1 )
939  fn = __currently_inited_fn;
940
[5511]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
[5770]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;
[5511]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++) {
[5770]993  if ( fn != -1 && fn != i )
994   continue;
995
[5511]996  for (j = 0; j < __MAX_FNREGS; j++) {
[5770]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);
[5511]1017   }
[5770]1018   memset(&(__fnrefs[i][j]), 0, sizeof(__fnrefs[i][j]));
1019   __fnrefs[i][j].lhandle = NULL;
[5511]1020  }
1021 }
1022
1023 return 0;
1024}
1025
[5770]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
[5816]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) {
[5814]1031 const struct roar_dl_service * s;
1032 struct __fnregs * c = NULL;
1033 size_t i;
[5816]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));
[5814]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;
[5817]1059  if ( universal == 2 && s->appname != NULL )
1060   continue;
[5814]1061  if ( s->appname != NULL && !!strcmp(s->appname, appname) )
1062   continue;
1063  if ( (s->appabi == NULL && appabi != NULL) || (s->appabi != NULL && appabi == NULL) ||
1064       (s->appabi != NULL && appabi != NULL && !!strcmp(s->appabi, appabi) ) )
1065   continue;
1066  if ( s->servicename == NULL || !!strcmp(s->servicename, servicename) )
1067   continue;
1068  if ( s->serviceabi == NULL || !!strcmp(s->serviceabi, serviceabi) )
1069   continue;
1070
1071  if ( s->get_api == NULL )
1072   continue;
1073
[5816]1074  if ( roar_dl_ref(c->lhandle) != 0 )
1075   continue;
1076
[5818]1077  api->service = s;
[5816]1078  api->lhandle = c->lhandle;
1079
1080  api->api = s->get_api(s, para);
1081  if ( api->api == NULL ) {
1082   err = roar_error;
1083   roar_dl_unref(c->lhandle);
1084   api->lhandle = NULL;
1085   roar_error = err;
1086   return -1;
[5815]1087  }
1088
[5816]1089  return 0;
[5814]1090 }
1091
1092 roar_err_set(ROAR_ERROR_NOENT);
[5816]1093 return -1;
1094}
1095
1096int libroar_dl_service_free_api_real(struct roar_dl_service_api * api) {
1097 if ( api == NULL ) {
1098  roar_err_set(ROAR_ERROR_FAULT);
1099  return -1;
1100 }
1101
1102 roar_dl_unref(api->lhandle);
1103
1104 memset(api, 0, sizeof(struct roar_dl_service_api));
1105
1106 return 0;
[5814]1107}
1108
[3297]1109//ll
Note: See TracBrowser for help on using the repository browser.