1#include <stdio.h>
2#include <stdlib.h>
3#include <hardware/sensors.h>
4#include <pthread.h>
5#include <cutils/atomic.h>
6
7#include "SensorEventQueue.cpp"
8
9// Unit tests for the SensorEventQueue.
10
11// Run it like this:
12//
13// make sensorstests -j32 && \
14// out/host/linux-x86/obj/EXECUTABLES/sensorstests_intermediates/sensorstests
15
16bool checkWritableBufferSize(SensorEventQueue* queue, int requested, int expected) {
17    sensors_event_t* buffer;
18    int actual = queue->getWritableRegion(requested, &buffer);
19    if (actual != expected) {
20        printf("Expected buffer size was %d; actual was %d\n", expected, actual);
21        return false;
22    }
23    return true;
24}
25
26bool checkSize(SensorEventQueue* queue, int expected) {
27    int actual = queue->getSize();
28    if (actual != expected) {
29        printf("Expected queue size was %d; actual was %d\n", expected, actual);
30        return false;
31    }
32    return true;
33}
34
35bool checkInt(char* msg, int expected, int actual) {
36    if (actual != expected) {
37        printf("%s; expected %d; actual was %d\n", msg, expected, actual);
38        return false;
39    }
40    return true;
41}
42
43bool testSimpleWriteSizeCounts() {
44    printf("testSimpleWriteSizeCounts\n");
45    SensorEventQueue* queue = new SensorEventQueue(10);
46    if (!checkSize(queue, 0)) return false;
47    if (!checkWritableBufferSize(queue, 11, 10)) return false;
48    if (!checkWritableBufferSize(queue, 10, 10)) return false;
49    if (!checkWritableBufferSize(queue, 9, 9)) return false;
50
51    queue->markAsWritten(7);
52    if (!checkSize(queue, 7)) return false;
53    if (!checkWritableBufferSize(queue, 4, 3)) return false;
54    if (!checkWritableBufferSize(queue, 3, 3)) return false;
55    if (!checkWritableBufferSize(queue, 2, 2)) return false;
56
57    queue->markAsWritten(3);
58    if (!checkSize(queue, 10)) return false;
59    if (!checkWritableBufferSize(queue, 1, 0)) return false;
60
61    printf("passed\n");
62    return true;
63}
64
65bool testWrappingWriteSizeCounts() {
66    printf("testWrappingWriteSizeCounts\n");
67    SensorEventQueue* queue = new SensorEventQueue(10);
68    queue->markAsWritten(9);
69    if (!checkSize(queue, 9)) return false;
70
71    // dequeue from the front
72    queue->dequeue();
73    queue->dequeue();
74    if (!checkSize(queue, 7)) return false;
75    if (!checkWritableBufferSize(queue, 100, 1)) return false;
76
77    // Write all the way to the end.
78    queue->markAsWritten(1);
79    if (!checkSize(queue, 8)) return false;
80    // Now the two free spots in the front are available.
81    if (!checkWritableBufferSize(queue, 100, 2)) return false;
82
83    // Fill the queue again
84    queue->markAsWritten(2);
85    if (!checkSize(queue, 10)) return false;
86
87    printf("passed\n");
88    return true;
89}
90
91
92
93struct TaskContext {
94  bool success;
95  SensorEventQueue* queue;
96};
97
98static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
99static pthread_cond_t dataAvailableCond = PTHREAD_COND_INITIALIZER;
100
101int FULL_QUEUE_CAPACITY = 5;
102int FULL_QUEUE_EVENT_COUNT = 31;
103
104void *fullQueueWriterTask(void* ptr) {
105    TaskContext* ctx = (TaskContext*)ptr;
106    SensorEventQueue* queue = ctx->queue;
107    ctx->success = true;
108    int totalWaits = 0;
109    int totalWrites = 0;
110    sensors_event_t* buffer;
111
112    while (totalWrites < FULL_QUEUE_EVENT_COUNT) {
113        pthread_mutex_lock(&mutex);
114        if (queue->waitForSpace(&mutex)) {
115            totalWaits++;
116            printf(".");
117        }
118        int writableSize = queue->getWritableRegion(FULL_QUEUE_CAPACITY, &buffer);
119        queue->markAsWritten(writableSize);
120        totalWrites += writableSize;
121        for (int i = 0; i < writableSize; i++) {
122            printf("w");
123        }
124        pthread_cond_broadcast(&dataAvailableCond);
125        pthread_mutex_unlock(&mutex);
126    }
127    printf("\n");
128
129    ctx->success =
130            checkInt("totalWrites", FULL_QUEUE_EVENT_COUNT, totalWrites) &&
131            checkInt("totalWaits", FULL_QUEUE_EVENT_COUNT - FULL_QUEUE_CAPACITY, totalWaits);
132    return NULL;
133}
134
135bool fullQueueReaderShouldRead(int queueSize, int totalReads) {
136    if (queueSize == 0) {
137        return false;
138    }
139    int totalWrites = totalReads + queueSize;
140    return queueSize == FULL_QUEUE_CAPACITY || totalWrites == FULL_QUEUE_EVENT_COUNT;
141}
142
143void* fullQueueReaderTask(void* ptr) {
144    TaskContext* ctx = (TaskContext*)ptr;
145    SensorEventQueue* queue = ctx->queue;
146    int totalReads = 0;
147    while (totalReads < FULL_QUEUE_EVENT_COUNT) {
148        pthread_mutex_lock(&mutex);
149        // Only read if there are events,
150        // and either the queue is full, or if we're reading the last few events.
151        while (!fullQueueReaderShouldRead(queue->getSize(), totalReads)) {
152            pthread_cond_wait(&dataAvailableCond, &mutex);
153        }
154        queue->dequeue();
155        totalReads++;
156        printf("r");
157        pthread_mutex_unlock(&mutex);
158    }
159    printf("\n");
160    ctx->success = ctx->success && checkInt("totalreads", FULL_QUEUE_EVENT_COUNT, totalReads);
161    return NULL;
162}
163
164// Test internal queue-full waiting and broadcasting.
165bool testFullQueueIo() {
166    printf("testFullQueueIo\n");
167    SensorEventQueue* queue = new SensorEventQueue(FULL_QUEUE_CAPACITY);
168
169    TaskContext readerCtx;
170    readerCtx.success = true;
171    readerCtx.queue = queue;
172
173    TaskContext writerCtx;
174    writerCtx.success = true;
175    writerCtx.queue = queue;
176
177    pthread_t writer, reader;
178    pthread_create(&reader, NULL, fullQueueReaderTask, &readerCtx);
179    pthread_create(&writer, NULL, fullQueueWriterTask, &writerCtx);
180
181    pthread_join(writer, NULL);
182    pthread_join(reader, NULL);
183
184    if (!readerCtx.success || !writerCtx.success) return false;
185    printf("passed\n");
186    return true;
187}
188
189
190int main(int argc, char **argv) {
191    if (testSimpleWriteSizeCounts() &&
192            testWrappingWriteSizeCounts() &&
193            testFullQueueIo()) {
194        printf("ALL PASSED\n");
195    } else {
196        printf("SOMETHING FAILED\n");
197    }
198    return EXIT_SUCCESS;
199}
200