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)
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);
}
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