From 2fe453d27f41d22f6f7d3804eb603dbb6c8490cc Mon Sep 17 00:00:00 2001 From: Burcu Dogan Date: Tue, 6 Oct 2015 09:23:29 -0700 Subject: [PATCH] exp/sensor: don't block the looper thread indefinitely The sensor package had a deadlock case if it started to poll the events but all sensors have been disabled on the underlying ALooper. Consider the following program: app.Main(func(a app.App) { sensor.Enable(a, sensor.Gyroscope, time.Millisecond) go func() { time.Sleep(5 * time.Second) sensor.Disable(sensor.Gyroscope) time.Sleep(2 * time.Second) sensor.Enable(a, sensor.Gyroscope, time.Millisecond) }() for e := range a.Events() { case sensor.Event: //... } The initial Enable will enable the gyroscope and start polling events from the ALooper. After 5 seconds, the gyroscope will be disabled. ALooper_pollAll(-1, NULL, &events, NULL) will block indefinately because there are no events will be available until another sensor is enabled. After 2 seconds, we will attempt to enable the gyroscope again. But, the underlying thread will be blocked at pollAll and won't be able to make the sensor enabling call on the same thread. In order to overcome this deadlock case, this thread introduces a hard timeout limit during polling. If timeout occurs, the looper thread will be unblocked and select{} statement will be able to handle {enable,disable,close}Signal cases. Fixes golang/go#12501. Change-Id: I35efa2e29057ca37f8ac0f38be8dc59c9b8262b3 Reviewed-on: https://go-review.googlesource.com/15438 Reviewed-by: Hyang-Ah Hana Kim --- exp/sensor/android.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exp/sensor/android.c b/exp/sensor/android.c index dfe4bbf..6f505be 100644 --- a/exp/sensor/android.c +++ b/exp/sensor/android.c @@ -11,6 +11,8 @@ #define GO_ANDROID_SENSOR_LOOPER_ID 100 +#define GO_ANDROID_READ_TIMEOUT_MS 1000 + ASensorEventQueue* queue = NULL; ALooper* looper = NULL; @@ -48,7 +50,7 @@ int GoAndroid_readQueue(int n, int32_t* types, int64_t* timestamps, float* vecto // Try n times read from the event queue. // If anytime timeout occurs, don't retry to read and immediately return. // Consume the event queue entirely between polls. - while (i < n && (id = ALooper_pollAll(-1, NULL, &events, NULL)) >= 0) { + while (i < n && (id = ALooper_pollAll(GO_ANDROID_READ_TIMEOUT_MS, NULL, &events, NULL)) >= 0) { if (id != GO_ANDROID_SENSOR_LOOPER_ID) { continue; }