4a-hal-device-config: bump to latest revision
[AGL/meta-agl-devel.git] / meta-audio-4a-framework / recipes-connectivity / bluez-alsa / bluez-alsa / 0004-Fixed-the-SIGSEGV-at-PCM-close.patch
1 From 23a1f554565c0cb9fade1a8f86ab9a09bf3d04e7 Mon Sep 17 00:00:00 2001
2 From: Thierry Bultel <thierry.bultel@iot.bzh>
3 Date: Wed, 26 Dec 2018 10:06:38 +0100
4 Subject: [PATCH] Fixed the SIGSEGV at PCM close
5
6 There is a (still not identified) race condition at PCM
7 close, producing a SIGSEGV when pthread_cancel is called.
8 Instead of proposing a trick with pthread_setcancelstate,
9 this fix introduces a cancellation pipe, on which the io_thread
10 polls. This guaranties a better, safer, exit path.
11
12 Signed-off-by: Thierry Bultel <thierry.bultel@iot.bzh>
13 ---
14  src/asound/bluealsa-pcm.c | 82 +++++++++++++++++++++++++++++++++++++++++------
15  1 file changed, 72 insertions(+), 10 deletions(-)
16
17 diff --git a/src/asound/bluealsa-pcm.c b/src/asound/bluealsa-pcm.c
18 index 2136964..013aebb 100644
19 --- a/src/asound/bluealsa-pcm.c
20 +++ b/src/asound/bluealsa-pcm.c
21 @@ -67,6 +67,8 @@ struct bluealsa_pcm {
22         snd_pcm_uframes_t io_hw_boundary;
23         snd_pcm_uframes_t io_hw_ptr;
24  
25 +       int cancelPipe[2];
26 +
27  };
28  
29  
30 @@ -107,7 +109,9 @@ static void *io_thread(void *arg) {
31         struct asrsync asrs;
32         asrsync_init(&asrs, io->rate);
33  
34 -       debug("Starting IO loop");
35 +       const char * type = io->stream== SND_PCM_STREAM_CAPTURE?"CAPTURE":"PLAYBACK";
36 +
37 +       debug("------------ Starting IO loop (%s)-----------------------", type);
38         for (;;) {
39  
40                 int tmp;
41 @@ -124,6 +128,11 @@ static void *io_thread(void *arg) {
42                         debug("IO thread resumed: %d", io->state);
43                 }
44  
45 +               if (pcm->io_started == false) {
46 +                       debug("io_thread not started -> exit");
47 +                       goto final;
48 +               }
49 +
50                 snd_pcm_uframes_t io_ptr = pcm->io_ptr;
51                 snd_pcm_uframes_t io_buffer_size = io->buffer_size;
52                 snd_pcm_uframes_t io_hw_ptr = pcm->io_hw_ptr;
53 @@ -152,21 +161,44 @@ static void *io_thread(void *arg) {
54                 if (io_hw_ptr >= io_hw_boundary)
55                         io_hw_ptr -= io_hw_boundary;
56  
57 +               struct pollfd fds[2];
58 +
59 +               fds[0].fd = pcm->pcm_fd;
60 +               fds[1].fd = pcm->cancelPipe[0];
61 +
62 +               if (io->stream == SND_PCM_STREAM_CAPTURE)
63 +                       fds[0].events |= POLLIN;
64 +               else
65 +                       fds[0].events |= POLLOUT;
66 +
67 +               fds[1].events = POLLIN | POLLHUP;
68 +
69                 if (io->stream == SND_PCM_STREAM_CAPTURE) {
70  
71                         /* Read the whole period "atomically". This will assure, that frames
72                          * are not fragmented, so the pointer can be correctly updated. */
73 -                       while (len != 0 && (ret = read(pcm->pcm_fd, head, len)) != 0) {
74 +                       while (len != 0 &&
75 +                                       pcm->io_started) {
76 +
77 +                               int pollres = poll(fds, 2, -1);
78 +
79 +                               if ((fds[1].revents & POLLIN) != 0) {
80 +                                       debug("io_thread: CANCELLED");
81 +                                       goto final;
82 +                               }
83 +
84 +                               ret = read(pcm->pcm_fd, head, len);
85                                 if (ret == -1) {
86 -                                       if (errno == EINTR)
87 -                                               continue;
88 +                                       if (errno == EINTR) {
89 +                                               break;
90 +                                       }
91                                         SNDERR("PCM FIFO read error: %s", strerror(errno));
92                                         goto final;
93                                 }
94                                 head += ret;
95                                 len -= ret;
96 -                       }
97  
98 +                       }
99                         if (ret == 0)
100                                 goto final;
101  
102 @@ -182,9 +214,18 @@ static void *io_thread(void *arg) {
103  
104                         /* Perform atomic write - see the explanation above. */
105                         do {
106 +
107 +                               int pollres = poll(fds, 2, -1);
108 +
109 +                               if ((fds[1].revents & POLLIN) != 0) {
110 +                                       debug("io_thread: CANCELLED");
111 +                                       goto final;
112 +                               }
113 +
114                                 if ((ret = write(pcm->pcm_fd, head, len)) == -1) {
115 -                                       if (errno == EINTR)
116 -                                               continue;
117 +                                       if (errno == EINTR) {
118 +                                               break;
119 +                                       }
120                                         SNDERR("PCM FIFO write error: %s", strerror(errno));
121                                         goto final;
122                                 }
123 @@ -251,12 +292,24 @@ static int bluealsa_start(snd_pcm_ioplug_t *io) {
124  
125  static int bluealsa_stop(snd_pcm_ioplug_t *io) {
126         struct bluealsa_pcm *pcm = io->private_data;
127 -       debug("Stopping");
128 +       debug("Stopping %p", pcm);
129 +       if (!pcm) {
130 +               debug("PCM ALREADY CLOSED !");
131 +               return 0;
132 +       }
133         if (pcm->io_started) {
134                 pcm->io_started = false;
135 -               pthread_cancel(pcm->io_thread);
136 +
137 +               char dummy = 0;
138 +
139 +               if (write(pcm->cancelPipe[1], &dummy, sizeof(dummy)) < 0)
140 +                       debug("Failed to write to the cancellation pipe");
141 +
142                 pthread_join(pcm->io_thread, NULL);
143         }
144 +done:
145 +       debug("Stop done");
146 +
147         return 0;
148  }
149  
150 @@ -269,10 +322,14 @@ static snd_pcm_sframes_t bluealsa_pointer(snd_pcm_ioplug_t *io) {
151  
152  static int bluealsa_close(snd_pcm_ioplug_t *io) {
153         struct bluealsa_pcm *pcm = io->private_data;
154 -       debug("Closing plugin");
155 +       debug("Closing plugin %p", pcm);
156         close(pcm->fd);
157         close(pcm->event_fd);
158 +       close(pcm->cancelPipe[0]);
159 +       close(pcm->cancelPipe[1]);
160         free(pcm);
161 +       io->private_data = NULL;
162 +       debug("PCM closed");
163         return 0;
164  }
165  
166 @@ -649,6 +706,11 @@ SND_PCM_PLUGIN_DEFINE_FUNC(bluealsa) {
167         pcm->pcm_fd = -1;
168         pcm->delay_ex = delay;
169  
170 +       if (pipe(pcm->cancelPipe) == -1) {
171 +               SNDERR("BlueALSA failed to create cancellation pipe: %s", strerror(errno));
172 +               ret = -errno;
173 +       }
174 +
175         if ((pcm->fd = bluealsa_open(interface)) == -1) {
176                 SNDERR("BlueALSA connection failed: %s", strerror(errno));
177                 ret = -errno;
178 -- 
179 2.16.4
180