source: roaraudio/libroar/plugincontainer.c @ 5438:4eb05969f66c

Last change on this file since 5438:4eb05969f66c was 5438:4eb05969f66c, checked in by phi, 10 years ago

fix code so refcount is correct and avoid double free

File size: 9.3 KB
Line 
1//plugincontainer.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2011-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#define MAX_PLUGINS 64
39
40struct roar_plugincontainer {
41 size_t refc;
42 struct roar_dl_librarypara * default_para;
43 struct roar_dl_lhandle * handle[MAX_PLUGINS];
44 size_t deprefc[MAX_PLUGINS];
45 size_t numhandles;
46};
47
48static int _loader(struct roar_dl_librarypara * lhandle, void * loader_userdata, enum roar_dl_loadercmd cmd, void * argp) {
49 roar_err_set(ROAR_ERROR_NOSYS);
50 return -1;
51}
52
53static inline void _copy_str(char ** dst, const char * src) {
54 for (; *src; src++, (*dst)++) **dst = *src;
55 *((*dst)++) = 0;
56}
57
58static void * _copy_kv(struct roar_keyval ** copy, struct roar_keyval * src, size_t len) {
59 size_t buflen = 0;
60 size_t i;
61 void * ret;
62 char * p;
63 struct roar_keyval * c;
64
65 for (i = 0; i < len; i++) {
66  if ( src[i].key != NULL )
67   buflen += roar_mm_strlen(src[i].key) + 1;
68  if ( src[i].value != NULL )
69   buflen += roar_mm_strlen(src[i].value) + 1;
70 }
71
72 c   = roar_mm_malloc(len * sizeof(struct roar_keyval));
73 if ( c == NULL )
74  return NULL;
75
76 memset(c, 0, len * sizeof(struct roar_keyval));
77
78 ret = roar_mm_malloc(buflen);
79 if ( ret == NULL )
80  return NULL;
81
82 memset(ret, 0, buflen);
83
84 p = ret;
85
86 for (i = 0; i < len; i++) {
87  if ( src[i].key == NULL ) {
88   c[i].key = NULL;
89  } else {
90   c[i].key = p;
91   _copy_str(&p, src[i].key);
92  }
93
94  if ( src[i].value == NULL ) {
95   c[i].value = NULL;
96  } else {
97   c[i].value = p;
98   _copy_str(&p, src[i].value);
99  }
100 }
101
102 *copy = c;
103 return ret;
104}
105
106static struct roar_dl_librarypara * _copy_para(struct roar_dl_librarypara * para, struct roar_plugincontainer * cont) {
107 struct roar_dl_librarypara * ret = NULL;
108 int err;
109
110 if ( para == NULL || cont == NULL ) {
111  roar_err_set(ROAR_ERROR_FAULT);
112  return NULL;
113 }
114
115 ret = roar_dl_para_new(NULL, para->binargv, para->appname, para->abiversion);
116
117 if ( para->argc && para->argv != NULL ) {
118  ret->argc       = para->argc;
119  ret->args_store = _copy_kv(&(ret->argv), para->argv, para->argc);
120  if ( ret->args_store == NULL ) {
121   err = roar_error;
122   roar_dl_para_unref(ret);
123   roar_error = err;
124   return NULL;
125  }
126 }
127
128 ret->notifycore      = para->notifycore;
129 ret->container       = cont;
130 ret->loader          = _loader;
131 ret->loader_userdata = NULL;
132
133 return ret;
134}
135
136static struct roar_plugincontainer * _new_init(void) {
137 struct roar_plugincontainer * ret = roar_mm_malloc(sizeof(struct roar_plugincontainer));
138 if ( ret == NULL )
139  return NULL;
140
141 memset(ret, 0, sizeof(struct roar_plugincontainer));
142
143 ret->refc = 1;
144
145 return ret;
146}
147
148struct roar_plugincontainer * roar_plugincontainer_new(struct roar_dl_librarypara * default_para) {
149 struct roar_plugincontainer * ret = _new_init();
150 int err;
151
152 if ( ret == NULL )
153  return NULL;
154
155 if ( default_para != NULL ) {
156  ret->default_para = _copy_para(default_para, ret);
157  if ( ret->default_para == NULL ) {
158   err = roar_error;
159   roar_plugincontainer_unref(ret);
160   roar_err_set(err);
161   return NULL;
162  }
163 }
164
165 return ret;
166}
167
168struct roar_plugincontainer * roar_plugincontainer_new_simple(const char * appname, const char * abiversion) {
169 struct roar_plugincontainer * ret;
170 struct roar_dl_librarypara * para = roar_dl_para_new(NULL, NULL, appname, abiversion);
171 int err;
172
173 ret = roar_plugincontainer_new(para);
174 err = roar_error;
175
176 roar_dl_para_unref(para);
177
178 roar_err_set(err);
179 return ret;
180}
181
182int roar_plugincontainer_ref(struct roar_plugincontainer * cont) {
183 if ( cont == NULL ) {
184  ROAR_DBG("roar_plugincontainer_ref(cont=%p) = -1 // error=FAULT", cont);
185  roar_err_set(ROAR_ERROR_FAULT);
186  return -1;
187 }
188
189 cont->refc++;
190
191 ROAR_DBG("roar_plugincontainer_ref(cont=%p) = 0", cont);
192 return 0;
193}
194
195int roar_plugincontainer_unref(struct roar_plugincontainer * cont) {
196 size_t i;
197
198 if ( cont == NULL ) {
199  ROAR_DBG("roar_plugincontainer_unref(cont=%p) = -1 // error=FAULT", cont);
200  roar_err_set(ROAR_ERROR_FAULT);
201  return -1;
202 }
203
204 cont->refc--;
205
206 if ( cont->refc ) {
207  ROAR_DBG("roar_plugincontainer_unref(cont=%p) = 0", cont);
208  return 0;
209 }
210
211 while (cont->numhandles) {
212  for (i = 0; i < MAX_PLUGINS; i++) {
213   if ( cont->handle[i] == NULL )
214    continue;
215
216   // skip plugins in use by others. We will unload them in a later loop.
217   if ( cont->deprefc[i] )
218    continue;
219
220   roar_dl_close(cont->handle[i]);
221   cont->handle[i] = NULL;
222   cont->numhandles--;
223  }
224 }
225
226 if ( cont->default_para != NULL )
227  roar_dl_para_unref(cont->default_para);
228
229 roar_mm_free(cont);
230
231 ROAR_DBG("roar_plugincontainer_unref(cont=%p) = 0", cont);
232 return 0;
233}
234
235// plugin loading and unloading:
236int roar_plugincontainer_load(struct roar_plugincontainer * cont, const char * name, struct roar_dl_librarypara * para) {
237 struct roar_dl_lhandle * ret = roar_plugincontainer_load_lhandle(cont, name, ROAR_DL_FLAG_PLUGIN, 1, para);
238
239 if ( ret == NULL )
240  return -1;
241
242 roar_dl_unref(ret);
243
244 return 0;
245}
246
247struct roar_dl_lhandle * roar_plugincontainer_load_lhandle    (struct roar_plugincontainer * cont,
248                                                               const char * name,
249                                                               int flags,
250                                                               int ra_init,
251                                                               struct roar_dl_librarypara * para) {
252 ssize_t idx = -1;
253 size_t i;
254 int err;
255
256 if ( cont == NULL || name == NULL ) {
257  roar_err_set(ROAR_ERROR_FAULT);
258  return NULL;
259 }
260
261 if ( para == NULL ) {
262  para = cont->default_para;
263  roar_dl_para_ref(para);
264 } else {
265  para = _copy_para(para, cont);
266 }
267
268
269 // search for a free index.
270 if ( cont->numhandles == MAX_PLUGINS ) {
271  // return early if we are full.
272  roar_dl_para_unref(para);
273  roar_err_set(ROAR_ERROR_NOSPC);
274  return NULL;
275 }
276 for (i = 0; i < MAX_PLUGINS; i++) {
277  if ( cont->handle[i] == NULL ) {
278   idx = i;
279   break;
280  }
281 }
282
283 if ( idx == -1 ) {
284  roar_dl_para_unref(para);
285  roar_err_set(ROAR_ERROR_NOSPC);
286  return NULL;
287 }
288
289 cont->handle[idx] = roar_dl_open(name, flags, ra_init, para);
290 if ( cont->handle[idx] == NULL ) {
291  err = roar_error;
292  roar_dl_para_unref(para);
293  roar_error = err;
294  return NULL;
295 }
296
297 cont->deprefc[idx] = 0;
298 cont->numhandles++;
299
300 roar_dl_para_unref(para);
301 roar_dl_ref(cont->handle[idx]);
302 return cont->handle[idx];
303}
304
305int roar_plugincontainer_unload(struct roar_plugincontainer * cont, const char * name) {
306 const struct roar_dl_libraryname * libname;
307 size_t i;
308
309 if ( cont == NULL || name == NULL ) {
310  roar_err_set(ROAR_ERROR_FAULT);
311  return -1;
312 }
313
314 for (i = 0; i < MAX_PLUGINS; i++) {
315  if ( cont->handle[i] == NULL )
316   continue;
317  libname = roar_dl_getlibname(cont->handle[i]);
318  if ( libname == NULL )
319   continue;
320
321  if ( !strcmp(libname->name, name) )
322   return roar_plugincontainer_unload_lhandle(cont, cont->handle[i]);
323 }
324
325 roar_err_set(ROAR_ERROR_NOENT);
326 return -1;
327}
328
329int roar_plugincontainer_unload_lhandle(struct roar_plugincontainer * cont, struct roar_dl_lhandle * lhandle) {
330 size_t i;
331
332 if ( cont == NULL ) {
333  roar_err_set(ROAR_ERROR_FAULT);
334  return -1;
335 }
336
337 if ( lhandle == NULL ) {
338  roar_err_set(ROAR_ERROR_INVAL);
339  return -1;
340 }
341
342 for (i = 0; i < MAX_PLUGINS; i++) {
343  if ( cont->handle[i] == lhandle ) {
344   if ( cont->deprefc[i] ) {
345    // still in use.
346    roar_err_set(ROAR_ERROR_BUSY);
347    return -1;
348   }
349   roar_dl_close(cont->handle[i]);
350   cont->handle[i] = NULL;
351   cont->numhandles--;
352   return 0;
353  }
354 }
355
356 roar_err_set(ROAR_ERROR_NOENT);
357 return -1;
358}
359
360int                      roar_plugincontainer_ra_init         (struct roar_plugincontainer * cont) {
361 size_t i;
362
363 if ( cont == NULL ) {
364  roar_err_set(ROAR_ERROR_FAULT);
365  return -1;
366 }
367
368 for (i = 0; i < MAX_PLUGINS; i++) {
369  if ( cont->handle[i] == NULL )
370   continue;
371  roar_dl_ra_init(cont->handle[i], NULL, cont->default_para);
372 }
373
374 return 0;
375}
376
377// appsched:
378int roar_plugincontainer_appsched_trigger(struct roar_plugincontainer * cont, enum roar_dl_appsched_trigger trigger) {
379 size_t i;
380
381 if ( cont == NULL ) {
382  roar_err_set(ROAR_ERROR_FAULT);
383  return -1;
384 }
385
386 for (i = 0; i < MAX_PLUGINS; i++) {
387  if ( cont->handle[i] == NULL )
388   continue;
389
390  roar_dl_appsched_trigger(cont->handle[i], trigger);
391 }
392
393 return 0;
394}
395
396//ll
Note: See TracBrowser for help on using the repository browser.