Skip to content

Commit f910da1

Browse files
authored
Merge pull request #1002 from alvarolobato/fix-connect-loop-188
Fix segfault and connect loop - PC/SDL2: defer jsonl/json to main thread
2 parents c387627 + ce3773c commit f910da1

7 files changed

Lines changed: 57 additions & 1 deletion

File tree

src/hasp/hasp_dispatch.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@
2020
#include <iostream>
2121
#include <fstream>
2222
#include <sstream>
23+
#include <queue>
24+
#include <mutex>
25+
#include <string>
2326
#include "../mqtt/hasp_mqtt.h"
27+
28+
/* Deferred command queue: MQTT callback runs on Paho thread; jsonl/json handlers call LVGL
29+
* (hasp_new_object) which is not thread-safe. Queue jsonl/json for processing on main thread.
30+
* 64 is enough for burst layout + state; PC has plenty of memory. */
31+
#define DISPATCH_DEFERRED_QUEUE_MAX 64
32+
static std::queue<std::pair<std::string, std::string>> deferred_queue;
33+
static std::mutex deferred_mutex;
2434
#else
2535
#include "StringStream.h"
2636
#include "StreamUtils.h" // for exec ReadBufferingStream
@@ -463,6 +473,33 @@ void dispatch_topic_payload(const char* topic, const char* payload, bool update,
463473
dispatch_command(topic, (char*)payload, update, source); // dispatch as is
464474
}
465475

476+
#if HASP_TARGET_PC
477+
void dispatch_defer_command(const char* topic, const char* payload)
478+
{
479+
std::lock_guard<std::mutex> lock(deferred_mutex);
480+
if(deferred_queue.size() >= DISPATCH_DEFERRED_QUEUE_MAX) {
481+
(void)deferred_queue.front();
482+
deferred_queue.pop(); // drop oldest
483+
}
484+
deferred_queue.push({std::string(topic), std::string(payload)});
485+
}
486+
487+
void dispatch_process_deferred(void)
488+
{
489+
std::pair<std::string, std::string> item;
490+
for(;;) {
491+
{
492+
std::lock_guard<std::mutex> lock(deferred_mutex);
493+
if(deferred_queue.empty()) break;
494+
item = deferred_queue.front();
495+
deferred_queue.pop();
496+
}
497+
bool update = item.second.size() > 0;
498+
dispatch_topic_payload(item.first.c_str(), item.second.c_str(), update, TAG_MQTT);
499+
}
500+
}
501+
#endif
502+
466503
// void dispatch_output_group_state(uint8_t groupid, uint16_t state)
467504
// {
468505
// char payload[64];

src/hasp/hasp_dispatch.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ void dispatch_config(const char* topic, const char* payload, uint8_t source);
9393

9494
void dispatch_normalized_group_values(hasp_update_value_t& value);
9595

96+
#if HASP_TARGET_PC
97+
/* Defer json/jsonl from MQTT thread to main (LVGL) thread to avoid segfault (PC/SDL2 only). */
98+
void dispatch_defer_command(const char* topic, const char* payload);
99+
void dispatch_process_deferred(void);
100+
#endif
101+
96102
void dispatch_state_subtopic(const char* subtopic, const char* payload);
97103
void dispatch_state_eventid(const char* topic, hasp_event_t eventid);
98104
void dispatch_state_brightness(const char* topic, hasp_event_t eventid, int32_t val);

src/main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ IRAM_ATTR void loop()
172172
}
173173
#endif
174174

175+
#if HASP_TARGET_PC
176+
/* Process jsonl/json commands deferred from MQTT thread (LVGL not thread-safe on PC). */
177+
dispatch_process_deferred();
178+
#endif
179+
175180
#if HASP_USE_LVGL_TASK == 0
176181
guiLoop();
177182
#endif

src/mqtt/hasp_mqtt_paho_async.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const char FP_CONFIG_GROUP[] PROGMEM = "group";
4444

4545
#include "hasp_mqtt.h" // functions to implement here
4646

47-
#include "hasp/hasp_dispatch.h" // for dispatch_topic_payload
47+
#include "hasp/hasp_dispatch.h" // for dispatch_topic_payload, dispatch_defer_command
4848
#include "hasp_debug.h" // for logging
4949

5050
#if !defined(_WIN32)
@@ -206,6 +206,11 @@ static void mqtt_message_cb(char* topic, char* payload, size_t length)
206206
// LOG_TRACE(TAG_MQTT, F("ignoring LWT = online"));
207207
}
208208
} else {
209+
// On PC, jsonl/json handlers call LVGL from MQTT thread -> segfault. Defer to main thread.
210+
if(!strcmp(topic, "command/jsonl") || !strcmp(topic, "command/json")) {
211+
dispatch_defer_command(topic, payload);
212+
return;
213+
}
209214
dispatch_mtx.lock();
210215
dispatch_topic_payload(topic, (const char*)payload, length > 0, TAG_MQTT);
211216
dispatch_mtx.unlock();

user_setups/darwin/darwin_headless.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extra_scripts =
66
tools/linux_build_extra.py
77
build_flags =
88
${env.build_flags}
9+
-std=c++14
910
-D HASP_MODEL="MacOS Headless"
1011
-D HASP_TARGET_PC=1
1112

user_setups/linux/linux_fbdev.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ extra_scripts =
44
tools/linux_build_extra.py
55
build_flags =
66
${env.build_flags}
7+
-std=c++14
78
-D HASP_MODEL="Linux App"
89
-D HASP_TARGET_PC=1
910

user_setups/linux/linux_headless.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ extra_scripts =
44
tools/linux_build_extra.py
55
build_flags =
66
${env.build_flags}
7+
-std=c++14
78
-D HASP_MODEL="Linux Headless"
89
-D HASP_TARGET_PC=1
910

0 commit comments

Comments
 (0)