ALSA: seq: prioq: Unify cell removal functions
authorTakashi Iwai <tiwai@suse.de>
Thu, 22 Feb 2024 13:21:52 +0000 (14:21 +0100)
committerTakashi Iwai <tiwai@suse.de>
Thu, 22 Feb 2024 16:27:18 +0000 (17:27 +0100)
Both snd_seq_prioq_remove_events() and snd_seq_prioq_leave() have a
very similar loop for removing events.  Unify them with a callback for
code simplification.

Only the code refactoring, and no functional changes.

Link: https://lore.kernel.org/r/20240222132152.29063-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/core/seq/seq_prioq.c

index 1d857981e8764ce506df3457e97ce44eddb593fa..e062df7610e1d0bfcf7d8421cdd174b2ad048b0a 100644 (file)
@@ -249,30 +249,11 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
        return f->cells;
 }
 
-static inline int prioq_match(struct snd_seq_event_cell *cell,
-                             int client, int timestamp)
-{
-       if (cell->event.source.client == client ||
-           cell->event.dest.client == client)
-               return 1;
-       if (!timestamp)
-               return 0;
-       switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
-       case SNDRV_SEQ_TIME_STAMP_TICK:
-               if (cell->event.time.tick)
-                       return 1;
-               break;
-       case SNDRV_SEQ_TIME_STAMP_REAL:
-               if (cell->event.time.time.tv_sec ||
-                   cell->event.time.time.tv_nsec)
-                       return 1;
-               break;
-       }
-       return 0;
-}
-
-/* remove cells for left client */
-void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
+/* remove cells matching with the condition */
+static void prioq_remove_cells(struct snd_seq_prioq *f,
+                              bool (*match)(struct snd_seq_event_cell *cell,
+                                            void *arg),
+                              void *arg)
 {
        register struct snd_seq_event_cell *cell, *next;
        unsigned long flags;
@@ -281,39 +262,29 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
 
        /* collect all removed cells */
        spin_lock_irqsave(&f->lock, flags);
-       cell = f->head;
-       while (cell) {
+       for (cell = f->head; cell; cell = next) {
                next = cell->next;
-               if (prioq_match(cell, client, timestamp)) {
-                       /* remove cell from prioq */
-                       if (cell == f->head) {
-                               f->head = cell->next;
-                       } else {
-                               prev->next = cell->next;
-                       }
-                       if (cell == f->tail)
-                               f->tail = cell->next;
-                       f->cells--;
-                       /* add cell to free list */
-                       cell->next = NULL;
-                       if (freefirst == NULL) {
-                               freefirst = cell;
-                       } else {
-                               freeprev->next = cell;
-                       }
-                       freeprev = cell;
-               } else {
-#if 0
-                       pr_debug("ALSA: seq: type = %i, source = %i, dest = %i, "
-                              "client = %i\n",
-                               cell->event.type,
-                               cell->event.source.client,
-                               cell->event.dest.client,
-                               client);
-#endif
+               if (!match(cell, arg)) {
                        prev = cell;
+                       continue;
                }
-               cell = next;            
+
+               /* remove cell from prioq */
+               if (cell == f->head)
+                       f->head = cell->next;
+               else
+                       prev->next = cell->next;
+               if (cell == f->tail)
+                       f->tail = cell->next;
+               f->cells--;
+
+               /* add cell to free list */
+               cell->next = NULL;
+               if (freefirst == NULL)
+                       freefirst = cell;
+               else
+                       freeprev->next = cell;
+               freeprev = cell;
        }
        spin_unlock_irqrestore(&f->lock, flags);        
 
@@ -325,22 +296,68 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
        }
 }
 
-static int prioq_remove_match(struct snd_seq_remove_events *info,
-                             struct snd_seq_event *ev)
+struct prioq_match_arg {
+       int client;
+       int timestamp;
+};
+
+static inline bool prioq_match(struct snd_seq_event_cell *cell, void *arg)
+{
+       struct prioq_match_arg *v = arg;
+
+       if (cell->event.source.client == v->client ||
+           cell->event.dest.client == v->client)
+               return true;
+       if (!v->timestamp)
+               return false;
+       switch (cell->event.flags & SNDRV_SEQ_TIME_STAMP_MASK) {
+       case SNDRV_SEQ_TIME_STAMP_TICK:
+               if (cell->event.time.tick)
+                       return true;
+               break;
+       case SNDRV_SEQ_TIME_STAMP_REAL:
+               if (cell->event.time.time.tv_sec ||
+                   cell->event.time.time.tv_nsec)
+                       return true;
+               break;
+       }
+       return false;
+}
+
+/* remove cells for left client */
+void snd_seq_prioq_leave(struct snd_seq_prioq *f, int client, int timestamp)
 {
+       struct prioq_match_arg arg = { client, timestamp };
+
+       return prioq_remove_cells(f, prioq_match, &arg);
+}
+
+struct prioq_remove_match_arg {
+       int client;
+       struct snd_seq_remove_events *info;
+};
+
+static bool prioq_remove_match(struct snd_seq_event_cell *cell, void *arg)
+{
+       struct prioq_remove_match_arg *v = arg;
+       struct snd_seq_event *ev = &cell->event;
+       struct snd_seq_remove_events *info = v->info;
        int res;
 
+       if (ev->source.client != v->client)
+               return false;
+
        if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) {
                if (ev->dest.client != info->dest.client ||
                                ev->dest.port != info->dest.port)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) {
                if (! snd_seq_ev_is_channel_type(ev))
-                       return 0;
+                       return false;
                /* data.note.channel and data.control.channel are identical */
                if (ev->data.note.channel != info->channel)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_AFTER) {
                if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
@@ -348,7 +365,7 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
                else
                        res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
                if (!res)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) {
                if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
@@ -356,81 +373,35 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
                else
                        res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
                if (res)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) {
                if (ev->type != info->type)
-                       return 0;
+                       return false;
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) {
                /* Do not remove off events */
                switch (ev->type) {
                case SNDRV_SEQ_EVENT_NOTEOFF:
                /* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */
-                       return 0;
+                       return false;
                default:
                        break;
                }
        }
        if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) {
                if (info->tag != ev->tag)
-                       return 0;
+                       return false;
        }
 
-       return 1;
+       return true;
 }
 
 /* remove cells matching remove criteria */
 void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client,
                                 struct snd_seq_remove_events *info)
 {
-       struct snd_seq_event_cell *cell, *next;
-       unsigned long flags;
-       struct snd_seq_event_cell *prev = NULL;
-       struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
+       struct prioq_remove_match_arg arg = { client, info };
 
-       /* collect all removed cells */
-       spin_lock_irqsave(&f->lock, flags);
-       cell = f->head;
-
-       while (cell) {
-               next = cell->next;
-               if (cell->event.source.client == client &&
-                       prioq_remove_match(info, &cell->event)) {
-
-                       /* remove cell from prioq */
-                       if (cell == f->head) {
-                               f->head = cell->next;
-                       } else {
-                               prev->next = cell->next;
-                       }
-
-                       if (cell == f->tail)
-                               f->tail = cell->next;
-                       f->cells--;
-
-                       /* add cell to free list */
-                       cell->next = NULL;
-                       if (freefirst == NULL) {
-                               freefirst = cell;
-                       } else {
-                               freeprev->next = cell;
-                       }
-
-                       freeprev = cell;
-               } else {
-                       prev = cell;
-               }
-               cell = next;            
-       }
-       spin_unlock_irqrestore(&f->lock, flags);        
-
-       /* remove selected cells */
-       while (freefirst) {
-               freenext = freefirst->next;
-               snd_seq_cell_free(freefirst);
-               freefirst = freenext;
-       }
+       return prioq_remove_cells(f, prioq_remove_match, &arg);
 }
-
-