ALSA: seq: Continue broadcasting events to ports if one of them fails
Sometimes PORT_EXIT messages are lost when a process is exiting. This happens if you subscribe to the announce port with client A, then subscribe to the announce port with client B, then kill client A. Client B will not see the PORT_EXIT message because client A's port is closing and is earlier in the announce port subscription list. The for each loop will try to send the announcement to client A and fail, then will stop trying to broadcast to other ports. Killing B works fine since the announcement will already have gone to A. The CLIENT_EXIT message does not get lost. How to reproduce problem: *** termA $ aseqdump -p 0:1 0:1 Port subscribed 0:1 -> 128:0 *** termB $ aseqdump -p 0:1 *** termA 0:1 Client start client 129 0:1 Port start 129:0 0:1 Port subscribed 0:1 -> 129:0 *** termB 0:1 Port subscribed 0:1 -> 129:0 *** termA ^C *** termB 0:1 Client exit client 128 <--- expected Port exit as well (before client exit) Signed-off-by: Adam Goode <agoode@google.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
1c9b8f5125
commit
27423257b7
|
@ -660,7 +660,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
|
|||
int atomic, int hop)
|
||||
{
|
||||
struct snd_seq_subscribers *subs;
|
||||
int err = 0, num_ev = 0;
|
||||
int err, result = 0, num_ev = 0;
|
||||
struct snd_seq_event event_saved;
|
||||
struct snd_seq_client_port *src_port;
|
||||
struct snd_seq_port_subs_info *grp;
|
||||
|
@ -685,8 +685,12 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
|
|||
subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);
|
||||
err = snd_seq_deliver_single_event(client, event,
|
||||
0, atomic, hop);
|
||||
if (err < 0)
|
||||
break;
|
||||
if (err < 0) {
|
||||
/* save first error that occurs and continue */
|
||||
if (!result)
|
||||
result = err;
|
||||
continue;
|
||||
}
|
||||
num_ev++;
|
||||
/* restore original event record */
|
||||
*event = event_saved;
|
||||
|
@ -697,7 +701,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
|
|||
up_read(&grp->list_mutex);
|
||||
*event = event_saved; /* restore */
|
||||
snd_seq_port_unlock(src_port);
|
||||
return (err < 0) ? err : num_ev;
|
||||
return (result < 0) ? result : num_ev;
|
||||
}
|
||||
|
||||
|
||||
|
@ -709,7 +713,7 @@ static int port_broadcast_event(struct snd_seq_client *client,
|
|||
struct snd_seq_event *event,
|
||||
int atomic, int hop)
|
||||
{
|
||||
int num_ev = 0, err = 0;
|
||||
int num_ev = 0, err, result = 0;
|
||||
struct snd_seq_client *dest_client;
|
||||
struct snd_seq_client_port *port;
|
||||
|
||||
|
@ -724,14 +728,18 @@ static int port_broadcast_event(struct snd_seq_client *client,
|
|||
err = snd_seq_deliver_single_event(NULL, event,
|
||||
SNDRV_SEQ_FILTER_BROADCAST,
|
||||
atomic, hop);
|
||||
if (err < 0)
|
||||
break;
|
||||
if (err < 0) {
|
||||
/* save first error that occurs and continue */
|
||||
if (!result)
|
||||
result = err;
|
||||
continue;
|
||||
}
|
||||
num_ev++;
|
||||
}
|
||||
read_unlock(&dest_client->ports_lock);
|
||||
snd_seq_client_unlock(dest_client);
|
||||
event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */
|
||||
return (err < 0) ? err : num_ev;
|
||||
return (result < 0) ? result : num_ev;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -741,7 +749,7 @@ static int port_broadcast_event(struct snd_seq_client *client,
|
|||
static int broadcast_event(struct snd_seq_client *client,
|
||||
struct snd_seq_event *event, int atomic, int hop)
|
||||
{
|
||||
int err = 0, num_ev = 0;
|
||||
int err, result = 0, num_ev = 0;
|
||||
int dest;
|
||||
struct snd_seq_addr addr;
|
||||
|
||||
|
@ -760,12 +768,16 @@ static int broadcast_event(struct snd_seq_client *client,
|
|||
err = snd_seq_deliver_single_event(NULL, event,
|
||||
SNDRV_SEQ_FILTER_BROADCAST,
|
||||
atomic, hop);
|
||||
if (err < 0)
|
||||
break;
|
||||
if (err < 0) {
|
||||
/* save first error that occurs and continue */
|
||||
if (!result)
|
||||
result = err;
|
||||
continue;
|
||||
}
|
||||
num_ev += err;
|
||||
}
|
||||
event->dest = addr; /* restore */
|
||||
return (err < 0) ? err : num_ev;
|
||||
return (result < 0) ? result : num_ev;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue