Commit ec89fc1b authored by Takashi Iwai's avatar Takashi Iwai

ALSA: seq: prioq: Unify cell removal functions

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.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent bc80e83e
...@@ -249,30 +249,11 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f) ...@@ -249,30 +249,11 @@ int snd_seq_prioq_avail(struct snd_seq_prioq * f)
return f->cells; return f->cells;
} }
static inline int prioq_match(struct snd_seq_event_cell *cell, /* remove cells matching with the condition */
int client, int timestamp) static void prioq_remove_cells(struct snd_seq_prioq *f,
{ bool (*match)(struct snd_seq_event_cell *cell,
if (cell->event.source.client == client || void *arg),
cell->event.dest.client == client) void *arg)
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)
{ {
register struct snd_seq_event_cell *cell, *next; register struct snd_seq_event_cell *cell, *next;
unsigned long flags; unsigned long flags;
...@@ -281,39 +262,29 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp) ...@@ -281,39 +262,29 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp)
/* collect all removed cells */ /* collect all removed cells */
spin_lock_irqsave(&f->lock, flags); spin_lock_irqsave(&f->lock, flags);
cell = f->head; for (cell = f->head; cell; cell = next) {
while (cell) {
next = cell->next; next = cell->next;
if (prioq_match(cell, client, timestamp)) { if (!match(cell, arg)) {
/* 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
prev = cell; 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); spin_unlock_irqrestore(&f->lock, flags);
...@@ -325,22 +296,68 @@ void snd_seq_prioq_leave(struct snd_seq_prioq * f, int client, int timestamp) ...@@ -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 prioq_match_arg {
struct snd_seq_event *ev) 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; int res;
if (ev->source.client != v->client)
return false;
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) { if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) {
if (ev->dest.client != info->dest.client || if (ev->dest.client != info->dest.client ||
ev->dest.port != info->dest.port) ev->dest.port != info->dest.port)
return 0; return false;
} }
if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) { if (info->remove_mode & SNDRV_SEQ_REMOVE_DEST_CHANNEL) {
if (! snd_seq_ev_is_channel_type(ev)) if (! snd_seq_ev_is_channel_type(ev))
return 0; return false;
/* data.note.channel and data.control.channel are identical */ /* data.note.channel and data.control.channel are identical */
if (ev->data.note.channel != info->channel) 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_AFTER) {
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK) if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
...@@ -348,7 +365,7 @@ static int prioq_remove_match(struct snd_seq_remove_events *info, ...@@ -348,7 +365,7 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
else else
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time); res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
if (!res) if (!res)
return 0; return false;
} }
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) { if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_BEFORE) {
if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK) if (info->remove_mode & SNDRV_SEQ_REMOVE_TIME_TICK)
...@@ -356,81 +373,35 @@ static int prioq_remove_match(struct snd_seq_remove_events *info, ...@@ -356,81 +373,35 @@ static int prioq_remove_match(struct snd_seq_remove_events *info,
else else
res = snd_seq_compare_real_time(&ev->time.time, &info->time.time); res = snd_seq_compare_real_time(&ev->time.time, &info->time.time);
if (res) if (res)
return 0; return false;
} }
if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) { if (info->remove_mode & SNDRV_SEQ_REMOVE_EVENT_TYPE) {
if (ev->type != info->type) if (ev->type != info->type)
return 0; return false;
} }
if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) { if (info->remove_mode & SNDRV_SEQ_REMOVE_IGNORE_OFF) {
/* Do not remove off events */ /* Do not remove off events */
switch (ev->type) { switch (ev->type) {
case SNDRV_SEQ_EVENT_NOTEOFF: case SNDRV_SEQ_EVENT_NOTEOFF:
/* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */ /* case SNDRV_SEQ_EVENT_SAMPLE_STOP: */
return 0; return false;
default: default:
break; break;
} }
} }
if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) { if (info->remove_mode & SNDRV_SEQ_REMOVE_TAG_MATCH) {
if (info->tag != ev->tag) if (info->tag != ev->tag)
return 0; return false;
} }
return 1; return true;
} }
/* remove cells matching remove criteria */ /* remove cells matching remove criteria */
void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client, void snd_seq_prioq_remove_events(struct snd_seq_prioq * f, int client,
struct snd_seq_remove_events *info) struct snd_seq_remove_events *info)
{ {
struct snd_seq_event_cell *cell, *next; struct prioq_remove_match_arg arg = { client, info };
unsigned long flags;
struct snd_seq_event_cell *prev = NULL;
struct snd_seq_event_cell *freefirst = NULL, *freeprev = NULL, *freenext;
/* collect all removed cells */ return prioq_remove_cells(f, prioq_remove_match, &arg);
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;
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment