ALSA: Add simple refcount helper functions

There are many open-code to manage the same pattern for refcount +
wakeup sync at closing.  Let's provide the common helper functions to
replace the open-code.

- The recount is kept in struct snd_refcount, where it's initialized
by snd_refcount_init().
- The user can simply reference or unreference via snd_refcount_get()
and snd_refcount_put() functions
- The user can wait for the all usages gone by snd_refcount_sync()

Note that here we use atomic_t instead of refcount_t since the current
users allow reusing the refcount after sync again.  The design of
refcount_t prevents exactly this behavior, so it doesn't fit.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20260610154538.51076-2-tiwai@suse.de
This commit is contained in:
Takashi Iwai 2026-06-10 17:45:31 +02:00
parent 03a1085906
commit dcca9b6064
2 changed files with 45 additions and 0 deletions

View File

@ -75,6 +75,27 @@ struct snd_device {
#define snd_device(n) list_entry(n, struct snd_device, list)
/*
* A simple reference counter with a wait queue;
* typically used for usage counts, and you can synchronize at finishing
* via snd_refcount_sync(), which is woken up when the refcount reaches to
* zero again.
*/
struct snd_refcount {
atomic_t count;
wait_queue_head_t waiter;
};
void snd_refcount_init(struct snd_refcount *ref);
static inline void snd_refcount_get(struct snd_refcount *ref)
{
atomic_inc(&ref->count);
}
void snd_refcount_put(struct snd_refcount *ref);
void snd_refcount_sync(struct snd_refcount *ref);
/* main structure for soundcard */
struct snd_card {

View File

@ -174,3 +174,27 @@ void snd_fasync_free(struct snd_fasync *fasync)
kfree(fasync);
}
EXPORT_SYMBOL_GPL(snd_fasync_free);
/*
* generic refcount helper
*/
void snd_refcount_init(struct snd_refcount *ref)
{
atomic_set(&ref->count, 0);
init_waitqueue_head(&ref->waiter);
}
EXPORT_SYMBOL_GPL(snd_refcount_init);
void snd_refcount_put(struct snd_refcount *ref)
{
if (atomic_dec_and_test(&ref->count))
wake_up(&ref->waiter);
}
EXPORT_SYMBOL_GPL(snd_refcount_put);
void snd_refcount_sync(struct snd_refcount *ref)
{
wait_event(ref->waiter, !atomic_read(&ref->count));
}
EXPORT_SYMBOL_GPL(snd_refcount_sync);