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 | ||
