am 3922484d: Merge "Optimize EventHub reads." into gingerbread

Merge commit '3922484d7458a4ab72fc1ca8952a0776dd1c7d20' into gingerbread-plus-aosp

* commit '3922484d7458a4ab72fc1ca8952a0776dd1c7d20':
  Optimize EventHub reads.
This commit is contained in:
Jeff Brown
2010-08-18 13:37:44 -07:00
committed by Android Git Automerger
2 changed files with 97 additions and 71 deletions

View File

@@ -267,6 +267,12 @@ private:
#ifdef EV_SW #ifdef EV_SW
int32_t mSwitches[SW_MAX + 1]; int32_t mSwitches[SW_MAX + 1];
#endif #endif
static const int INPUT_BUFFER_SIZE = 64;
struct input_event mInputBufferData[INPUT_BUFFER_SIZE];
int32_t mInputBufferIndex;
int32_t mInputBufferCount;
int32_t mInputDeviceIndex;
}; };
}; // namespace android }; // namespace android

View File

@@ -99,6 +99,7 @@ EventHub::EventHub(void)
, mDevicesById(0), mNumDevicesById(0) , mDevicesById(0), mNumDevicesById(0)
, mOpeningDevices(0), mClosingDevices(0) , mOpeningDevices(0), mClosingDevices(0)
, mDevices(0), mFDs(0), mFDCount(0), mOpened(false) , mDevices(0), mFDs(0), mFDCount(0), mOpened(false)
, mInputBufferIndex(0), mInputBufferCount(0), mInputDeviceIndex(0)
{ {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
#ifdef EV_SW #ifdef EV_SW
@@ -341,13 +342,6 @@ bool EventHub::getEvent(RawEvent* outEvent)
outEvent->value = 0; outEvent->value = 0;
outEvent->when = 0; outEvent->when = 0;
status_t err;
int i;
int res;
int pollres;
struct input_event iev;
// Note that we only allow one caller to getEvent(), so don't need // Note that we only allow one caller to getEvent(), so don't need
// to do locking here... only when adding/removing devices. // to do locking here... only when adding/removing devices.
@@ -356,9 +350,8 @@ bool EventHub::getEvent(RawEvent* outEvent)
mOpened = true; mOpened = true;
} }
while(1) { for (;;) {
// Report any devices that had last been added/removed.
// First, report any devices that had last been added/removed.
if (mClosingDevices != NULL) { if (mClosingDevices != NULL) {
device_t* device = mClosingDevices; device_t* device = mClosingDevices;
LOGV("Reporting device closed: id=0x%x, name=%s\n", LOGV("Reporting device closed: id=0x%x, name=%s\n",
@@ -388,34 +381,15 @@ bool EventHub::getEvent(RawEvent* outEvent)
return true; return true;
} }
release_wake_lock(WAKE_LOCK_ID); // Grab the next input event.
for (;;) {
// Consume buffered input events, if any.
if (mInputBufferIndex < mInputBufferCount) {
const struct input_event& iev = mInputBufferData[mInputBufferIndex++];
const device_t* device = mDevices[mInputDeviceIndex];
pollres = poll(mFDs, mFDCount, -1); LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d", device->path.string(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec, iev.type, iev.code, iev.value);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
if (pollres <= 0) {
if (errno != EINTR) {
LOGW("select failed (errno=%d)\n", errno);
usleep(100000);
}
continue;
}
//printf("poll %d, returned %d\n", mFDCount, pollres);
// mFDs[0] is used for inotify, so process regular events starting at mFDs[1]
for(i = 1; i < mFDCount; i++) {
if(mFDs[i].revents) {
LOGV("revents for %d = 0x%08x", i, mFDs[i].revents);
if(mFDs[i].revents & POLLIN) {
res = read(mFDs[i].fd, &iev, sizeof(iev));
if (res == sizeof(iev)) {
device_t* device = mDevices[i];
LOGV("%s got: t0=%d, t1=%d, type=%d, code=%d, v=%d",
device->path.string(),
(int) iev.time.tv_sec, (int) iev.time.tv_usec,
iev.type, iev.code, iev.value);
if (device->id == mFirstKeyboardId) { if (device->id == mFirstKeyboardId) {
outEvent->deviceId = 0; outEvent->deviceId = 0;
} else { } else {
@@ -424,7 +398,7 @@ bool EventHub::getEvent(RawEvent* outEvent)
outEvent->type = iev.type; outEvent->type = iev.type;
outEvent->scanCode = iev.code; outEvent->scanCode = iev.code;
if (iev.type == EV_KEY) { if (iev.type == EV_KEY) {
err = device->layoutMap->map(iev.code, status_t err = device->layoutMap->map(iev.code,
& outEvent->keyCode, & outEvent->flags); & outEvent->keyCode, & outEvent->flags);
LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n", LOGV("iev.code=%d keyCode=%d flags=0x%08x err=%d\n",
iev.code, outEvent->keyCode, outEvent->flags, err); iev.code, outEvent->keyCode, outEvent->flags, err);
@@ -442,14 +416,31 @@ bool EventHub::getEvent(RawEvent* outEvent)
// as expected by the rest of the system. // as expected by the rest of the system.
outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC); outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
return true; return true;
} else { }
if (res<0) {
// Finish reading all events from devices identified in previous poll().
// This code assumes that mInputDeviceIndex is initially 0 and that the
// revents member of pollfd is initialized to 0 when the device is first added.
// Since mFDs[0] is used for inotify, we process regular events starting at index 1.
mInputDeviceIndex += 1;
if (mInputDeviceIndex >= mFDCount) {
mInputDeviceIndex = 0;
break;
}
const struct pollfd &pfd = mFDs[mInputDeviceIndex];
if (pfd.revents & POLLIN) {
int32_t readSize = read(pfd.fd, mInputBufferData,
sizeof(struct input_event) * INPUT_BUFFER_SIZE);
if (readSize < 0) {
if (errno != EAGAIN && errno != EINTR) {
LOGW("could not get event (errno=%d)", errno); LOGW("could not get event (errno=%d)", errno);
}
} else if ((readSize % sizeof(struct input_event)) != 0) {
LOGE("could not get event (wrong size: %d)", readSize);
} else { } else {
LOGE("could not get event (wrong size: %d)", res); mInputBufferCount = readSize / sizeof(struct input_event);
} mInputBufferIndex = 0;
continue;
}
} }
} }
} }
@@ -459,6 +450,27 @@ bool EventHub::getEvent(RawEvent* outEvent)
if(mFDs[0].revents & POLLIN) { if(mFDs[0].revents & POLLIN) {
read_notify(mFDs[0].fd); read_notify(mFDs[0].fd);
} }
// Poll for events. Mind the wake lock dance!
// We hold a wake lock at all times except during poll(). This works due to some
// subtle choreography. When a device driver has pending (unread) events, it acquires
// a kernel wake lock. However, once the last pending event has been read, the device
// driver will release the kernel wake lock. To prevent the system from going to sleep
// when this happens, the EventHub holds onto its own user wake lock while the client
// is processing events. Thus the system can only sleep if there are no events
// pending or currently being processed.
release_wake_lock(WAKE_LOCK_ID);
int pollResult = poll(mFDs, mFDCount, -1);
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
if (pollResult <= 0) {
if (errno != EINTR) {
LOGW("select failed (errno=%d)\n", errno);
usleep(100000);
}
}
} }
} }
@@ -476,6 +488,7 @@ bool EventHub::openPlatformInput(void)
mFDs = (pollfd *)calloc(1, sizeof(mFDs[0])); mFDs = (pollfd *)calloc(1, sizeof(mFDs[0]));
mDevices = (device_t **)calloc(1, sizeof(mDevices[0])); mDevices = (device_t **)calloc(1, sizeof(mDevices[0]));
mFDs[0].events = POLLIN; mFDs[0].events = POLLIN;
mFDs[0].revents = 0;
mDevices[0] = NULL; mDevices[0] = NULL;
#ifdef HAVE_INOTIFY #ifdef HAVE_INOTIFY
mFDs[0].fd = inotify_init(); mFDs[0].fd = inotify_init();
@@ -582,6 +595,12 @@ int EventHub::open_device(const char *deviceName)
idstr[0] = '\0'; idstr[0] = '\0';
} }
if (fcntl(fd, F_SETFL, O_NONBLOCK)) {
LOGE("Error %d making device file descriptor non-blocking.", errno);
close(fd);
return -1;
}
int devid = 0; int devid = 0;
while (devid < mNumDevicesById) { while (devid < mNumDevicesById) {
if (mDevicesById[devid].device == NULL) { if (mDevicesById[devid].device == NULL) {
@@ -639,6 +658,7 @@ int EventHub::open_device(const char *deviceName)
device->fd = fd; device->fd = fd;
mFDs[mFDCount].fd = fd; mFDs[mFDCount].fd = fd;
mFDs[mFDCount].events = POLLIN; mFDs[mFDCount].events = POLLIN;
mFDs[mFDCount].revents = 0;
// Figure out the kinds of events the device reports. // Figure out the kinds of events the device reports.