source: roaraudio/libroar/roardl.c @ 5512:71b49441933f

Last change on this file since 5512:71b49441933f was 5512:71b49441933f, checked in by phi, 12 years ago

avoid the need for linking plugins against libroar

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