source: roaraudio/libroar/roardl.c @ 5511:e2207bedaf0e

Last change on this file since 5511:e2207bedaf0e was 5511:e2207bedaf0e, checked in by phi, 12 years ago

Added a way to register plugin parts with a universal API (Closes: #245)

File size: 26.3 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 lib = func(para);
582
583 if ( lib == NULL )
584  return -1;
585
586 if ( lib->version != ROAR_DL_LIBINST_VERSION )
587  return -1;
588
589 if ( sizeof(struct roar_dl_libraryinst) > lib->len )
590  return -1;
591
592 if ( lib->host_appname != NULL || lib->host_abiversion != NULL ) {
593  // check for correct host.
594  if ( para == NULL ) {
595   roar_err_set(ROAR_ERROR_INVAL);
596   return -1;
597  }
598  if ( roar_dl_para_check_version(para, lib->host_appname, lib->host_abiversion) == -1 )
599   return -1;
600 }
601
602 if ( (lib->libdep == NULL && lib->libdep_len) || (lib->libdep != NULL && !lib->libdep_len) ) {
603  roar_err_set(ROAR_ERROR_BADLIB);
604  return -1;
605 }
606
607 if ( lib->libdep != NULL && lib->libdep_len ) {
608  // dynamic loader infos are currently not supported.
609  roar_err_set(ROAR_ERROR_NOTSUP);
610  return -1;
611 }
612
613 if ( !((void*)lhandle < (void*)128) ) {
614  lhandle->lib = lib;
615
616  if ( lib->global_data_len ) {
617   lhandle->context.global_data = roar_mm_malloc(lib->global_data_len);
618   if ( lhandle->context.global_data == NULL )
619    return -1;
620
621   if ( lib->global_data_init == NULL ) {
622    memset(lhandle->context.global_data, 0, lib->global_data_len);
623   } else {
624    memcpy(lhandle->context.global_data, lib->global_data_init, lib->global_data_len);
625   }
626  }
627 }
628
629 if ( lib->global_data_pointer != NULL ) {
630  global_data_state = *(lib->global_data_pointer);
631  if ( (void*)lhandle < (void*)128 ) {
632   *(lib->global_data_pointer) = lib->global_data_init;
633  } else {
634   *(lib->global_data_pointer) = lhandle->context.global_data;
635  }
636 }
637
638 old_init = __currently_inited;
639 __currently_inited = lhandle;
640 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
641  if ( lib->func[i] != NULL )
642   lib->func[i](para, lib);
643 }
644 __currently_inited = old_init;
645
646
647 if ( lib->global_data_pointer != NULL ) {
648  if ( !((void*)lhandle < (void*)128) ) {
649   *(lib->global_data_pointer) = global_data_state;
650  }
651 }
652
653 if ( !((void*)lhandle < (void*)128) )
654  lhandle->runtime_flags |= RTF_RA_INITED;
655
656 return 0;
657}
658
659const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
660#if defined(ROAR_HAVE_LIBDL)
661 (void)lhandle;
662 return dlerror();
663#elif defined(ROAR_TARGET_WIN32)
664 roar_err_from_errno();
665 return roar_error2str(roar_error);
666#else
667 return NULL;
668#endif
669}
670
671struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
672 if ( (void*)lhandle < (void*)128 ) {
673  roar_err_set(ROAR_ERROR_NOTSUP);
674  return NULL;
675 }
676
677 if ( lhandle->para == NULL ) {
678  roar_err_set(ROAR_ERROR_NOENT);
679  return NULL;
680 }
681
682 if ( roar_dl_para_ref(lhandle->para) == -1 )
683  return NULL;
684
685 return lhandle->para;
686}
687
688const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
689 if ( (void*)lhandle < (void*)128 ) {
690  roar_err_set(ROAR_ERROR_NOTSUP);
691  return NULL;
692 }
693
694 if ( lhandle->lib == NULL ) {
695  roar_err_set(ROAR_ERROR_BADLIB);
696  return NULL;
697 }
698
699 if ( lhandle->lib->libname == NULL ) {
700  roar_err_set(ROAR_ERROR_NOENT);
701  return NULL;
702 }
703
704 if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
705  roar_err_set(ROAR_ERROR_BADVERSION);
706  return NULL;
707 }
708
709 if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
710  roar_err_set(ROAR_ERROR_HOLE);
711  return NULL;
712 }
713
714 return lhandle->lib->libname;
715}
716
717int                      roar_dl_context_restore(struct roar_dl_lhandle * lhandle) {
718 struct roar_error_state error_state;
719
720 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = ?", lhandle);
721
722 if ( (void*)lhandle < (void*)128 ) {
723  ROAR_DBG("roar_dl_context_restore(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
724  roar_err_set(ROAR_ERROR_NOTSUP);
725  return -1;
726 }
727
728 roar_err_store(&error_state);
729 roar_err_restore(&(lhandle->context.error_state));
730 lhandle->context.error_state = error_state;
731
732 if ( lhandle->lib->global_data_pointer != NULL ) {
733  ROAR_DBG("roar_dl_context_restore(lhandle=%p): gptr(%p): %p -> %p", lhandle,
734           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data);
735  lhandle->context.global_data_state = *(lhandle->lib->global_data_pointer);
736  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data;
737 }
738
739 if ( lhandle->para->notifycore != NULL )
740  lhandle->context.notifycore = roar_notify_core_swap_global(lhandle->para->notifycore);
741
742 ROAR_DBG("roar_dl_context_restore(lhandle=%p) = 0", lhandle);
743 return 0;
744}
745
746int                      roar_dl_context_store(struct roar_dl_lhandle * lhandle) {
747 struct roar_error_state error_state;
748
749 ROAR_DBG("roar_dl_context_store(lhandle=%p) = ?", lhandle);
750
751 if ( (void*)lhandle < (void*)128 ) {
752  ROAR_DBG("roar_dl_context_store(lhandle=%p) = -1 // errno=NOTSUP", lhandle);
753  roar_err_set(ROAR_ERROR_NOTSUP);
754  return -1;
755 }
756
757 if ( lhandle->para->notifycore != NULL ) {
758  roar_notify_core_unref(roar_notify_core_swap_global(lhandle->context.notifycore));
759  roar_notify_core_unref(lhandle->context.notifycore);
760  lhandle->context.notifycore = NULL;
761 }
762
763 if ( lhandle->lib->global_data_pointer != NULL ) {
764  ROAR_DBG("roar_dl_context_store(lhandle=%p): gptr(%p): %p -> %p", lhandle,
765           lhandle->lib->global_data_pointer, *(lhandle->lib->global_data_pointer), lhandle->context.global_data_state);
766  *(lhandle->lib->global_data_pointer) = lhandle->context.global_data_state;
767 }
768
769 roar_err_store(&error_state);
770 roar_err_restore(&(lhandle->context.error_state));
771 lhandle->context.error_state = error_state;
772
773 ROAR_DBG("roar_dl_context_store(lhandle=%p) = 0", lhandle);
774 return 0;
775}
776
777int                      roar_dl_appsched_trigger(struct roar_dl_lhandle * lhandle, enum roar_dl_appsched_trigger trigger) {
778 int (*func)  (struct roar_dl_librarypara * para) = NULL;
779 int ret;
780
781 if ( (void*)lhandle < (void*)128 ) {
782  roar_err_set(ROAR_ERROR_NOTSUP);
783  return -1;
784 }
785
786 if ( lhandle->lib == NULL ) {
787  roar_err_set(ROAR_ERROR_TYPEMM);
788  return -1;
789 }
790
791 if ( lhandle->lib->appsched == NULL ) {
792  roar_err_set(ROAR_ERROR_NOENT);
793  return -1;
794 }
795
796 switch (trigger) {
797#define _trig(lname,uname) \
798  case ROAR_DL_APPSCHED_ ## uname :             \
799    func = lhandle->lib->appsched->lname;       \
800   break;
801  _trig(init, INIT);
802  _trig(free, FREE);
803  _trig(update, UPDATE);
804  _trig(tick, TICK);
805  _trig(wait, WAIT);
806// use ifndef here so warnings of unhandled enum values will be shown in DEBUG mode.
807#ifndef DEBUG
808  default:
809    roar_err_set(ROAR_ERROR_BADRQC);
810    return -1;
811   break;
812#endif
813 }
814
815 if ( func == NULL ) {
816  if ( trigger == ROAR_DL_APPSCHED_INIT ) {
817   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
818   lhandle->runtime_flags -= RTF_APPSCHED_FREED;
819  } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
820   lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
821   lhandle->runtime_flags -= RTF_APPSCHED_INITED;
822  }
823  roar_err_set(ROAR_ERROR_NOENT);
824  return -1;
825 }
826
827 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
828  if ( lhandle->runtime_flags & RTF_APPSCHED_INITED ) {
829   roar_err_set(ROAR_ERROR_BUSY);
830   return -1;
831  }
832 } else {
833  if ( !(lhandle->runtime_flags & RTF_APPSCHED_INITED) ) {
834   roar_err_set(ROAR_ERROR_BUSY);
835   return -1;
836  }
837 }
838
839 roar_dl_context_restore(lhandle);
840 ret = func(lhandle->para);
841 roar_dl_context_store(lhandle);
842
843 if ( trigger == ROAR_DL_APPSCHED_INIT ) {
844  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
845  lhandle->runtime_flags -= RTF_APPSCHED_FREED;
846 } else if ( trigger == ROAR_DL_APPSCHED_FREE ) {
847  lhandle->runtime_flags |= RTF_APPSCHED_INITED|RTF_APPSCHED_FREED;
848  lhandle->runtime_flags -= RTF_APPSCHED_INITED;
849 }
850
851 return ret;
852}
853
854
855#define __MAX_FNREGS 24
856static struct __fnregs {
857 struct roar_dl_lhandle * lhandle;
858 int subtype;
859 const void * object;
860 size_t objectlen;
861 int version;
862 int options;
863} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
864
865static int  __fnreg_check_trigger(const struct __fnregs * handle) {
866 if ( handle->subtype != ROAR_DL_FNREG_SUBTYPE )
867  return -1;
868 if ( handle->version != ROAR_DL_FNREG_VERSION )
869  return -1;
870 if ( handle->objectlen != ROAR_DL_FNREG_SIZE )
871  return -1;
872
873 return 0;
874}
875
876static void __fnreg_trigger_if_match(const struct roar_dl_fnreg * callback,
877                                     const struct __fnregs * reg,
878                                     int fn,
879                                     enum roar_dl_fnreg_action action) {
880 if ( callback->fn != -1 && callback->fn != fn )
881  return;
882 if ( callback->subtype != -1 && callback->subtype != reg->subtype )
883  return;
884 if ( callback->version != -1 && callback->version != reg->version )
885  return;
886
887 if ( callback->callback == NULL )
888  return;
889
890 callback->callback(action, fn, reg->subtype, reg->object, reg->objectlen, reg->version, reg->options, callback->userdata, reg->lhandle);
891}
892
893static void __fnreg_trigger_by_reg(const struct __fnregs * reg, enum roar_dl_fnreg_action action, int fn) {
894 size_t j;
895
896 for (j = 0; j < __MAX_FNREGS; j++) {
897  if ( __fnrefs[ROAR_DL_FN_REGFN][j].lhandle != NULL ) {
898   if ( __fnreg_check_trigger(&(__fnrefs[ROAR_DL_FN_REGFN][j])) == -1 )
899    continue;
900   __fnreg_trigger_if_match(__fnrefs[ROAR_DL_FN_REGFN][j].object, reg, fn, action);
901  }
902 }
903}
904
905static void __fnreg_trigger_by_handler(const struct __fnregs * handle, enum roar_dl_fnreg_action action) {
906 size_t i, j;
907
908 if ( __fnreg_check_trigger(handle) == -1 )
909  return;
910
911 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
912  for (j = 0; j < __MAX_FNREGS; j++) {
913   if ( __fnrefs[i][j].lhandle != NULL ) {
914    __fnreg_trigger_if_match(handle->object, &(__fnrefs[i][j]), i, action);
915   }
916  }
917 }
918}
919
920int roar_dl_register_fn(struct roar_dl_lhandle * lhandle, int fn, int subtype, const void * object, size_t objectlen, int version, int options) {
921 struct __fnregs * c = NULL;
922 size_t i;
923
924 if ( lhandle == NULL )
925  lhandle = __currently_inited;
926
927 if ( lhandle == NULL ) {
928  roar_err_set(ROAR_ERROR_FAULT);
929  return -1;
930 }
931
932 if ( fn < 0 || fn >= ROAR_DL_FN_MAX ) {
933  roar_err_set(ROAR_ERROR_RANGE);
934  return -1;
935 }
936
937 if ( object == NULL || objectlen == 0 ) {
938  roar_err_set(ROAR_ERROR_INVAL);
939  return -1;
940 }
941
942 for (i = 0; i < __MAX_FNREGS; i++) {
943  if ( __fnrefs[fn][i].lhandle != NULL )
944   continue;
945  c = &(__fnrefs[fn][i]);
946  break;
947 }
948
949 if ( c == NULL ) {
950  roar_err_set(ROAR_ERROR_NOSPC);
951  return -1;
952 }
953
954 c->lhandle   = lhandle;
955 c->subtype   = subtype;
956 c->object    = object;
957 c->objectlen = objectlen;
958 c->version   = version;
959
960 if ( fn == ROAR_DL_FN_REGFN ) {
961  __fnreg_trigger_by_handler(c, ROAR_DL_FNREG);
962 } else {
963  __fnreg_trigger_by_reg(c, ROAR_DL_FNREG, fn);
964 }
965
966 return 0;
967}
968
969int roar_dl_unregister_fn(struct roar_dl_lhandle * lhandle) {
970 size_t i, j;
971
972//} __fnrefs[ROAR_DL_FN_MAX][__MAX_FNREGS];
973
974 if ( lhandle == NULL ) {
975  roar_err_set(ROAR_ERROR_FAULT);
976  return -1;
977 }
978
979 for (i = 0; i < ROAR_DL_FN_MAX; i++) {
980  for (j = 0; j < __MAX_FNREGS; j++) {
981   if ( __fnrefs[i][j].lhandle == lhandle ) {
982    if ( i == ROAR_DL_FN_REGFN ) {
983     __fnreg_trigger_by_handler(&(__fnrefs[i][j]), ROAR_DL_FNUNREG);
984    } else {
985     __fnreg_trigger_by_reg(&(__fnrefs[i][j]), ROAR_DL_FNUNREG, i);
986    }
987    memset(&(__fnrefs[i][j]), 0, sizeof(__fnrefs[i][j]));
988    __fnrefs[i][j].lhandle = NULL;
989   }
990  }
991 }
992
993 return 0;
994}
995
996//ll
Note: See TracBrowser for help on using the repository browser.