144 lines
4.6 KiB
C++
144 lines
4.6 KiB
C++
/*
|
|
* Copyright (C) 2021 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef CHRE_SIMULATION_TEST_EVENT_QUEUE_H_
|
|
#define CHRE_SIMULATION_TEST_EVENT_QUEUE_H_
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <cinttypes>
|
|
|
|
#include "chre/platform/memory.h"
|
|
#include "chre/util/fixed_size_blocking_queue.h"
|
|
#include "chre/util/memory.h"
|
|
#include "chre/util/non_copyable.h"
|
|
#include "chre/util/singleton.h"
|
|
#include "test_event.h"
|
|
|
|
namespace chre {
|
|
|
|
//! A test event type to indicate the test nanoapp has loaded.
|
|
#define CHRE_EVENT_SIMULATION_TEST_NANOAPP_LOADED \
|
|
CHRE_SIMULATION_TEST_EVENT_ID(0)
|
|
|
|
//! A test event type to indicate the test has timed out, and should abort.
|
|
#define CHRE_EVENT_SIMULATION_TEST_TIMEOUT CHRE_SIMULATION_TEST_EVENT_ID(1)
|
|
|
|
//! A test event type to indicate the test nanoapp has unloaded.
|
|
#define CHRE_EVENT_SIMULATION_TEST_NANOAPP_UNLOADED \
|
|
CHRE_SIMULATION_TEST_EVENT_ID(2)
|
|
|
|
/**
|
|
* A class that monitors events for the test to consume.
|
|
*
|
|
* This class can be used as an execution barrier for the test, i.e. waiting
|
|
* for a specific event to occur. The barrier is done through the semantics of
|
|
* CHRE events, and can be used e.g. for nanoapps to redirect incoming events
|
|
* using pushEvent().
|
|
*
|
|
* The main test thread can then wait for this event using waitForEvent().
|
|
*
|
|
* Note 1) pushEvent() can also be invoked outside the nanoapp, for instance
|
|
* using deferred system callbacks.
|
|
* Note 2) The CHRE_EVENT_SIMULATION_TEST_TIMEOUT event type can be used to
|
|
* abort the test due to a timeout (this usage is recommended in order to avoid
|
|
* the test framework from stalling).
|
|
*/
|
|
class TestEventQueue : public NonCopyable {
|
|
public:
|
|
//! Push an event to the queue.
|
|
void pushEvent(uint16_t eventType) {
|
|
mQueue.push({eventType});
|
|
}
|
|
|
|
/**
|
|
* Push an event with data to the queue.
|
|
*
|
|
* Note: The data passed to this method must be trivially copyable. It is
|
|
* recommended to pass a scalar or a struct composed of scalars only. If this
|
|
* method is used in the test nanoapp handleEvent be careful not to forward
|
|
* pointers to memory that could be freed by the CHRE framework before the
|
|
* data is received using @ref waitForEvent.
|
|
*
|
|
* @param eventType The type of event.
|
|
* @param eventData The data to send together with the event, which must not
|
|
* contain references to dynamically allocated memory.
|
|
*/
|
|
template <class T>
|
|
void pushEvent(uint16_t eventType, T eventData) {
|
|
static_assert(std::is_trivial<T>::value);
|
|
auto ptr = memoryAlloc<T>();
|
|
ASSERT_NE(ptr, nullptr);
|
|
*ptr = eventData;
|
|
mQueue.push({eventType, static_cast<void *>(ptr)});
|
|
}
|
|
|
|
//! Block until the event happens.
|
|
void waitForEvent(uint16_t eventType) {
|
|
while (true) {
|
|
auto event = mQueue.pop();
|
|
LOGD("Got event type 0x%" PRIx16, eventType);
|
|
ASSERT_NE(event.type, CHRE_EVENT_SIMULATION_TEST_TIMEOUT)
|
|
<< "Timeout waiting for event " << eventType;
|
|
memoryFree(event.data);
|
|
if (event.type == eventType) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//! Block until the event happens and populate the event data.
|
|
template <class T>
|
|
void waitForEvent(uint16_t eventType, T *data) {
|
|
static_assert(std::is_trivial<T>::value);
|
|
while (true) {
|
|
auto event = mQueue.pop();
|
|
LOGD("Got event type 0x%" PRIx16, eventType);
|
|
ASSERT_NE(event.type, CHRE_EVENT_SIMULATION_TEST_TIMEOUT)
|
|
<< "Timeout waiting for event " << eventType;
|
|
if (event.type == eventType) {
|
|
*data = *(static_cast<T *>(event.data));
|
|
memoryFree(event.data);
|
|
break;
|
|
}
|
|
memoryFree(event.data);
|
|
}
|
|
}
|
|
|
|
//! Flush the queue.
|
|
void flush() {
|
|
while (!mQueue.empty()) {
|
|
auto event = mQueue.pop();
|
|
memoryFree(event.data);
|
|
}
|
|
}
|
|
|
|
private:
|
|
static const size_t kQueueCapacity = 64;
|
|
FixedSizeBlockingQueue<TestEvent, kQueueCapacity> mQueue;
|
|
};
|
|
|
|
//! Provide an alias to the TestEventQueue singleton.
|
|
typedef Singleton<TestEventQueue> TestEventQueueSingleton;
|
|
|
|
//! Extern the explicit TestEventQueueSingleton to force non-inline method
|
|
//! calls.
|
|
extern template class Singleton<TestEventQueue>;
|
|
|
|
} // namespace chre
|
|
|
|
#endif // CHRE_SIMULATION_TEST_EVENT_QUEUE_H_
|