source: roaraudio/libroar/roardl.c @ 5695:dd52b51afdfb

Last change on this file since 5695:dd52b51afdfb was 5688:c7e8e3a700ec, checked in by phi, 12 years ago

avoid a warning on OpenBSD

File size: 26.8 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
[5511]643 old_init = __currently_inited;
[5514]644 old_fn   = __currently_inited_fn;
[5511]645 __currently_inited = lhandle;
[3300]646 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
[5514]647  __currently_inited_fn = i;
[3300]648  if ( lib->func[i] != NULL )
649   lib->func[i](para, lib);
650 }
[5514]651 __currently_inited_fn = old_fn;
[5511]652 __currently_inited = old_init;
653
[3300]654
[5312]655 if ( lib->global_data_pointer != NULL ) {
[5313]656  if ( !((void*)lhandle < (void*)128) ) {
657   *(lib->global_data_pointer) = global_data_state;
658  }
[5312]659 }
660
[5431]661 if ( !((void*)lhandle < (void*)128) )
[5503]662  lhandle->runtime_flags |= RTF_RA_INITED;
[5431]663
[3302]664 return 0;
[3297]665}
666
[5275]667const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
[5517]668#if defined(ROAR_HAVE_H_DLFCN)
[5270]669 (void)lhandle;
[3364]670 return dlerror();
[5481]671#elif defined(ROAR_TARGET_WIN32)
672 roar_err_from_errno();
673 return roar_error2str(roar_error);
[3364]674#else
675 return NULL;
676#endif
677}
678
[5275]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
[5312]725int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
726 struct roar_error_state error_state;
727
[5317]728 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = ?", lhandle);
729
[5312]730 if ( (void*)lhandle < (void*)128 ) {
[5317]731  ROAR_DBG("roar_dl_context_restore(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
[5312]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 ) {
[5317]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);
[5312]743  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
744  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
745 }
746
[5583]747 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL )
[5317]748  lhandle->context.notifycore = roar_notify_core_swap_global(lhandle->para->notifycore);
749
750 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = 0", lhandle);
[5312]751 return 0;
752}
753
754int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
755 struct roar_error_state error_state;
756
[5317]757 ROAR_DBG("roar_dl_context_store(lhandle=%p) = ?", lhandle);
758
[5312]759 if ( (void*)lhandle < (void*)128 ) {
[5317]760  ROAR_DBG("roar_dl_context_store(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
[5312]761  roar_err_set(ROAR_ERROR_NOTSUP);
762  return -1;
763 }
764
[5583]765 if ( lhandle->para != NULL && lhandle->para->notifycore != NULL ) {
[5317]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
[5312]771 if ( lhandle->lib->global_data_pointer != NULL ) {
[5317]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);
[5312]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
[5317]781 ROAR_DBG("roar_dl_context_store(lhandle=%p) = 0", lhandle);
[5312]782 return 0;
783}
784
[5317]785int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger) {
[5335]786 int (*func)  (struct roar_dl_librarypara * para) = NULL;
[5317]787 int ret;
788
789 if ( (void*)lhandle < (void*)128 ) {
790  roar_err_set(ROAR_ERROR_NOTSUP);
791  return -1;
792 }
793
[5446]794 if ( lhandle->lib == NULL ) {
795  roar_err_set(ROAR_ERROR_TYPEMM);
796  return -1;
797 }
798
[5317]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 :             \
[5335]807    func = lhandle->lib->appsched->lname;       \
[5317]808   break;
809  _trig(init, INIT);
810  _trig(free, FREE);
811  _trig(update, UPDATE);
[5335]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
[5317]821 }
822
[5335]823 if ( func == NULL ) {
[5503]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  }
[5335]831  roar_err_set(ROAR_ERROR_NOENT);
832  return -1;
833 }
834
[5503]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
[5335]847 roar_dl_context_restore(lhandle);
848 ret = func(lhandle->para);
849 roar_dl_context_store(lhandle);
[5503]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
[5335]859 return ret;
[5317]860}
861
[5511]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
[5514]935 if ( fn == -1 )
936  fn = __currently_inited_fn;
937
[5511]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
[3297]1007//ll
Note: See TracBrowser for help on using the repository browser.