#include <stdio.h> #include <stdlib.h> #include <hardware/sensors.h> #include <pthread.h> #include <cutils/atomic.h> #include "SensorEventQueue.cpp" // Unit tests for the SensorEventQueue. // Run it like this: // // make sensorstests -j32 && \ // out/host/linux-x86/obj/EXECUTABLES/sensorstests_intermediates/sensorstests bool checkWritableBufferSize(SensorEventQueue* queue, int requested, int expected) { sensors_event_t* buffer; int actual = queue->getWritableRegion(requested, &buffer); if (actual != expected) { printf("Expected buffer size was %d; actual was %d\n", expected, actual); return false; } return true; } bool checkSize(SensorEventQueue* queue, int expected) { int actual = queue->getSize(); if (actual != expected) { printf("Expected queue size was %d; actual was %d\n", expected, actual); return false; } return true; } bool checkInt(const char* msg, int expected, int actual) { if (actual != expected) { printf("%s; expected %d; actual was %d\n", msg, expected, actual); return false; } return true; } bool testSimpleWriteSizeCounts() { printf("testSimpleWriteSizeCounts\n"); SensorEventQueue* queue = new SensorEventQueue(10); if (!checkSize(queue, 0)) return false; if (!checkWritableBufferSize(queue, 11, 10)) return false; if (!checkWritableBufferSize(queue, 10, 10)) return false; if (!checkWritableBufferSize(queue, 9, 9)) return false; queue->markAsWritten(7); if (!checkSize(queue, 7)) return false; if (!checkWritableBufferSize(queue, 4, 3)) return false; if (!checkWritableBufferSize(queue, 3, 3)) return false; if (!checkWritableBufferSize(queue, 2, 2)) return false; queue->markAsWritten(3); if (!checkSize(queue, 10)) return false; if (!checkWritableBufferSize(queue, 1, 0)) return false; printf("passed\n"); return true; } bool testWrappingWriteSizeCounts() { printf("testWrappingWriteSizeCounts\n"); SensorEventQueue* queue = new SensorEventQueue(10); queue->markAsWritten(9); if (!checkSize(queue, 9)) return false; // dequeue from the front queue->dequeue(); queue->dequeue(); if (!checkSize(queue, 7)) return false; if (!checkWritableBufferSize(queue, 100, 1)) return false; // Write all the way to the end. queue->markAsWritten(1); if (!checkSize(queue, 8)) return false; // Now the two free spots in the front are available. if (!checkWritableBufferSize(queue, 100, 2)) return false; // Fill the queue again queue->markAsWritten(2); if (!checkSize(queue, 10)) return false; printf("passed\n"); return true; } struct TaskContext { bool success; SensorEventQueue* queue; }; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t dataAvailableCond = PTHREAD_COND_INITIALIZER; int FULL_QUEUE_CAPACITY = 5; int FULL_QUEUE_EVENT_COUNT = 31; void *fullQueueWriterTask(void* ptr) { TaskContext* ctx = (TaskContext*)ptr; SensorEventQueue* queue = ctx->queue; ctx->success = true; int totalWaits = 0; int totalWrites = 0; sensors_event_t* buffer; while (totalWrites < FULL_QUEUE_EVENT_COUNT) { pthread_mutex_lock(&mutex); if (queue->waitForSpace(&mutex)) { totalWaits++; printf("."); } int writableSize = queue->getWritableRegion(FULL_QUEUE_CAPACITY, &buffer); queue->markAsWritten(writableSize); totalWrites += writableSize; for (int i = 0; i < writableSize; i++) { printf("w"); } pthread_cond_broadcast(&dataAvailableCond); pthread_mutex_unlock(&mutex); } printf("\n"); ctx->success = checkInt("totalWrites", FULL_QUEUE_EVENT_COUNT, totalWrites) && checkInt("totalWaits", FULL_QUEUE_EVENT_COUNT - FULL_QUEUE_CAPACITY, totalWaits); return NULL; } bool fullQueueReaderShouldRead(int queueSize, int totalReads) { if (queueSize == 0) { return false; } int totalWrites = totalReads + queueSize; return queueSize == FULL_QUEUE_CAPACITY || totalWrites == FULL_QUEUE_EVENT_COUNT; } void* fullQueueReaderTask(void* ptr) { TaskContext* ctx = (TaskContext*)ptr; SensorEventQueue* queue = ctx->queue; int totalReads = 0; while (totalReads < FULL_QUEUE_EVENT_COUNT) { pthread_mutex_lock(&mutex); // Only read if there are events, // and either the queue is full, or if we're reading the last few events. while (!fullQueueReaderShouldRead(queue->getSize(), totalReads)) { pthread_cond_wait(&dataAvailableCond, &mutex); } queue->dequeue(); totalReads++; printf("r"); pthread_mutex_unlock(&mutex); } printf("\n"); ctx->success = ctx->success && checkInt("totalreads", FULL_QUEUE_EVENT_COUNT, totalReads); return NULL; } // Test internal queue-full waiting and broadcasting. bool testFullQueueIo() { printf("testFullQueueIo\n"); SensorEventQueue* queue = new SensorEventQueue(FULL_QUEUE_CAPACITY); TaskContext readerCtx; readerCtx.success = true; readerCtx.queue = queue; TaskContext writerCtx; writerCtx.success = true; writerCtx.queue = queue; pthread_t writer, reader; pthread_create(&reader, NULL, fullQueueReaderTask, &readerCtx); pthread_create(&writer, NULL, fullQueueWriterTask, &writerCtx); pthread_join(writer, NULL); pthread_join(reader, NULL); if (!readerCtx.success || !writerCtx.success) return false; printf("passed\n"); return true; } int main(int argc __attribute((unused)), char **argv __attribute((unused))) { if (testSimpleWriteSizeCounts() && testWrappingWriteSizeCounts() && testFullQueueIo()) { printf("ALL PASSED\n"); } else { printf("SOMETHING FAILED\n"); } return EXIT_SUCCESS; }