mirror of
https://github.com/esphome/esphome.git
synced 2026-05-24 09:56:46 +08:00
[openthread] Guard InstanceLock against uninitialized semaphore (#14940)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
Jesse Hills
parent
8af0991590
commit
729d3d4bc2
@@ -11,6 +11,7 @@
|
||||
#include <openthread/instance.h>
|
||||
#include <openthread/thread.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
@@ -28,6 +29,8 @@ class OpenThreadComponent : public Component {
|
||||
float get_setup_priority() const override { return setup_priority::WIFI; }
|
||||
|
||||
bool is_connected() const { return this->connected_; }
|
||||
/// Returns true once esp_openthread_init() has completed and the OT lock is usable.
|
||||
bool is_lock_initialized() const { return this->lock_initialized_; }
|
||||
network::IPAddresses get_ip_addresses();
|
||||
std::optional<otIp6Address> get_omr_address();
|
||||
void ot_main();
|
||||
@@ -51,6 +54,7 @@ class OpenThreadComponent : public Component {
|
||||
uint32_t poll_period_{0};
|
||||
#endif
|
||||
std::optional<int8_t> output_power_{};
|
||||
std::atomic<bool> lock_initialized_{false};
|
||||
bool teardown_started_{false};
|
||||
bool teardown_complete_{false};
|
||||
bool connected_{false};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "esp_openthread_lock.h"
|
||||
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
@@ -81,6 +82,9 @@ void OpenThreadComponent::ot_main() {
|
||||
// Initialize the OpenThread stack
|
||||
// otLoggingSetLevel(OT_LOG_LEVEL_DEBG);
|
||||
ESP_ERROR_CHECK(esp_openthread_init(&config));
|
||||
// Mark lock as initialized so InstanceLock callers know it's safe to acquire.
|
||||
// Must be set after esp_openthread_init() which creates the internal semaphore.
|
||||
this->lock_initialized_ = true;
|
||||
// Fetch OT instance once to avoid repeated call into OT stack
|
||||
otInstance *instance = esp_openthread_get_instance();
|
||||
|
||||
@@ -180,7 +184,8 @@ void OpenThreadComponent::ot_main() {
|
||||
|
||||
esp_openthread_launch_mainloop();
|
||||
|
||||
// Clean up
|
||||
// Clean up - reset lock flag before deinit destroys the semaphore
|
||||
this->lock_initialized_ = false;
|
||||
esp_openthread_deinit();
|
||||
esp_openthread_netif_glue_deinit();
|
||||
esp_netif_destroy(openthread_netif);
|
||||
@@ -210,6 +215,9 @@ network::IPAddresses OpenThreadComponent::get_ip_addresses() {
|
||||
otInstance *OpenThreadComponent::get_openthread_instance_() { return esp_openthread_get_instance(); }
|
||||
|
||||
std::optional<InstanceLock> InstanceLock::try_acquire(int delay) {
|
||||
if (!global_openthread_component->is_lock_initialized()) {
|
||||
return {};
|
||||
}
|
||||
if (esp_openthread_lock_acquire(delay)) {
|
||||
return InstanceLock();
|
||||
}
|
||||
@@ -217,6 +225,18 @@ std::optional<InstanceLock> InstanceLock::try_acquire(int delay) {
|
||||
}
|
||||
|
||||
InstanceLock InstanceLock::acquire() {
|
||||
// Wait for the lock to be created by ot_main() before attempting to acquire it.
|
||||
// esp_openthread_lock_acquire() will assert-crash if called before esp_openthread_init().
|
||||
constexpr uint32_t lock_init_timeout_ms = 10000;
|
||||
uint32_t start = millis();
|
||||
while (!global_openthread_component->is_lock_initialized()) {
|
||||
if (millis() - start > lock_init_timeout_ms) {
|
||||
ESP_LOGE(TAG, "OpenThread lock not initialized after %" PRIu32 "ms, aborting", lock_init_timeout_ms);
|
||||
abort();
|
||||
}
|
||||
delay(10);
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
while (!esp_openthread_lock_acquire(100)) {
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user