alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
From: Takashi Iwai <tiwai@suse.de>
To: Andrew Gabbasov <andrew_gabbasov@mentor.com>
Cc: Timo Wischer <twischer@de.adit-jv.com>,
	alsa-devel@alsa-project.org, Takashi Iwai <tiwai@suse.com>,
	linux-kernel@vger.kernel.org
Subject: Re: [alsa-devel] [PATCH v2 7/8] ALSA: aloop: Support selection of snd_timer instead of jiffies
Date: Thu, 07 Nov 2019 09:05:14 +0100	[thread overview]
Message-ID: <s5hlfss862t.wl-tiwai@suse.de> (raw)
In-Reply-To: <20191105143218.5948-8-andrew_gabbasov@mentor.com>

On Tue, 05 Nov 2019 15:32:17 +0100,
Andrew Gabbasov wrote:
> @@ -102,6 +106,13 @@ struct loopback_cable {
>  	unsigned int pause;
>  	/* timer specific */
>  	struct loopback_ops *ops;
> +	/* If sound timer is used */
> +	struct {
> +		int owner;

The term "owner" is a bit confusing here.  It seems holding the PCM
direction, but most people expect it being a process-id or something
like that from the word.

> +		struct snd_timer_id id;
> +		struct tasklet_struct event_tasklet;

You don't need to make own tasklet.  The timer core calls it via
tasklet in anyway unless you pass SNDRV_TIMER_IFLG_FAST -- see below.

And the tasklet is no longer recommended infrastructure in the recent
kernel, we should avoid it as much as possible.

>  struct loopback_setup {
> @@ -122,6 +133,7 @@ struct loopback {
>  	struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2];
>  	struct snd_pcm *pcm[2];
>  	struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2];
> +	char *timer_source;

This can be const char *, I suppose.

> +static void loopback_snd_timer_period_elapsed(
> +		struct loopback_cable * const cable,
> +		const int event, const unsigned long resolution)
> +{
> +	struct loopback_pcm *dpcm_play =
> +			cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
> +	struct loopback_pcm *dpcm_capt =
> +			cable->streams[SNDRV_PCM_STREAM_CAPTURE];

You shouldn't assign them outside the cable->lock.

> +	struct snd_pcm_runtime *valid_runtime;
> +	unsigned int running, elapsed_bytes;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&cable->lock, flags);
> +	running = cable->running ^ cable->pause;
> +	/* no need to do anything if no stream is running */
> +	if (!running) {
> +		spin_unlock_irqrestore(&cable->lock, flags);
> +		return;
> +	}
> +
> +	if (event == SNDRV_TIMER_EVENT_MSTOP) {
> +		if (!dpcm_play || !dpcm_play->substream ||
> +		    !dpcm_play->substream->runtime ||
> +		    !dpcm_play->substream->runtime->status ||

Would these conditions really happen?

> +		    dpcm_play->substream->runtime->status->state !=
> +		    SNDRV_PCM_STATE_DRAINING) {

What's special with DRAINING state?  The code doesn't show or explain
it.  And for other conditions, we keep going even if the event is
MSTOP?

> +			spin_unlock_irqrestore(&cable->lock, flags);
> +			return;
> +		}
> +	}
> +
> +	valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
> +				dpcm_play->substream->runtime :
> +				dpcm_capt->substream->runtime;
> +
> +	/* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */
> +	if (event == SNDRV_TIMER_EVENT_TICK) {
> +		/* The hardware rules guarantee that playback and capture period
> +		 * are the same. Therefore only one device has to be checked
> +		 * here.
> +		 */
> +		if (loopback_snd_timer_check_resolution(valid_runtime,
> +							resolution) < 0) {
> +			spin_unlock_irqrestore(&cable->lock, flags);
> +			if (cable->running & (1 << SNDRV_PCM_STREAM_PLAYBACK))
> +				snd_pcm_stop_xrun(dpcm_play->substream);
> +			if (cable->running & (1 << SNDRV_PCM_STREAM_CAPTURE))
> +				snd_pcm_stop_xrun(dpcm_capt->substream);

Referencing outside the lock isn't really safe.  In the case of
jiffies timer code, it's a kind of OK because it's done in the timer
callback function that is assigned for each stream open -- that is,
the stream runtime is guaranteed to be present in the timer callback.
But I'm not sure about your case...


> @@ -749,6 +1037,152 @@ static struct loopback_ops loopback_jiffies_timer_ops = {
>  	.dpcm_info = loopback_jiffies_timer_dpcm_info,
>  };
>  
> +static int loopback_parse_timer_id(const char * const str,
> +				   struct snd_timer_id *tid)
> +{
> +	/* [<pref>:](<card name>|<card idx>)[{.,}<dev idx>[{.,}<subdev idx>]] */
> +	const char * const sep_dev = ".,";
> +	const char * const sep_pref = ":";
> +	const char *name = str;
> +	char save, *sep;
> +	int card = 0, device = 0, subdevice = 0;
> +	int err;
> +
> +	sep = strpbrk(str, sep_pref);
> +	if (sep)
> +		name = sep + 1;
> +	sep = strpbrk(name, sep_dev);
> +	if (sep) {
> +		save = *sep;
> +		*sep = '\0';
> +	}
> +	err = kstrtoint(name, 0, &card);
> +	if (err == -EINVAL) {
> +		/* Must be the name, not number */
> +		for (card = 0; card < snd_ecards_limit; card++) {
> +			if (snd_cards[card] &&
> +			    !strcmp(snd_cards[card]->id, name)) {
> +				err = 0;
> +				break;
> +			}
> +		}
> +	}

As kbuildbot reported, this is obviously broken with the recent
kernel.  snd_cards[] is no longer exported!  And I don't want to
export again.

IOW, if we need this kind of thing, it's better to modify the existing
code in sound/core/init.c and export that function.

> +/* call in loopback->cable_lock */
> +static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
> +{
> +	int err = 0;
> +	unsigned long flags;
> +	struct snd_timer_id tid = {
> +		.dev_class = SNDRV_TIMER_CLASS_PCM,
> +		.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION,
> +	};
> +	struct snd_timer_instance *timer = NULL;

Why initialing to NULL here?

> +	spin_lock_irqsave(&dpcm->cable->lock, flags);

You need no irqsave version but spin_lock_irq() for the context like
open/close that is guaranteed to be sleepable.

> +	spin_lock_irqsave(&dpcm->cable->lock, flags);
> +
> +	/* The callback has to be called from another tasklet. If
> +	 * SNDRV_TIMER_IFLG_FAST is specified it will be called from the
> +	 * snd_pcm_period_elapsed() call of the selected sound card.

Well, you're the one who specifies SNDRV_TIMER_IFLG_XXX, so you know
that the flag isn't set.  So tasklet makes little sense.

> +	 * snd_pcm_period_elapsed() helds snd_pcm_stream_lock_irqsave().
> +	 * Due to our callback loopback_snd_timer_function() also calls
> +	 * snd_pcm_period_elapsed() which calls snd_pcm_stream_lock_irqsave().
> +	 * This would end up in a dead lock.
> +	 */
> +	timer->flags |= SNDRV_TIMER_IFLG_AUTO;
> +	timer->callback = loopback_snd_timer_function;
> +	timer->callback_data = (void *)dpcm->cable;
> +	timer->ccallback = loopback_snd_timer_event;

This reminds me that we need a safer way to assign these stuff in
general...  But it's above this patch set, in anyway.


thanks,

Takashi
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

  parent reply	other threads:[~2019-11-07  8:06 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-05 14:32 [alsa-devel] [PATCH v2 0/8] ALSA: aloop: Support sound timer as clock source instead of jiffies Andrew Gabbasov
2019-11-05 14:32 ` [alsa-devel] [PATCH v2 1/8] ALSA: aloop: Describe units of variables Andrew Gabbasov
2019-11-05 14:32   ` [alsa-devel] [PATCH v2 2/8] ALSA: aloop: loopback_timer_start: Support return of error code Andrew Gabbasov
2019-11-05 14:32     ` [alsa-devel] [PATCH v2 3/8] ALSA: aloop: loopback_timer_stop: " Andrew Gabbasov
2019-11-05 14:32       ` [alsa-devel] [PATCH v2 4/8] ALSA: aloop: Use callback functions for timer specific implementations Andrew Gabbasov
2019-11-05 14:32         ` [alsa-devel] [PATCH v2 5/8] ALSA: aloop: Rename all jiffies timer specific functions Andrew Gabbasov
2019-11-05 14:32           ` [alsa-devel] [PATCH v2 6/8] ALSA: aloop: Move CABLE_VALID_BOTH to the top of file Andrew Gabbasov
2019-11-05 14:32             ` [alsa-devel] [PATCH v2 7/8] ALSA: aloop: Support selection of snd_timer instead of jiffies Andrew Gabbasov
2019-11-05 14:32               ` [alsa-devel] [PATCH v2 8/8] ALSA: aloop: Support runtime change of snd_timer via info interface Andrew Gabbasov
2019-11-07  8:06                 ` Takashi Iwai
2019-11-07 10:40                   ` Gabbasov, Andrew
2019-11-07 10:50                     ` Takashi Iwai
2019-11-06  0:43               ` [alsa-devel] [PATCH v2 7/8] ALSA: aloop: Support selection of snd_timer instead of jiffies kbuild test robot
2019-11-06 21:25               ` kbuild test robot
2019-11-07  8:05               ` Takashi Iwai [this message]
2019-11-08 18:09                 ` Andrew Gabbasov
2019-11-11 11:17                 ` Andrew Gabbasov
2019-11-06 15:51       ` [alsa-devel] [PATCH v2 3/8] ALSA: aloop: loopback_timer_stop: Support return of error code Takashi Iwai
2019-11-06 17:45         ` Andrew Gabbasov
2019-11-06 15:50     ` [alsa-devel] [PATCH v2 2/8] ALSA: aloop: loopback_timer_start: " Takashi Iwai

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=s5hlfss862t.wl-tiwai@suse.de \
    --to=tiwai@suse.de \
    --cc=alsa-devel@alsa-project.org \
    --cc=andrew_gabbasov@mentor.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=tiwai@suse.com \
    --cc=twischer@de.adit-jv.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).