ALSA: pcm: Make PCM linked list consistent while re-grouping
authorTakashi Iwai <tiwai@suse.de>
Sun, 13 Jan 2019 08:40:21 +0000 (09:40 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 21 Jan 2019 15:39:54 +0000 (16:39 +0100)
Make a common helper to re-assign the PCM link using list_move() instead
of open code with manual list_del() and list_add_tail().  This assures
the consistency and we can get rid of snd_pcm_group.count field -- its
purpose is only to check whether the list is singular, and we can know
it by list_is_singular() call now.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
include/sound/pcm.h
sound/core/pcm_native.c

index d6bd3ca..e1c747c 100644 (file)
@@ -439,7 +439,6 @@ struct snd_pcm_group {              /* keep linked substreams */
        spinlock_t lock;
        struct mutex mutex;
        struct list_head substreams;
-       int count;
 };
 
 struct pid;
index 9e4e289..1a56bb1 100644 (file)
@@ -1131,6 +1131,13 @@ static int snd_pcm_action_single(const struct action_ops *ops,
        return res;
 }
 
+static void snd_pcm_group_assign(struct snd_pcm_substream *substream,
+                                struct snd_pcm_group *new_group)
+{
+       substream->group = new_group;
+       list_move(&substream->link_list, &new_group->substreams);
+}
+
 /*
  *  Note: call with stream lock
  */
@@ -1995,14 +2002,10 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
                goto _end;
        }
        if (!snd_pcm_stream_linked(substream)) {
-               substream->group = group;
+               snd_pcm_group_assign(substream, group);
                group = NULL;
-               list_add_tail(&substream->link_list, &substream->group->substreams);
-               substream->group->count = 1;
        }
-       list_add_tail(&substream1->link_list, &substream->group->substreams);
-       substream->group->count++;
-       substream1->group = substream->group;
+       snd_pcm_group_assign(substream1, substream->group);
  _end:
        write_unlock_irq(&snd_pcm_link_rwlock);
        up_write(&snd_pcm_link_rwsem);
@@ -2015,14 +2018,13 @@ static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
 
 static void relink_to_local(struct snd_pcm_substream *substream)
 {
-       substream->group = &substream->self_group;
-       INIT_LIST_HEAD(&substream->self_group.substreams);
-       list_add_tail(&substream->link_list, &substream->self_group.substreams);
+       snd_pcm_group_assign(substream, &substream->self_group);
 }
 
 static int snd_pcm_unlink(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_substream *s;
+       struct snd_pcm_group *group;
        int res = 0;
 
        down_write_nonfifo(&snd_pcm_link_rwsem);
@@ -2031,16 +2033,20 @@ static int snd_pcm_unlink(struct snd_pcm_substream *substream)
                res = -EALREADY;
                goto _end;
        }
-       list_del(&substream->link_list);
-       substream->group->count--;
-       if (substream->group->count == 1) {     /* detach the last stream, too */
+
+       group = substream->group;
+
+       relink_to_local(substream);
+
+       /* detach the last stream, too */
+       if (list_is_singular(&group->substreams)) {
                snd_pcm_group_for_each_entry(s, substream) {
                        relink_to_local(s);
                        break;
                }
-               kfree(substream->group);
+               kfree(group);
        }
-       relink_to_local(substream);
+
        _end:
        write_unlock_irq(&snd_pcm_link_rwlock);
        up_write(&snd_pcm_link_rwsem);