Takashi
---
diff --git a/include/conf.h b/include/conf.h
index 087c05dc6bcf..72fd7c06a8d9 100644
--- a/include/conf.h
+++ b/include/conf.h
@@ -94,6 +94,10 @@ int snd_config_update_r(snd_config_t **top, snd_config_update_t **update, const
int snd_config_update_free(snd_config_update_t *update);
int snd_config_update_free_global(void);
+void snd_config_refresh(void);
+int snd_config_update_get(snd_config_t **top);
+void snd_config_put(snd_config_t *top);
+
int snd_config_search(snd_config_t *config, const char *key,
snd_config_t **result);
int snd_config_searchv(snd_config_t *config,
diff --git a/src/conf.c b/src/conf.c
index f8b7a6686529..1386a38b0b27 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -434,6 +434,7 @@ static pthread_once_t snd_config_update_mutex_once = PTHREAD_ONCE_INIT;
struct _snd_config {
char *id;
snd_config_type_t type;
+ int refcount; /* default = 0 */
union {
long integer;
long long integer64;
@@ -1833,6 +1834,10 @@ int snd_config_remove(snd_config_t *config)
int snd_config_delete(snd_config_t *config)
{
assert(config);
+ if (config->refcount > 0) {
+ config->refcount--;
+ return 0;
+ }
switch (config->type) {
case SND_CONFIG_TYPE_COMPOUND:
{
@@ -3851,6 +3856,60 @@ int snd_config_update(void)
return err;
}
+/**
+ * \brief Clear the local config update cache
+ *
+ * This function clears the local config update cache to guarantee that
+ * the next call of #snd_config_update will reread the config files.
+ */
+void snd_config_refresh(void)
+{
+ snd_config_lock();
+ if (snd_config_global_update)
+ snd_config_update_free(snd_config_global_update);
+ snd_config_global_update = NULL;
+ snd_config_unlock();
+}
+
+/**
+ * \brief Updates #snd_config and take its reference.
+ * \return 0 if #snd_config was up to date, 1 if #snd_config was
+ * updated, otherwise a negative error code.
+ *
+ * Unlike #snd_config_update, this function increases a reference counter
+ * so that the obtained tree won't be deleted until unreferenced by
+ * #snd_config_put.
+ */
+int snd_config_update_get(snd_config_t **top)
+{
+ int err;
+
+ *top = NULL;
+ snd_config_lock();
+ err = snd_config_update_r(&snd_config, &snd_config_global_update, NULL);
+ if (err >= 0) {
+ *top = snd_config;
+ if (*top)
+ (*top)->refcount++;
+ }
+ snd_config_unlock();
+ return err;
+}
+
+/**
+ * \brief Unreference the config tree.
+ *
+ * Decreases a reference counter of the given config tree. This is the
+ * counterpart of #snd_config_update_get.
+ */
+void snd_config_put(snd_config_t *cfg)
+{
+ snd_config_lock();
+ if (cfg)
+ snd_config_delete(cfg);
+ snd_config_unlock();
+}
+
/**
* \brief Frees a private update structure.
* \param[in] update The private update structure to free.
diff --git a/src/control/control.c b/src/control/control.c
index 8a5d530f2674..6078189a6a70 100644
--- a/src/control/control.c
+++ b/src/control/control.c
@@ -968,12 +968,16 @@ static int snd_ctl_open_noupdate(snd_ctl_t **ctlp, snd_config_t *root, const cha
*/
int snd_ctl_open(snd_ctl_t **ctlp, const char *name, int mode)
{
+ snd_config_t *top;
int err;
+
assert(ctlp && name);
- err = snd_config_update();
+ err = snd_config_update_get(&top);
if (err < 0)
return err;
- return snd_ctl_open_noupdate(ctlp, snd_config, name, mode);
+ err = snd_ctl_open_noupdate(ctlp, top, name, mode);
+ snd_config_put(top);
+ return err;
}
/**
diff --git a/src/hwdep/hwdep.c b/src/hwdep/hwdep.c
index 5dc791c99189..c8b368fa68a2 100644
--- a/src/hwdep/hwdep.c
+++ b/src/hwdep/hwdep.c
@@ -168,12 +168,16 @@ static int snd_hwdep_open_noupdate(snd_hwdep_t **hwdep, snd_config_t *root, cons
*/
int snd_hwdep_open(snd_hwdep_t **hwdep, const char *name, int mode)
{
+ snd_config_t *top;
int err;
+
assert(hwdep && name);
- err = snd_config_update();
+ err = snd_config_update_get(&top);
if (err < 0)
return err;
- return snd_hwdep_open_noupdate(hwdep, snd_config, name, mode);
+ err = snd_hwdep_open_noupdate(hwdep, top, name, mode);
+ snd_config_put(top);
+ return err;
}
/**
diff --git a/src/pcm/pcm.c b/src/pcm/pcm.c
index 203e7a52491b..42da2c8a8b55 100644
--- a/src/pcm/pcm.c
+++ b/src/pcm/pcm.c
@@ -2288,12 +2288,16 @@ static int snd_pcm_open_noupdate(snd_pcm_t **pcmp, snd_config_t *root,
int snd_pcm_open(snd_pcm_t **pcmp, const char *name,
snd_pcm_stream_t stream, int mode)
{
+ snd_config_t *top;
int err;
+
assert(pcmp && name);
- err = snd_config_update();
+ err = snd_config_update_get(&top);
if (err < 0)
return err;
- return snd_pcm_open_noupdate(pcmp, snd_config, name, stream, mode, 0);
+ err = snd_pcm_open_noupdate(pcmp, top, name, stream, mode, 0);
+ snd_config_put(top);
+ return err;
}
/**
diff --git a/src/rawmidi/rawmidi.c b/src/rawmidi/rawmidi.c
index 0c89b8b984b9..d965edaf1f42 100644
--- a/src/rawmidi/rawmidi.c
+++ b/src/rawmidi/rawmidi.c
@@ -305,12 +305,16 @@ static int snd_rawmidi_open_noupdate(snd_rawmidi_t **inputp, snd_rawmidi_t **out
int snd_rawmidi_open(snd_rawmidi_t **inputp, snd_rawmidi_t **outputp,
const char *name, int mode)
{
+ snd_config_t *top;
int err;
+
assert((inputp || outputp) && name);
- err = snd_config_update();
+ err = snd_config_update_get(&top);
if (err < 0)
return err;
- return snd_rawmidi_open_noupdate(inputp, outputp, snd_config, name, mode);
+ err = snd_rawmidi_open_noupdate(inputp, outputp, top, name, mode);
+ snd_config_put(top);
+ return err;
}
/**
diff --git a/src/seq/seq.c b/src/seq/seq.c
index 4405e68a7fe9..c1aa7981d557 100644
--- a/src/seq/seq.c
+++ b/src/seq/seq.c
@@ -974,12 +974,16 @@ static int snd_seq_open_noupdate(snd_seq_t **seqp, snd_config_t *root,
int snd_seq_open(snd_seq_t **seqp, const char *name,
int streams, int mode)
{
+ snd_config_t *top;
int err;
+
assert(seqp && name);
- err = snd_config_update();
+ err = snd_config_update_get(&top);
if (err < 0)
return err;
- return snd_seq_open_noupdate(seqp, snd_config, name, streams, mode, 0);
+ err = snd_seq_open_noupdate(seqp, top, name, streams, mode, 0);
+ snd_config_put(top);
+ return err;
}
/**
diff --git a/src/timer/timer.c b/src/timer/timer.c
index a25e4f797ce4..6af6d8224df1 100644
--- a/src/timer/timer.c
+++ b/src/timer/timer.c
@@ -201,12 +201,16 @@ static int snd_timer_open_noupdate(snd_timer_t **timer, snd_config_t *root, cons
*/
int snd_timer_open(snd_timer_t **timer, const char *name, int mode)
{
+ snd_config_t *top;
int err;
+
assert(timer && name);
- err = snd_config_update();
+ err = snd_config_update_get(&top);
if (err < 0)
return err;
- return snd_timer_open_noupdate(timer, snd_config, name, mode);
+ err = snd_timer_open_noupdate(timer, top, name, mode);
+ snd_config_put(top);
+ return err;
}
/**
diff --git a/src/timer/timer_query.c b/src/timer/timer_query.c
index 93d2455d07fc..23bf0711aafe 100644
--- a/src/timer/timer_query.c
+++ b/src/timer/timer_query.c
@@ -159,12 +159,16 @@ static int snd_timer_query_open_noupdate(snd_timer_query_t **timer, snd_config_t
*/
int snd_timer_query_open(snd_timer_query_t **timer, const char *name, int mode)
{
+ snd_config_t *top;
int err;
+
assert(timer && name);
- err = snd_config_update();
+ err = snd_config_update_get(&top);
if (err < 0)
return err;
- return snd_timer_query_open_noupdate(timer, snd_config, name, mode);
+ err = snd_timer_query_open_noupdate(timer, top, name, mode);
+ snd_config_put(top);
+ return err;
}
/**