general: recoded snd_dlobj_ functions

- changed logic to get/put blocks
- added mutex locking of the symbol list
- added reference counting (do not free used dl handles)

Signed-off-by: Jaroslav Kysela <perex@perex.cz>
This commit is contained in:
Jaroslav Kysela 2010-08-23 17:05:36 +02:00
parent be06ab3ee7
commit 91c9c8f1b8
7 changed files with 153 additions and 123 deletions

View file

@ -254,10 +254,10 @@ static inline int snd_open_device(const char *filename, int fmode)
}
/* make local functions really local */
#define snd_dlobj_cache_lookup \
snd1_dlobj_cache_lookup
#define snd_dlobj_cache_add \
snd1_dlobj_cache_add
#define snd_dlobj_cache_get \
snd1_dlobj_cache_get
#define snd_dlobj_cache_put \
snd1_dlobj_cache_put
#define snd_dlobj_cache_cleanup \
snd1_dlobj_cache_cleanup
#define snd_config_set_hop \
@ -268,8 +268,8 @@ static inline int snd_open_device(const char *filename, int fmode)
snd1_config_search_alias_hooks
/* dlobj cache */
void *snd_dlobj_cache_lookup(const char *name);
int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func);
void *snd_dlobj_cache_get(const char *lib, const char *name, const char *version, int verbose);
int snd_dlobj_cache_put(void *open_func);
void snd_dlobj_cache_cleanup(void);
/* for recursive checks */

View file

@ -94,8 +94,7 @@ int snd_ctl_close(snd_ctl_t *ctl)
}
err = ctl->ops->close(ctl);
free(ctl->name);
if (ctl->dl_handle)
snd_dlclose(ctl->dl_handle);
snd_dlobj_cache_put(ctl->open_func);
free(ctl);
return err;
}
@ -768,7 +767,6 @@ static int snd_ctl_open_conf(snd_ctl_t **ctlp, const char *name,
#ifndef PIC
extern void *snd_control_open_symbols(void);
#endif
void *h = NULL;
if (snd_config_get_type(ctl_conf) != SND_CONFIG_TYPE_COMPOUND) {
if (name)
SNDERR("Invalid type for CTL %s definition", name);
@ -854,40 +852,22 @@ static int snd_ctl_open_conf(snd_ctl_t **ctlp, const char *name,
#ifndef PIC
snd_control_open_symbols();
#endif
open_func = snd_dlobj_cache_lookup(open_name);
open_func = snd_dlobj_cache_get(lib, open_name,
SND_DLSYM_VERSION(SND_CONTROL_DLSYM_VERSION), 1);
if (open_func) {
err = 0;
goto _err;
}
h = snd_dlopen(lib, RTLD_NOW);
if (h)
open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_CONTROL_DLSYM_VERSION));
err = 0;
if (!h) {
SNDERR("Cannot open shared library %s", lib);
err = -ENOENT;
} else if (!open_func) {
SNDERR("symbol %s is not defined inside %s", open_name, lib);
snd_dlclose(h);
err = open_func(ctlp, name, ctl_root, ctl_conf, mode);
if (err >= 0) {
(*ctlp)->open_func = open_func;
err = 0;
} else {
snd_dlobj_cache_put(open_func);
}
} else {
err = -ENXIO;
}
_err:
if (type_conf)
snd_config_delete(type_conf);
if (err >= 0) {
err = open_func(ctlp, name, ctl_root, ctl_conf, mode);
if (err >= 0) {
if (h /*&& (mode & SND_CTL_KEEP_ALIVE)*/) {
snd_dlobj_cache_add(open_name, h, open_func);
h = NULL;
}
(*ctlp)->dl_handle = h;
err = 0;
} else {
if (h)
snd_dlclose(h);
}
}
free(buf);
free(buf1);
return err;

View file

@ -56,7 +56,7 @@ typedef struct _snd_ctl_ops {
struct _snd_ctl {
void *dl_handle;
void *open_func;
char *name;
snd_ctl_type_t type;
const snd_ctl_ops_t *ops;

View file

@ -29,6 +29,9 @@
#include "list.h"
#include "local.h"
#ifdef HAVE_LIBPTHREAD
#include <pthread.h>
#endif
#ifndef DOC_HIDDEN
#ifndef PIC
@ -169,69 +172,140 @@ void *snd_dlsym(void *handle, const char *name, const char *version)
/*
* dlobj cache
*
* FIXME: add reference counter and proper locking
*/
#ifndef DOC_HIDDEN
struct dlobj_cache {
const char *lib;
const char *name;
void *obj;
void *dlobj;
void *func;
unsigned int refcnt;
struct list_head list;
};
static LIST_HEAD(pcm_dlobj_list);
#ifdef HAVE_LIBPTHREAD
static pthread_mutex_t snd_dlobj_mutex = PTHREAD_MUTEX_INITIALIZER;
void *snd_dlobj_cache_lookup(const char *name)
static inline void snd_dlobj_lock(void)
{
struct list_head *p;
struct dlobj_cache *c;
list_for_each(p, &pcm_dlobj_list) {
c = list_entry(p, struct dlobj_cache, list);
if (strcmp(c->name, name) == 0)
return c->func;
}
return NULL;
pthread_mutex_lock(&snd_dlobj_mutex);
}
int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func)
static inline void snd_dlobj_unlock(void)
{
pthread_mutex_unlock(&snd_dlobj_mutex);
}
#else
static inline void snd_dlobj_lock(void) {}
static inline void snd_dlobj_unlock(void) {}
#endif
static LIST_HEAD(pcm_dlobj_list);
void *snd_dlobj_cache_get(const char *lib, const char *name,
const char *version, int verbose)
{
struct list_head *p;
struct dlobj_cache *c;
void *func, *dlobj = NULL;
int dlobj_close = 0;
snd_dlobj_lock();
list_for_each(p, &pcm_dlobj_list) {
c = list_entry(p, struct dlobj_cache, list);
if (strcmp(c->name, name) == 0)
return 0; /* already exists */
if (c->lib && lib && strcmp(c->lib, lib) != 0)
continue;
if (!c->lib && lib)
continue;
if (!lib && c->lib)
continue;
dlobj = c->dlobj;
if (strcmp(c->name, name) == 0) {
c->refcnt++;
func = c->func;
snd_dlobj_unlock();
return func;
}
}
if (dlobj == NULL) {
dlobj = snd_dlopen(lib, RTLD_NOW);
if (dlobj == NULL) {
if (verbose)
SNDERR("Cannot open shared library %s",
lib ? lib : "[builtin]");
snd_dlobj_unlock();
return NULL;
}
dlobj_close = 1;
}
func = snd_dlsym(dlobj, name, version);
if (func == NULL) {
if (verbose)
SNDERR("symbol %s is not defined inside %s",
name, lib ? lib : "[builtin]");
goto __err;
}
c = malloc(sizeof(*c));
if (! c)
return -ENOMEM;
goto __err;
c->refcnt = 1;
c->lib = lib ? strdup(lib) : NULL;
c->name = strdup(name);
if (! c->name) {
if ((lib && ! c->lib) || ! c->name) {
free((void *)c->name);
free((void *)c->lib);
free(c);
return -ENOMEM;
__err:
if (dlobj_close)
snd_dlclose(dlobj);
snd_dlobj_unlock();
return NULL;
}
c->obj = dlobj;
c->func = open_func;
c->dlobj = dlobj;
c->func = func;
list_add_tail(&c->list, &pcm_dlobj_list);
return 0;
snd_dlobj_unlock();
return func;
}
int snd_dlobj_cache_put(void *func)
{
struct list_head *p;
struct dlobj_cache *c;
unsigned int refcnt;
snd_dlobj_lock();
list_for_each(p, &pcm_dlobj_list) {
c = list_entry(p, struct dlobj_cache, list);
if (c->func == func) {
refcnt = c->refcnt;
if (c->refcnt > 0)
c->refcnt--;
snd_dlobj_unlock();
return refcnt == 1 ? 0 : -EINVAL;
}
}
snd_dlobj_unlock();
return -ENOENT;
}
void snd_dlobj_cache_cleanup(void)
{
struct list_head *p;
struct list_head *p, *npos;
struct dlobj_cache *c;
while (! list_empty(&pcm_dlobj_list)) {
p = pcm_dlobj_list.next;
snd_dlobj_lock();
list_for_each_safe(p, npos, &pcm_dlobj_list) {
c = list_entry(p, struct dlobj_cache, list);
list_del(p);
snd_dlclose(c->obj);
free((void *)c->name); /* shut up gcc warning */
free(c);
if (c->refcnt == 0) {
list_del(p);
snd_dlclose(c->dlobj);
free((void *)c->name); /* shut up gcc warning */
free((void *)c->lib); /* shut up gcc warning */
free(c);
}
}
snd_dlobj_unlock();
}
#endif

View file

@ -2068,7 +2068,6 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
#ifndef PIC
extern void *snd_pcm_open_symbols(void);
#endif
void *h = NULL;
if (snd_config_get_type(pcm_conf) != SND_CONFIG_TYPE_COMPOUND) {
char *val;
id = NULL;
@ -2157,39 +2156,18 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
#ifndef PIC
snd_pcm_open_symbols(); /* this call is for static linking only */
#endif
open_func = snd_dlobj_cache_lookup(open_name);
open_func = snd_dlobj_cache_get(lib, open_name,
SND_DLSYM_VERSION(SND_PCM_DLSYM_VERSION), 1);
if (open_func) {
err = 0;
goto _err;
}
h = snd_dlopen(lib, RTLD_NOW);
if (h)
open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_PCM_DLSYM_VERSION));
err = 0;
if (!h) {
SNDERR("Cannot open shared library %s",
lib ? lib : "[builtin]");
err = -ENOENT;
} else if (!open_func) {
SNDERR("symbol %s is not defined inside %s", open_name,
lib ? lib : "[builtin]");
snd_dlclose(h);
err = -ENXIO;
}
_err:
if (err >= 0) {
err = open_func(pcmp, name, pcm_root, pcm_conf, stream, mode);
if (err >= 0) {
if (h /*&& (mode & SND_PCM_KEEP_ALIVE)*/) {
snd_dlobj_cache_add(open_name, h, open_func);
h = NULL;
}
(*pcmp)->dl_handle = h;
(*pcmp)->open_func = open_func;
err = 0;
} else {
if (h)
snd_dlclose(h);
snd_dlobj_cache_put(open_func);
}
} else {
err = -ENXIO;
}
if (err >= 0) {
err = snd_config_search(pcm_root, "defaults.pcm.compat", &tmp);
@ -2209,6 +2187,7 @@ static int snd_pcm_open_conf(snd_pcm_t **pcmp, const char *name,
snd_config_get_integer(tmp, &(*pcmp)->minperiodtime);
err = 0;
}
_err:
if (type_conf)
snd_config_delete(type_conf);
free(buf);
@ -2304,8 +2283,7 @@ int snd_pcm_free(snd_pcm_t *pcm)
free(pcm->name);
free(pcm->hw.link_dst);
free(pcm->appl.link_dst);
if (pcm->dl_handle)
snd_dlclose(pcm->dl_handle);
snd_dlobj_cache_put(pcm->open_func);
free(pcm);
return 0;
}

View file

@ -174,7 +174,7 @@ typedef struct {
} snd_pcm_fast_ops_t;
struct _snd_pcm {
void *dl_handle;
void *open_func;
char *name;
snd_pcm_type_t type;
snd_pcm_stream_t stream;

View file

@ -61,6 +61,7 @@ struct _snd_pcm_rate {
snd_pcm_channel_area_t *pareas; /* areas for splitted period (rate pcm) */
snd_pcm_channel_area_t *sareas; /* areas for splitted period (slave pcm) */
snd_pcm_rate_info_t info;
void *open_func;
void *obj;
snd_pcm_rate_ops_t ops;
unsigned int get_idx;
@ -1204,6 +1205,8 @@ static int snd_pcm_rate_close(snd_pcm_t *pcm)
if (rate->ops.close)
rate->ops.close(rate->obj);
if (rate->open_func)
snd_dlobj_cache_put(rate->open_func);
return snd_pcm_generic_close(pcm);
}
@ -1272,33 +1275,23 @@ static const char *const default_rate_plugins[] = {
"speexrate", "linear", NULL
};
static int rate_open_func(snd_pcm_rate_t *rate, const char *type)
static int rate_open_func(snd_pcm_rate_t *rate, const char *type, int verbose)
{
char open_name[64];
char open_name[64], lib_name[128], *lib = NULL;
snd_pcm_rate_open_func_t open_func;
int err;
snprintf(open_name, sizeof(open_name), "_snd_pcm_rate_%s_open", type);
open_func = snd_dlobj_cache_lookup(open_name);
if (!open_func) {
void *h;
char lib_name[128], *lib = NULL;
if (!is_builtin_plugin(type)) {
snprintf(lib_name, sizeof(lib_name),
if (!is_builtin_plugin(type)) {
snprintf(lib_name, sizeof(lib_name),
"%s/libasound_module_rate_%s.so", ALSA_PLUGIN_DIR, type);
lib = lib_name;
}
h = snd_dlopen(lib, RTLD_NOW);
if (!h)
return -ENOENT;
open_func = snd_dlsym(h, open_name, NULL);
if (!open_func) {
snd_dlclose(h);
return -ENOENT;
}
snd_dlobj_cache_add(open_name, h, open_func);
lib = lib_name;
}
open_func = snd_dlobj_cache_get(lib, open_name, NULL, verbose);
if (!open_func)
return -ENOENT;
rate->open_func = open_func;
rate->rate_min = SND_PCM_PLUGIN_RATE_MIN;
rate->rate_max = SND_PCM_PLUGIN_RATE_MAX;
rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION;
@ -1315,8 +1308,13 @@ static int rate_open_func(snd_pcm_rate_t *rate, const char *type)
/* try to open with the old protocol version */
rate->plugin_version = SND_PCM_RATE_PLUGIN_VERSION_OLD;
return open_func(SND_PCM_RATE_PLUGIN_VERSION_OLD,
&rate->obj, &rate->ops);
err = open_func(SND_PCM_RATE_PLUGIN_VERSION_OLD,
&rate->obj, &rate->ops);
if (err) {
snd_dlobj_cache_put(open_func);
rate->open_func = NULL;
}
return err;
}
#endif
@ -1373,21 +1371,21 @@ int snd_pcm_rate_open(snd_pcm_t **pcmp, const char *name,
if (!converter) {
const char *const *types;
for (types = default_rate_plugins; *types; types++) {
err = rate_open_func(rate, *types);
err = rate_open_func(rate, *types, 0);
if (!err) {
type = *types;
break;
}
}
} else if (!snd_config_get_string(converter, &type))
err = rate_open_func(rate, type);
err = rate_open_func(rate, type, 1);
else if (snd_config_get_type(converter) == SND_CONFIG_TYPE_COMPOUND) {
snd_config_iterator_t i, next;
snd_config_for_each(i, next, converter) {
snd_config_t *n = snd_config_iterator_entry(i);
if (snd_config_get_string(n, &type) < 0)
break;
err = rate_open_func(rate, type);
err = rate_open_func(rate, type, 0);
if (!err)
break;
}