]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ALSA: Add simple refcount helper functions
authorTakashi Iwai <tiwai@suse.de>
Wed, 10 Jun 2026 15:45:31 +0000 (17:45 +0200)
committerTakashi Iwai <tiwai@suse.de>
Thu, 11 Jun 2026 07:34:09 +0000 (09:34 +0200)
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
include/sound/core.h
sound/core/misc.c

index 8b2ca95d13f7db4dba8d227f165e857c6274b874..a3f10294e834ea296b5c6ec748544d917122ee19 100644 (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 {
index 833124c8e4fa83d188473493e44d7f86bc5532e7..4772b2a3b808d7882120b16faf3f24a968df8cc1 100644 (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);