Added the support of dl-object caches for PCM plugins.
#define snd_open_device(filename, fmode) open(filename, fmode);
#endif
+/* 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_cleanup(void);
+
#endif
typedef struct snd_pcm_ioplug snd_pcm_ioplug_t;
typedef struct snd_pcm_ioplug_callback snd_pcm_ioplug_callback_t;
+#define SND_PCM_IOPLUG_FLAG_LISTED (1<<0)
+
/* exported pcm data */
struct snd_pcm_ioplug {
/* must be filled before calling snd_pcm_ioplug_create() */
const char *name;
+ unsigned int flags; /* SND_PCM_IOPLUG_FLAG_XXX */
int poll_fd;
unsigned int poll_events;
unsigned int mmap_rw; /* pseudo mmap */
snd_config_update_free(snd_config_global_update);
snd_config_global_update = NULL;
pthread_mutex_unlock(&snd_config_update_mutex);
+
+ /* FIXME: better to place this in another place... */
+ snd_dlobj_cache_cleanup();
+
return 0;
}
#define _GNU_SOURCE
#include <dlfcn.h>
+#include "list.h"
#include "local.h"
#ifndef DOC_HIDDEN
return NULL;
return dlsym(handle, name);
}
+
+/*
+ * dlobj cache
+ *
+ * FIXME: add reference counter and proper locking
+ */
+
+struct dlobj_cache {
+ const char *name;
+ void *obj;
+ void *func;
+ struct list_head list;
+};
+
+static LIST_HEAD(pcm_dlobj_list);
+
+void *snd_dlobj_cache_lookup(const char *name)
+{
+ 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;
+}
+
+int snd_dlobj_cache_add(const char *name, void *dlobj, void *open_func)
+{
+ 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 0; /* already exists */
+ }
+ c = malloc(sizeof(*c));
+ if (! c)
+ return -ENOMEM;
+ c->name = strdup(name);
+ if (! c->name) {
+ free(c);
+ return -ENOMEM;
+ }
+ c->obj = dlobj;
+ c->func = open_func;
+ list_add_tail(&c->list, &pcm_dlobj_list);
+ return 0;
+}
+
+void snd_dlobj_cache_cleanup(void)
+{
+ struct list_head *p;
+ struct dlobj_cache *c;
+
+ while (! list_empty(&pcm_dlobj_list)) {
+ p = pcm_dlobj_list.next;
+ c = list_entry(p, struct dlobj_cache, list);
+ list_del(p);
+ snd_dlclose(c->obj);
+ free(c->name);
+ free(c);
+ }
+}
#ifndef PIC
snd_pcm_open_symbols(); /* this call is for static linking only */
#endif
+ open_func = snd_dlobj_cache_lookup(open_name);
+ 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 = -ENXIO;
}
_err:
- if (type_conf)
- snd_config_delete(type_conf);
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;
err = 0;
} else {
- snd_dlclose(h);
+ if (h)
+ snd_dlclose(h);
}
}
+ if (type_conf)
+ snd_config_delete(type_conf);
if (buf)
free(buf);
if (buf1)