2015-03-30 11:53:15 -07:00
|
|
|
// Copyright 2015 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2015-08-12 10:16:13 -07:00
|
|
|
// +build android
|
|
|
|
|
2015-03-30 11:53:15 -07:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <jni.h>
|
|
|
|
|
|
|
|
#include <android/sensor.h>
|
|
|
|
|
2015-09-04 00:17:01 -07:00
|
|
|
#define GO_ANDROID_SENSOR_LOOPER_ID 100
|
2015-03-30 11:53:15 -07:00
|
|
|
|
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 <hyangah@gmail.com>
2015-10-06 09:23:29 -07:00
|
|
|
#define GO_ANDROID_READ_TIMEOUT_MS 1000
|
|
|
|
|
2015-09-04 00:17:01 -07:00
|
|
|
ASensorEventQueue* queue = NULL;
|
|
|
|
ALooper* looper = NULL;
|
2015-03-30 11:53:15 -07:00
|
|
|
|
2015-09-04 00:17:01 -07:00
|
|
|
void GoAndroid_createManager() {
|
|
|
|
ASensorManager* manager = ASensorManager_getInstance();
|
|
|
|
looper = ALooper_forThread();
|
2015-03-30 11:53:15 -07:00
|
|
|
if (looper == NULL) {
|
|
|
|
looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
|
|
|
|
}
|
2015-09-04 00:17:01 -07:00
|
|
|
queue = ASensorManager_createEventQueue(manager, looper, GO_ANDROID_SENSOR_LOOPER_ID, NULL, NULL);
|
2015-03-30 11:53:15 -07:00
|
|
|
}
|
|
|
|
|
2015-09-04 00:17:01 -07:00
|
|
|
int GoAndroid_enableSensor(int s, int32_t usec) {
|
2015-03-30 11:53:15 -07:00
|
|
|
ASensorManager* manager = ASensorManager_getInstance();
|
|
|
|
const ASensor* sensor = ASensorManager_getDefaultSensor(manager, s);
|
|
|
|
if (sensor == NULL) {
|
|
|
|
return 1;
|
|
|
|
}
|
2015-09-04 00:17:01 -07:00
|
|
|
ASensorEventQueue_enableSensor(queue, sensor);
|
|
|
|
ASensorEventQueue_setEventRate(queue, sensor, usec);
|
2015-03-30 11:53:15 -07:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-09-04 00:17:01 -07:00
|
|
|
void GoAndroid_disableSensor(int s) {
|
2015-03-30 11:53:15 -07:00
|
|
|
ASensorManager* manager = ASensorManager_getInstance();
|
|
|
|
const ASensor* sensor = ASensorManager_getDefaultSensor(manager, s);
|
2015-09-04 00:17:01 -07:00
|
|
|
ASensorEventQueue_disableSensor(queue, sensor);
|
2015-03-30 11:53:15 -07:00
|
|
|
}
|
|
|
|
|
2015-09-04 00:17:01 -07:00
|
|
|
int GoAndroid_readQueue(int n, int32_t* types, int64_t* timestamps, float* vectors) {
|
2015-03-30 11:53:15 -07:00
|
|
|
int id;
|
|
|
|
int events;
|
|
|
|
ASensorEvent event;
|
2015-04-07 15:56:44 -04:00
|
|
|
int i = 0;
|
2015-04-07 17:19:45 -04:00
|
|
|
// 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.
|
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 <hyangah@gmail.com>
2015-10-06 09:23:29 -07:00
|
|
|
while (i < n && (id = ALooper_pollAll(GO_ANDROID_READ_TIMEOUT_MS, NULL, &events, NULL)) >= 0) {
|
2015-09-04 00:17:01 -07:00
|
|
|
if (id != GO_ANDROID_SENSOR_LOOPER_ID) {
|
2015-03-30 11:53:15 -07:00
|
|
|
continue;
|
|
|
|
}
|
2015-09-04 00:17:01 -07:00
|
|
|
while (i < n && ASensorEventQueue_getEvents(queue, &event, 1)) {
|
2015-04-07 15:56:44 -04:00
|
|
|
types[i] = event.type;
|
|
|
|
timestamps[i] = event.timestamp;
|
|
|
|
vectors[i*3] = event.vector.x;
|
|
|
|
vectors[i*3+1] = event.vector.y;
|
|
|
|
vectors[i*3+2] = event.vector.z;
|
|
|
|
i++;
|
2015-03-30 11:53:15 -07:00
|
|
|
}
|
|
|
|
}
|
2015-04-07 15:56:44 -04:00
|
|
|
return i;
|
2015-03-30 11:53:15 -07:00
|
|
|
}
|
|
|
|
|
2015-09-04 00:17:01 -07:00
|
|
|
void GoAndroid_destroyManager() {
|
2015-03-30 11:53:15 -07:00
|
|
|
ASensorManager* manager = ASensorManager_getInstance();
|
2015-09-04 00:17:01 -07:00
|
|
|
ASensorManager_destroyEventQueue(manager, queue);
|
2015-10-06 15:14:36 -07:00
|
|
|
queue = NULL;
|
|
|
|
looper = NULL;
|
2015-03-30 11:53:15 -07:00
|
|
|
}
|