summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorAdam Goode <agoode@google.com>2014-06-04 11:20:55 -0400
committerTakashi Iwai <tiwai@suse.de>2014-06-04 11:30:58 -0400
commit27423257b7e6b236f0ea40d939e5842f63dac949 (patch)
tree81f44740dc04be0757953c6a1961769d84317915 /sound
parent1c9b8f51251212113a8ed12836dc6ba6a14e8b33 (diff)
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>
Diffstat (limited to 'sound')
-rw-r--r--sound/core/seq/seq_clientmgr.c36
1 files changed, 24 insertions, 12 deletions
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
index 9ca5e647e54b..225c73152ee9 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,
660 int atomic, int hop) 660 int atomic, int hop)
661{ 661{
662 struct snd_seq_subscribers *subs; 662 struct snd_seq_subscribers *subs;
663 int err = 0, num_ev = 0; 663 int err, result = 0, num_ev = 0;
664 struct snd_seq_event event_saved; 664 struct snd_seq_event event_saved;
665 struct snd_seq_client_port *src_port; 665 struct snd_seq_client_port *src_port;
666 struct snd_seq_port_subs_info *grp; 666 struct snd_seq_port_subs_info *grp;
@@ -685,8 +685,12 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
685 subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL); 685 subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);
686 err = snd_seq_deliver_single_event(client, event, 686 err = snd_seq_deliver_single_event(client, event,
687 0, atomic, hop); 687 0, atomic, hop);
688 if (err < 0) 688 if (err < 0) {
689 break; 689 /* save first error that occurs and continue */
690 if (!result)
691 result = err;
692 continue;
693 }
690 num_ev++; 694 num_ev++;
691 /* restore original event record */ 695 /* restore original event record */
692 *event = event_saved; 696 *event = event_saved;
@@ -697,7 +701,7 @@ static int deliver_to_subscribers(struct snd_seq_client *client,
697 up_read(&grp->list_mutex); 701 up_read(&grp->list_mutex);
698 *event = event_saved; /* restore */ 702 *event = event_saved; /* restore */
699 snd_seq_port_unlock(src_port); 703 snd_seq_port_unlock(src_port);
700 return (err < 0) ? err : num_ev; 704 return (result < 0) ? result : num_ev;
701} 705}
702 706
703 707
@@ -709,7 +713,7 @@ static int port_broadcast_event(struct snd_seq_client *client,
709 struct snd_seq_event *event, 713 struct snd_seq_event *event,
710 int atomic, int hop) 714 int atomic, int hop)
711{ 715{
712 int num_ev = 0, err = 0; 716 int num_ev = 0, err, result = 0;
713 struct snd_seq_client *dest_client; 717 struct snd_seq_client *dest_client;
714 struct snd_seq_client_port *port; 718 struct snd_seq_client_port *port;
715 719
@@ -724,14 +728,18 @@ static int port_broadcast_event(struct snd_seq_client *client,
724 err = snd_seq_deliver_single_event(NULL, event, 728 err = snd_seq_deliver_single_event(NULL, event,
725 SNDRV_SEQ_FILTER_BROADCAST, 729 SNDRV_SEQ_FILTER_BROADCAST,
726 atomic, hop); 730 atomic, hop);
727 if (err < 0) 731 if (err < 0) {
728 break; 732 /* save first error that occurs and continue */
733 if (!result)
734 result = err;
735 continue;
736 }
729 num_ev++; 737 num_ev++;
730 } 738 }
731 read_unlock(&dest_client->ports_lock); 739 read_unlock(&dest_client->ports_lock);
732 snd_seq_client_unlock(dest_client); 740 snd_seq_client_unlock(dest_client);
733 event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */ 741 event->dest.port = SNDRV_SEQ_ADDRESS_BROADCAST; /* restore */
734 return (err < 0) ? err : num_ev; 742 return (result < 0) ? result : num_ev;
735} 743}
736 744
737/* 745/*
@@ -741,7 +749,7 @@ static int port_broadcast_event(struct snd_seq_client *client,
741static int broadcast_event(struct snd_seq_client *client, 749static int broadcast_event(struct snd_seq_client *client,
742 struct snd_seq_event *event, int atomic, int hop) 750 struct snd_seq_event *event, int atomic, int hop)
743{ 751{
744 int err = 0, num_ev = 0; 752 int err, result = 0, num_ev = 0;
745 int dest; 753 int dest;
746 struct snd_seq_addr addr; 754 struct snd_seq_addr addr;
747 755
@@ -760,12 +768,16 @@ static int broadcast_event(struct snd_seq_client *client,
760 err = snd_seq_deliver_single_event(NULL, event, 768 err = snd_seq_deliver_single_event(NULL, event,
761 SNDRV_SEQ_FILTER_BROADCAST, 769 SNDRV_SEQ_FILTER_BROADCAST,
762 atomic, hop); 770 atomic, hop);
763 if (err < 0) 771 if (err < 0) {
764 break; 772 /* save first error that occurs and continue */
773 if (!result)
774 result = err;
775 continue;
776 }
765 num_ev += err; 777 num_ev += err;
766 } 778 }
767 event->dest = addr; /* restore */ 779 event->dest = addr; /* restore */
768 return (err < 0) ? err : num_ev; 780 return (result < 0) ? result : num_ev;
769} 781}
770 782
771 783