diff mbox

[v2,1/1] ALSA: seq: Continue broadcasting events to ports if one of them fails

Message ID 1401895255-25348-1-git-send-email-agoode@google.com (mailing list archive)
State Accepted
Commit 27423257b7e6b236f0ea40d939e5842f63dac949
Headers show

Commit Message

Adam Goode June 4, 2014, 3:20 p.m. UTC
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>

Comments

Takashi Iwai June 4, 2014, 3:31 p.m. UTC | #1
At Wed,  4 Jun 2014 11:20:55 -0400,
Adam Goode wrote:
> 
> 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>

Applied, thanks.


Takashi


> 
> diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
> index 9ca5e64..225c7315 100644
> --- a/sound/core/seq/seq_clientmgr.c
> +++ b/sound/core/seq/seq_clientmgr.c
> @@ -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;
>  }
>  
>  
> -- 
> 2.0.0.526.g5318336
>
diff mbox

Patch

diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 9ca5e64..225c7315 100644
--- a/sound/core/seq/seq_clientmgr.c
+++ b/sound/core/seq/seq_clientmgr.c
@@ -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;
 }