Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ESP32 platform manager shutdown. #22417

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .restyled.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ restylers:
- "**/*.c"
- "**/*.cc"
- "**/*.cpp"
- "**/*.ipp"
- "**/*.cxx"
- "**/*.c++"
- "**/*.C"
Expand Down Expand Up @@ -137,6 +138,7 @@ restylers:
- "**/*.c"
- "**/*.cc"
- "**/*.cpp"
- "**/*.ipp"
- "**/*.cxx"
- "**/*.c++"
- "**/*.C"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ class GenericPlatformManagerImpl_FreeRTOS : public GenericPlatformManagerImpl<Im
protected:
TimeOut_t mNextTimerBaseTime;
TickType_t mNextTimerDurationTicks;
SemaphoreHandle_t mChipStackLock;
QueueHandle_t mChipEventQueue;
TaskHandle_t mEventLoopTask;
SemaphoreHandle_t mChipStackLock = NULL;
QueueHandle_t mChipEventQueue = NULL;
TaskHandle_t mEventLoopTask = NULL;
bool mChipTimerActive;

// ===== Methods that implement the PlatformManager abstract interface.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,31 +46,50 @@ CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_InitChipStack(void)

vTaskSetTimeOutState(&mNextTimerBaseTime);
mNextTimerDurationTicks = 0;
mEventLoopTask = NULL;
mChipTimerActive = false;
// TODO: This nulling out of mEventLoopTask should happen when we shut down
// the task, not here!
mEventLoopTask = NULL;
mChipTimerActive = false;

// We support calling Shutdown followed by InitChipStack, because some tests
// do that. To keep things simple for existing consumers, we keep not
// destroying our lock and queue in shutdown, but rather check whether they
// already exist here before trying to create them.

if (mChipStackLock == NULL)
{
#if defined(CHIP_CONFIG_FREERTOS_USE_STATIC_SEMAPHORE) && CHIP_CONFIG_FREERTOS_USE_STATIC_SEMAPHORE
mChipStackLock = xSemaphoreCreateMutexStatic(&mChipStackLockMutex);
mChipStackLock = xSemaphoreCreateMutexStatic(&mChipStackLockMutex);
#else
mChipStackLock = xSemaphoreCreateMutex();
mChipStackLock = xSemaphoreCreateMutex();
#endif // CHIP_CONFIG_FREERTOS_USE_STATIC_SEMAPHORE

if (mChipStackLock == NULL)
{
ChipLogError(DeviceLayer, "Failed to create CHIP stack lock");
ExitNow(err = CHIP_ERROR_NO_MEMORY);
if (mChipStackLock == NULL)
{
ChipLogError(DeviceLayer, "Failed to create CHIP stack lock");
ExitNow(err = CHIP_ERROR_NO_MEMORY);
}
}

if (mChipEventQueue == NULL)
{
#if defined(CHIP_CONFIG_FREERTOS_USE_STATIC_QUEUE) && CHIP_CONFIG_FREERTOS_USE_STATIC_QUEUE
mChipEventQueue =
xQueueCreateStatic(CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent), mEventQueueBuffer, &mEventQueueStruct);
mChipEventQueue = xQueueCreateStatic(CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent), mEventQueueBuffer,
&mEventQueueStruct);
#else
mChipEventQueue = xQueueCreate(CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent));
mChipEventQueue = xQueueCreate(CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent));
#endif
if (mChipEventQueue == NULL)
if (mChipEventQueue == NULL)
{
ChipLogError(DeviceLayer, "Failed to allocate CHIP event queue");
ExitNow(err = CHIP_ERROR_NO_MEMORY);
}
}
else
{
ChipLogError(DeviceLayer, "Failed to allocate CHIP event queue");
ExitNow(err = CHIP_ERROR_NO_MEMORY);
// Clear out any events that might be stuck in the queue, so we start
// with a clean slate, as if we had just re-created the queue.
xQueueReset(mChipEventQueue);
}

mShouldRunEventLoop.store(false);
Expand Down Expand Up @@ -145,7 +164,7 @@ void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_RunEventLoop(void)
ChipDeviceEvent event;

// Lock the CHIP stack.
Impl()->LockChipStack();
StackLock lock;

bool oldShouldRunEventLoop = false;
if (!mShouldRunEventLoop.compare_exchange_strong(oldShouldRunEventLoop /* expected */, true /* desired */))
Expand Down Expand Up @@ -198,13 +217,13 @@ void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_RunEventLoop(void)
waitTime = portMAX_DELAY;
}

// Unlock the CHIP stack, allowing other threads to enter CHIP while the event loop thread is sleeping.
Impl()->UnlockChipStack();

BaseType_t eventReceived = xQueueReceive(mChipEventQueue, &event, waitTime);

// Lock the CHIP stack.
Impl()->LockChipStack();
BaseType_t eventReceived = pdFALSE;
{
// Unlock the CHIP stack, allowing other threads to enter CHIP while
// the event loop thread is sleeping.
StackUnlock unlock;
eventReceived = xQueueReceive(mChipEventQueue, &event, waitTime);
}

// If an event was received, dispatch it. Continue receiving events from the queue and
// dispatching them until the queue is empty.
Expand Down Expand Up @@ -236,6 +255,9 @@ void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::EventLoopTaskMain(void * ar
{
ChipLogDetail(DeviceLayer, "CHIP task running");
static_cast<GenericPlatformManagerImpl_FreeRTOS<ImplClass> *>(arg)->Impl()->RunEventLoop();
// TODO: At this point, should we not
// vTaskDelete(static_cast<GenericPlatformManagerImpl_FreeRTOS<ImplClass> *>(arg)->mEventLoopTask)?
// Or somehow get our caller to do it once this thread is joined?
}

template <class ImplClass>
Expand Down Expand Up @@ -275,6 +297,7 @@ void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::PostEventFromISR(const Chip
template <class ImplClass>
void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_Shutdown(void)
{
GenericPlatformManagerImpl<ImplClass>::_Shutdown();
}

template <class ImplClass>
Expand Down
2 changes: 2 additions & 0 deletions src/platform/ESP32/PlatformManagerImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ void PlatformManagerImpl::_Shutdown()
}

Internal::GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>::_Shutdown();

esp_event_loop_delete_default();
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
}

void PlatformManagerImpl::HandleESPSystemEvent(void * arg, esp_event_base_t eventBase, int32_t eventId, void * eventData)
Expand Down
2 changes: 1 addition & 1 deletion src/system/tests/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ chip_test_suite("tests") {
"TestTimeSource.cpp",
]

if (chip_device_platform != "esp32" && chip_device_platform != "fake") {
if (chip_device_platform != "fake") {
test_sources += [ "TestSystemScheduleWork.cpp" ]
}

Expand Down
27 changes: 26 additions & 1 deletion src/test_driver/esp32/run_qemu_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import click
import logging
import os
import re
import sys
import subprocess

Expand Down Expand Up @@ -104,19 +105,41 @@ def main(log_level, no_log_timestamps, image, file_image_list, qemu, verbose):
(path, status.returncode))

# Parse output of the unit test. Generally expect things like:
# I (3034) CHIP-tests: Starting CHIP tests!
# ...
# Various test lines, none ending with "] : FAILED"
# ...
# Failed Tests: 0 / 5
# Failed Asserts: 0 / 77
# I (3034) CHIP-tests: CHIP test status: 0
in_test = False
for line in output.split('\n'):
if line.endswith('CHIP-tests: Starting CHIP tests!'):
in_test = True

if line.startswith('Failed Tests:') and not line.startswith('Failed Tests: 0 /'):
raise Exception("Tests seem failed: %s" % line)

if line.startswith('Failed Asserts:') and not line.startswith('Failed Asserts: 0 /'):
raise Exception("Asserts seem failed: %s" % line)

if 'CHIP test status: ' in line and 'CHIP test status: 0' not in line:
if 'CHIP-tests: CHIP test status: 0' in line:
in_test = False
elif 'CHIP-tests: CHIP test status: ' in line:
raise Exception("CHIP test status is NOT 0: %s" % line)

# Ignore FAILED messages not in the middle of a test, to reduce
# the chance of false posisitves from other logging.
if in_test and re.match('.*] : FAILED$', line):
raise Exception("Step failed: %s" % line)

# TODO: Figure out why exit(0) in man_app.cpp's tester_task is aborting and fix that.
if in_test and line.startswith('abort() was called at PC'):
raise Exception("Unexpected crash: %s" % line)

if in_test:
raise Exception('Not expected to be in the middle of a test when the log ends')

if verbose:
print("========== TEST OUTPUT BEGIN ============")
print(output)
Expand All @@ -125,7 +148,9 @@ def main(log_level, no_log_timestamps, image, file_image_list, qemu, verbose):
logging.info("Image %s PASSED", path)
except:
# make sure output is visible in stdout
print("========== TEST OUTPUT BEGIN ============")
print(output)
print("========== TEST OUTPUT END ============")
raise


Expand Down