From: Takashi Iwai Date: Wed, 10 Jun 2026 15:45:31 +0000 (+0200) Subject: ALSA: Add simple refcount helper functions X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=dcca9b6064c33c84fbeb9f09814178a206321249;p=thirdparty%2Fkernel%2Flinux.git 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 Link: https://patch.msgid.link/20260610154538.51076-2-tiwai@suse.de --- diff --git a/include/sound/core.h b/include/sound/core.h index 8b2ca95d13f7d..a3f10294e834e 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -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 { diff --git a/sound/core/misc.c b/sound/core/misc.c index 833124c8e4fa8..4772b2a3b808d 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -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);