diff options
author | Adam Goode <agoode@google.com> | 2014-06-04 11:20:55 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-06-04 11:30:58 -0400 |
commit | 27423257b7e6b236f0ea40d939e5842f63dac949 (patch) | |
tree | 81f44740dc04be0757953c6a1961769d84317915 /sound | |
parent | 1c9b8f51251212113a8ed12836dc6ba6a14e8b33 (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.c | 36 |
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, | |||
741 | static int broadcast_event(struct snd_seq_client *client, | 749 | static 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 | ||