All of lore.kernel.org
 help / color / mirror / Atom feed
From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
To: Tom Yan <tom.ty89@gmail.com>
Cc: alsa-devel@alsa-project.org,
	pulseaudio-discuss@lists.freedesktop.org,
	alsa-user@alsa-project.org, pierre-louis.bossart@linux.intel.com
Subject: Re: Why doesn't mixer control (values) have some kind of locking mechanism? (mutex?)
Date: Thu, 6 Aug 2020 23:47:29 +0900	[thread overview]
Message-ID: <20200806144729.GA381789@workstation> (raw)
In-Reply-To: <CAGnHSEkV9cpWoQKP1mT7RyqyTvGrZu045k=3W45Jm=mBidqDnw@mail.gmail.com>

Hi,

On Thu, Aug 06, 2020 at 08:31:51PM +0800, Tom Yan wrote:
> Yeah I suppose a "full" lock would do. (That was what I was trying to
> point out. I don't really understand Pierre's message. I merely
> suppose you need some facility in the kernel anyway so that you can
> lock from userspace.) I hope that amixer the utility will at least have
> the capability to reschedule/wait by then though (instead of just
> "failing" like in your python demo).

As long as I know, neither tools in alsa-utils/alsa-tools nor pulseaudio
use the lock mechanism. In short, you are the first person to address
to the issue. Thanks for your patience since the first post in 2015.

> As for the compare-and-swap part, it's just a plus. Not that
> "double-looping" for *each* channel doesn't work. It just again seems
> silly and primitive (and was once confusing to me).

I prepare a rough kernel patch abount the compare-and-swap idea for
our discussion. The compare-and-swap is done under lock acquisition of
'struct snd_card.controls_rwsem', therefore many types of operations
to control element (e.g. read as well) get affects. This idea works
well at first when alsa-lib supports corresponding API and userspace
applications uses it. Therefore we need more work than changing just
in userspace.

But in my opinion, if things can be solved just in userspace, it should
be done with no change in kernel space.

======== 8< --------

From 54832d11b9056da2883d6edfdccaab76d8b08a5c Mon Sep 17 00:00:00 2001
From: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Date: Thu, 6 Aug 2020 19:34:55 +0900
Subject: [PATCH] ALSA: control: add new ioctl request for compare_and_swap
 operation to element value

This is a rough implementation as a solution for an issue below. This is
not tested yet. The aim of this patch is for further discussion.

Typical userspace applications decide write value to control element
according to value read preliminarily. In the case, if multiple
applications begin a pair of read and write operations simultaneously,
the result is not deterministic without any lock mechanism. Although
ALSA control core has lock/unlock mechanism to a control element for
the case, the mechanism is not so popular. The mechanism neither not
used by tools in alsa-utils, alsa-tools, nor PulseAudio, at least.

This commit is an attempt to solve the case by introducing new ioctl
request. The request is a part of 'compare and swap' mechanism. The
applications should pass ioctl argument with a pair of old and new value
of the control element. ALSA control core read current value and compare
it to the old value under acquisition of lock. If they are the same,
the new value is going to be written at last.

Reported-by: Tom Yan <tom.ty89@gmail.com>
Reference: https://lore.kernel.org/alsa-devel/CAGnHSEkV9cpWoQKP1mT7RyqyTvGrZu045k=3W45Jm=mBidqDnw@mail.gmail.com/T/
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
---
 include/uapi/sound/asound.h |  6 ++++
 sound/core/control.c        | 56 +++++++++++++++++++++++++++++++++++++
 2 files changed, 62 insertions(+)

diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 535a7229e1d9..ff8d5416458d 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -1074,6 +1074,11 @@ struct snd_ctl_tlv {
 	unsigned int tlv[0];	/* first TLV */
 };
 
+struct snd_ctl_elem_compare_and_swap {
+	struct snd_ctl_elem_value old;
+	struct snd_ctl_elem_value new;
+};
+
 #define SNDRV_CTL_IOCTL_PVERSION	_IOR('U', 0x00, int)
 #define SNDRV_CTL_IOCTL_CARD_INFO	_IOR('U', 0x01, struct snd_ctl_card_info)
 #define SNDRV_CTL_IOCTL_ELEM_LIST	_IOWR('U', 0x10, struct snd_ctl_elem_list)
@@ -1089,6 +1094,7 @@ struct snd_ctl_tlv {
 #define SNDRV_CTL_IOCTL_TLV_READ	_IOWR('U', 0x1a, struct snd_ctl_tlv)
 #define SNDRV_CTL_IOCTL_TLV_WRITE	_IOWR('U', 0x1b, struct snd_ctl_tlv)
 #define SNDRV_CTL_IOCTL_TLV_COMMAND	_IOWR('U', 0x1c, struct snd_ctl_tlv)
+#define SNDRV_CTL_IOCTL_ELEM_COPARE_AND_SWAP	_IOWR('U', 0x1d, struct snd_ctl_elem_compare_and_swap)
 #define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int)
 #define SNDRV_CTL_IOCTL_HWDEP_INFO	_IOR('U', 0x21, struct snd_hwdep_info)
 #define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE	_IOR('U', 0x30, int)
diff --git a/sound/core/control.c b/sound/core/control.c
index aa0c0cf182af..0ac1f7c489be 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -1684,6 +1684,60 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
 	return -ENXIO;
 }
 
+static int snd_ctl_elem_compare_and_swap(struct snd_ctl_file *ctl_file,
+					 struct snd_ctl_elem_compare_and_swap *cas)
+{
+	struct snd_card *card = ctl_file->card;
+	// TODO: too much use on kernel stack...
+	struct snd_ctl_elem_value curr;
+	struct snd_ctl_elem_info info;
+	unsigned int unit_size;
+	int err;
+
+	info.id = cas->old.id;
+	err = snd_ctl_elem_info(ctl_file, &info);
+	if (err < 0)
+		return err;
+	if (info.type < SNDRV_CTL_ELEM_TYPE_BOOLEAN || info.type > SNDRV_CTL_ELEM_TYPE_INTEGER64)
+		return -ENXIO;
+	unit_size = value_sizes[info.type];
+
+	curr.id = cas->old.id;
+	err = snd_ctl_elem_read(card, &curr);
+	if (err < 0)
+		return err;
+
+	// Compare.
+	if (memcmp(&cas->old.value, &curr.value, unit_size * info.count) != 0)
+		return -EAGAIN;
+
+	// Swap.
+	return snd_ctl_elem_write(card, ctl_file, &cas->new);
+}
+
+static int snd_ctl_elem_compare_and_swap_user(struct snd_ctl_file *ctl_file,
+					      struct snd_ctl_elem_compare_and_swap __user *argp)
+{
+	struct snd_card *card = ctl_file->card;
+	struct snd_ctl_elem_compare_and_swap *cas;
+	int err;
+
+	cas = memdup_user(argp, sizeof(*cas));
+	if (IS_ERR(cas))
+		return PTR_ERR(cas);
+
+	err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
+	if (err < 0)
+		goto end;
+
+	down_read(&card->controls_rwsem);
+	err = snd_ctl_elem_compare_and_swap(ctl_file, cas);
+	up_read(&card->controls_rwsem);
+end:
+	kfree(cas);
+	return err;
+}
+
 static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
 	struct snd_ctl_file *ctl;
@@ -1737,6 +1791,8 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
 		err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
 		up_write(&ctl->card->controls_rwsem);
 		return err;
+	case SNDRV_CTL_IOCTL_ELEM_COPARE_AND_SWAP:
+		return snd_ctl_elem_compare_and_swap_user(ctl, argp);
 	case SNDRV_CTL_IOCTL_POWER:
 		return -ENOPROTOOPT;
 	case SNDRV_CTL_IOCTL_POWER_STATE:
-- 
2.25.1

======== 8< --------

Thanks

Takashi Sakamoto

  reply	other threads:[~2020-08-06 14:48 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-08-05 17:31 Why doesn't mixer control (values) have some kind of locking mechanism? (mutex?) Tom Yan
2020-08-05 18:40 ` Pierre-Louis Bossart
2020-08-06  2:06 ` Takashi Sakamoto
2020-08-06  8:57   ` Tom Yan
2020-08-06  9:14     ` Takashi Sakamoto
2020-08-06 12:31       ` Tom Yan
2020-08-06 14:47         ` Takashi Sakamoto [this message]
2020-08-06 15:34           ` Tom Yan
2020-08-06 17:19             ` Takashi Sakamoto
2020-08-06 18:45               ` Tom Yan
2020-08-07  9:08           ` Jaroslav Kysela
2020-08-06 15:30   ` [pulseaudio-discuss] " Pierre-Louis Bossart
2020-08-06 17:47     ` Takashi Sakamoto
2020-08-07  0:12       ` Pierre-Louis Bossart
2020-08-07  2:34         ` Takashi Sakamoto

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200806144729.GA381789@workstation \
    --to=o-takashi@sakamocchi.jp \
    --cc=alsa-devel@alsa-project.org \
    --cc=alsa-user@alsa-project.org \
    --cc=pierre-louis.bossart@linux.intel.com \
    --cc=pulseaudio-discuss@lists.freedesktop.org \
    --cc=tom.ty89@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.