[PATCH] ALSA: pcm: accept the OPEN state for snd_pcm_stop()

Takashi Iwai tiwai at suse.de
Thu Jan 13 13:56:21 CET 2022


On Thu, 13 Jan 2022 12:31:30 +0100,
Jaroslav Kysela wrote:
> 
> It may be useful to completely invalidate streaming under some
> circumstances like the USB gadget detach. This case is a bit different
> than the complete disconnection. The applications should be notified
> that the PCM streaming is no longer available, but the recovery may be
> expected.
> 
> This patch adds support for SNDRV_PCM_STATE_OPEN passed
> to snd_pcm_stop() function. Only the hw_free ioctl is allowed to free
> the buffers in this state for a full recovery operation or the PCM file
> handle must be closed.
> 
> In the OPEN state, ioctls return EBADFD error (with the added hw_free
> exception above). The applications which are not aware about this new
> state transition (and recovery) will fail with an error. This operation
> is expected.
> 
> Link: https://lore.kernel.org/alsa-devel/4e17c99b-1d8a-8ebe-972c-9b1299952ff8@ivitera.com/
> Cc: Pavel Hofman <pavel.hofman at ivitera.com>
> Signed-off-by: Jaroslav Kysela <perex at perex.cz>

I find the idea neat, but I'm afraid that it's a bit confusing from
the user POV as is.  Namely, the state is in OPEN, but you'd have to
perform hw_free manually at first for moving forward; how can user
know it?  Maybe PCM core should do hw_free by itself when hw_params is
called with hw_free_queued.

Also, do_hw_free() will skip the actual free because it's in OPEN
state, no?

In anyway, this doesn't look like a 5.17 material, so we still have
some time to stew more.


thanks,

Takashi

> ---
>  include/sound/pcm.h     |  1 +
>  sound/core/pcm.c        |  1 +
>  sound/core/pcm_native.c | 12 +++++++++++-
>  3 files changed, 13 insertions(+), 1 deletion(-)
> 
> diff --git a/include/sound/pcm.h b/include/sound/pcm.h
> index 33451f8ff755..4de1c2c91109 100644
> --- a/include/sound/pcm.h
> +++ b/include/sound/pcm.h
> @@ -467,6 +467,7 @@ struct snd_pcm_substream {
>  	/* -- assigned files -- */
>  	int ref_count;
>  	atomic_t mmap_count;
> +	atomic_t queued_hw_free;
>  	unsigned int f_flags;
>  	void (*pcm_release)(struct snd_pcm_substream *);
>  	struct pid *pid;
> diff --git a/sound/core/pcm.c b/sound/core/pcm.c
> index 6fd3677685d7..8dc7e99b2113 100644
> --- a/sound/core/pcm.c
> +++ b/sound/core/pcm.c
> @@ -694,6 +694,7 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
>  		snd_pcm_group_init(&substream->self_group);
>  		list_add_tail(&substream->link_list, &substream->self_group.substreams);
>  		atomic_set(&substream->mmap_count, 0);
> +		atomic_set(&substream->queued_hw_free, 0);
>  		prev = substream;
>  	}
>  	return 0;
> diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
> index 621883e71194..118ad3f26f4a 100644
> --- a/sound/core/pcm_native.c
> +++ b/sound/core/pcm_native.c
> @@ -686,10 +686,13 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
>  	snd_pcm_stream_lock_irq(substream);
>  	switch (runtime->status->state) {
>  	case SNDRV_PCM_STATE_OPEN:
> +		if (atomic_read(&substream->queued_hw_free))
> +			goto __badfd;
>  	case SNDRV_PCM_STATE_SETUP:
>  	case SNDRV_PCM_STATE_PREPARED:
>  		break;
>  	default:
> +__badfd:
>  		snd_pcm_stream_unlock_irq(substream);
>  		return -EBADFD;
>  	}
> @@ -829,6 +832,7 @@ static int do_hw_free(struct snd_pcm_substream *substream)
>  		result = substream->ops->hw_free(substream);
>  	if (substream->managed_buffer_alloc)
>  		snd_pcm_lib_free_pages(substream);
> +	atomic_set(&substream->queued_hw_free, 0);
>  	return result;
>  }
>  
> @@ -1454,6 +1458,8 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream,
>  	}
>  	wake_up(&runtime->sleep);
>  	wake_up(&runtime->tsleep);
> +	if (state == SNDRV_PCM_STATE_OPEN)
> +		atomic_set(&substream->queued_hw_free, 1);
>  }
>  
>  static const struct action_ops snd_pcm_action_stop = {
> @@ -1469,6 +1475,9 @@ static const struct action_ops snd_pcm_action_stop = {
>   *
>   * The state of each stream is then changed to the given state unconditionally.
>   *
> + * If the requested state is OPEN, the stream is invalidated and
> + * the application must call hw_free to recover the operation.
> + *
>   * Return: Zero if successful, or a negative error code.
>   */
>  int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
> @@ -2637,7 +2646,8 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
>  
>  	snd_pcm_drop(substream);
>  	if (substream->hw_opened) {
> -		if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
> +		if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN ||
> +		    atomic_read(&substream->queued_hw_free))
>  			do_hw_free(substream);
>  		substream->ops->close(substream);
>  		substream->hw_opened = 0;
> -- 
> 2.33.1
> 


More information about the Alsa-devel mailing list