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.h"
8 
9 // Unit tests for the SensorEventQueue.
10 
11 // Run it like this:
12 //
13 // m sensorstests && \
14 // out/host/linux-x86/nativetest64/sensorstests/sensorstests
15 
checkWritableBufferSize(SensorEventQueue * queue,int requested,int expected)16 bool 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 
checkSize(SensorEventQueue * queue,int expected)26 bool 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 
checkInt(const char * msg,int expected,int actual)35 bool checkInt(const 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 
testSimpleWriteSizeCounts()43 bool 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 
testWrappingWriteSizeCounts()65 bool 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 
93 struct TaskContext {
94   bool success;
95   SensorEventQueue* queue;
96 };
97 
98 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
99 static pthread_cond_t dataAvailableCond = PTHREAD_COND_INITIALIZER;
100 
101 int FULL_QUEUE_CAPACITY = 5;
102 int FULL_QUEUE_EVENT_COUNT = 31;
103 
fullQueueWriterTask(void * ptr)104 void *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 
fullQueueReaderShouldRead(int queueSize,int totalReads)135 bool 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 
fullQueueReaderTask(void * ptr)143 void* 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.
testFullQueueIo()165 bool 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 
main(int argc __attribute ((unused)),char ** argv __attribute ((unused)))190 int main(int argc __attribute((unused)), char **argv __attribute((unused))) {
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