]> code.delx.au - pulseaudio/commitdiff
alsa: Better error handling in mixer rtpoll callback
authorArun Raghavan <arun.raghavan@collabora.co.uk>
Tue, 4 Oct 2011 04:59:03 +0000 (10:29 +0530)
committerArun Raghavan <arun.raghavan@collabora.co.uk>
Tue, 4 Oct 2011 06:59:46 +0000 (12:29 +0530)
This improves the error handling in the mixer rtpoll callback. It avoids
a crash if an error occurs (the rtpoll_item is freed but still
referenced), and specifically makes sure we don't continue trying to
poll the device if the card is disconnected.

src/modules/alsa/alsa-mixer.c

index ec69efcb403d9639504cc1d2d05a9ce11b61ff6d..ebb3b0f1492e7725205471b8e3046e79ff0721ec 100644 (file)
@@ -271,7 +271,7 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) {
     struct pollfd *p;
     unsigned n_fds;
     unsigned short revents = 0;
-    int err;
+    int err, ret = 0;
 
     pd = pa_rtpoll_item_get_userdata(i);
     pa_assert_fp(pd);
@@ -281,17 +281,33 @@ static int rtpoll_work_cb(pa_rtpoll_item *i) {
 
     if ((err = snd_mixer_poll_descriptors_revents(pd->mixer, p, n_fds, &revents)) < 0) {
         pa_log_error("Unable to get poll revent: %s", pa_alsa_strerror(err));
-        pa_rtpoll_item_free(i);
-        return -1;
+        ret = -1;
+        goto fail;
     }
 
     if (revents) {
-        snd_mixer_handle_events(pd->mixer);
-        pa_rtpoll_item_free(i);
-        pa_alsa_set_mixer_rtpoll(pd, pd->mixer, pd->rtpoll);
+        err = snd_mixer_handle_events(pd->mixer);
+
+        if (PA_UNLIKELY(err == -ENODEV)) {
+            /* The card has been disconnected, stop polling */
+            goto fail;
+        } else {
+            /* Success, or at least an error we're likely to recover from */
+            pa_rtpoll_item_free(i);
+            pa_alsa_set_mixer_rtpoll(pd, pd->mixer, pd->rtpoll);
+        }
     }
 
-    return 0;
+    return ret;
+
+fail:
+    pa_rtpoll_item_free(i);
+
+    pd->poll_item = NULL;
+    pd->rtpoll = NULL;
+    pd->mixer = NULL;
+
+    return ret;
 }
 
 int pa_alsa_set_mixer_rtpoll(struct pa_alsa_mixer_pdata *pd, snd_mixer_t *mixer, pa_rtpoll *rtp) {