mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-08-24 11:39:49 +00:00
[verified] fix: retain map TLS while visible
This commit is contained in:
@@ -78,7 +78,8 @@ MapScreen::MapScreen(lv_obj_t* parent)
|
||||
download_config_(makeDownloadConfig()),
|
||||
downloader_(download_store_, download_transport_, download_clock_,
|
||||
download_policy_, download_config_),
|
||||
downloads_enabled_(false), download_failed_frame_epoch_(0U),
|
||||
downloads_enabled_(false), screen_visible_(false), transport_close_epoch_(0U),
|
||||
download_failed_frame_epoch_(0U),
|
||||
decode_failed_keys_{}, decode_failed_generations_{},
|
||||
compressed_staging_(nullptr),
|
||||
state_mutex_(nullptr), worker_task_(nullptr), stop_requested_(false),
|
||||
@@ -309,11 +310,28 @@ void MapScreen::workerEntry(void* context) {
|
||||
void MapScreen::workerLoop() {
|
||||
Hardware::TDeck::TileStoreResult initialized = store_.initialize();
|
||||
store_initialized_ = initialized == Hardware::TDeck::TileStoreResult::OK;
|
||||
std::uint32_t handled_close_epoch =
|
||||
transport_close_epoch_.load(std::memory_order_acquire);
|
||||
while (!stop_requested_.load(std::memory_order_acquire)) {
|
||||
// The worker exclusively owns HTTP/TLS teardown. Keep a successful
|
||||
// session across frame/zoom boundaries only while the map is visible
|
||||
// and online acquisition remains explicitly enabled.
|
||||
const bool downloads_enabled =
|
||||
downloads_enabled_.load(std::memory_order_acquire);
|
||||
const std::uint32_t close_epoch =
|
||||
transport_close_epoch_.load(std::memory_order_acquire);
|
||||
if (close_epoch != handled_close_epoch) {
|
||||
downloader_.setEnabled(false);
|
||||
download_transport_.disconnectIdle();
|
||||
handled_close_epoch = close_epoch;
|
||||
}
|
||||
const bool should_retain_download_transport = downloads_enabled &&
|
||||
screen_visible_.load(std::memory_order_acquire);
|
||||
|
||||
Pyxis::MapTileRequest request{};
|
||||
bool have_request = false;
|
||||
if (lockState(pdMS_TO_TICKS(20))) {
|
||||
if (requests_released_) {
|
||||
if (requests_released_ && should_retain_download_transport) {
|
||||
have_request = presenter_.takeRequest(request);
|
||||
}
|
||||
unlockState();
|
||||
@@ -328,26 +346,25 @@ void MapScreen::workerLoop() {
|
||||
completion.slot_token = request.slot_token;
|
||||
completion.slot_index = request.slot_index;
|
||||
completion.key = request.key;
|
||||
completion.result = loadTile(request);
|
||||
bool frame_drained = false;
|
||||
completion.result = loadTile(request, handled_close_epoch);
|
||||
if (lockState(portMAX_DELAY)) {
|
||||
(void)presenter_.publishCompletion(completion);
|
||||
frame_drained = presenter_.requestCount() == 0U;
|
||||
unlockState();
|
||||
}
|
||||
if (frame_drained) download_transport_.disconnectIdle();
|
||||
}
|
||||
download_transport_.disconnectIdle();
|
||||
worker_exited_.store(true, std::memory_order_release);
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
|
||||
Pyxis::MapTileLoadResult MapScreen::loadTile(
|
||||
const Pyxis::MapTileRequest& request) {
|
||||
const Pyxis::MapTileRequest& request, std::uint32_t transport_epoch) {
|
||||
const Pyxis::MapTileLoadResult cached = readTile(request);
|
||||
if (cached != Pyxis::MapTileLoadResult::MISS &&
|
||||
cached != Pyxis::MapTileLoadResult::INVALID_PNG) return cached;
|
||||
if (decodeFailedFor(request)) return Pyxis::MapTileLoadResult::DOWNLOAD_FAILED;
|
||||
const Pyxis::MapTileLoadResult downloaded = downloadTile(request);
|
||||
const Pyxis::MapTileLoadResult downloaded =
|
||||
downloadTile(request, transport_epoch);
|
||||
if (downloaded != Pyxis::MapTileLoadResult::READY) return downloaded;
|
||||
const Pyxis::MapTileLoadResult decoded = readTile(request);
|
||||
if (decoded == Pyxis::MapTileLoadResult::INVALID_PNG) {
|
||||
@@ -375,10 +392,15 @@ void MapScreen::markDecodeFailed(const Pyxis::MapTileRequest& request) {
|
||||
}
|
||||
|
||||
Pyxis::MapTileLoadResult MapScreen::downloadTile(
|
||||
const Pyxis::MapTileRequest& request) {
|
||||
const Pyxis::MapTileRequest& request, std::uint32_t transport_epoch) {
|
||||
const bool enabled = downloads_enabled_.load(std::memory_order_acquire);
|
||||
downloader_.setEnabled(enabled);
|
||||
if (!enabled) return Pyxis::MapTileLoadResult::MISS;
|
||||
if (!enabled || !screen_visible_.load(std::memory_order_acquire) ||
|
||||
transport_close_epoch_.load(std::memory_order_acquire) != transport_epoch) {
|
||||
downloader_.setEnabled(false);
|
||||
download_transport_.disconnectIdle();
|
||||
return Pyxis::MapTileLoadResult::MISS;
|
||||
}
|
||||
if (download_failed_frame_epoch_ == request.frame_epoch) {
|
||||
return Pyxis::MapTileLoadResult::DOWNLOAD_FAILED;
|
||||
}
|
||||
@@ -393,8 +415,12 @@ Pyxis::MapTileLoadResult MapScreen::downloadTile(
|
||||
|
||||
while (downloader_.isBusy()) {
|
||||
if (stop_requested_.load(std::memory_order_acquire) ||
|
||||
!downloads_enabled_.load(std::memory_order_acquire)) {
|
||||
!downloads_enabled_.load(std::memory_order_acquire) ||
|
||||
!screen_visible_.load(std::memory_order_acquire) ||
|
||||
transport_close_epoch_.load(std::memory_order_acquire) !=
|
||||
transport_epoch) {
|
||||
downloader_.setEnabled(false);
|
||||
download_transport_.disconnectIdle();
|
||||
return Pyxis::MapTileLoadResult::DOWNLOAD_FAILED;
|
||||
}
|
||||
bool stale = false;
|
||||
@@ -662,6 +688,8 @@ bool MapScreen::applyOneCompletion() {
|
||||
}
|
||||
|
||||
void MapScreen::show() {
|
||||
screen_visible_.store(true, std::memory_order_release);
|
||||
if (worker_task_) xTaskNotifyGive(worker_task_);
|
||||
if (lockState(pdMS_TO_TICKS(100))) {
|
||||
presenter_.show();
|
||||
unlockState();
|
||||
@@ -680,6 +708,10 @@ void MapScreen::show() {
|
||||
}
|
||||
|
||||
void MapScreen::hide() {
|
||||
if (screen_visible_.exchange(false, std::memory_order_acq_rel)) {
|
||||
transport_close_epoch_.fetch_add(1U, std::memory_order_acq_rel);
|
||||
}
|
||||
if (worker_task_) xTaskNotifyGive(worker_task_);
|
||||
if (lockState(pdMS_TO_TICKS(100))) {
|
||||
presenter_.hide();
|
||||
unlockState();
|
||||
|
||||
@@ -50,7 +50,12 @@ public:
|
||||
void serviceIo();
|
||||
void updateModel(const Pyxis::MapView::Request& request);
|
||||
void setDownloadEnabled(bool enabled) {
|
||||
downloads_enabled_.store(enabled, std::memory_order_release);
|
||||
const bool was_enabled =
|
||||
downloads_enabled_.exchange(enabled, std::memory_order_acq_rel);
|
||||
if (was_enabled && !enabled) {
|
||||
transport_close_epoch_.fetch_add(1U, std::memory_order_acq_rel);
|
||||
}
|
||||
if (worker_task_) xTaskNotifyGive(worker_task_);
|
||||
}
|
||||
|
||||
// These methods only mutate the pre-created object pool and are invoked
|
||||
@@ -90,6 +95,8 @@ private:
|
||||
Hardware::TDeck::MapTileDownloadConfig download_config_;
|
||||
Hardware::TDeck::MapTileDownloader downloader_;
|
||||
std::atomic<bool> downloads_enabled_;
|
||||
std::atomic<bool> screen_visible_;
|
||||
std::atomic<std::uint32_t> transport_close_epoch_;
|
||||
std::uint32_t download_failed_frame_epoch_;
|
||||
Hardware::TDeck::TileKey decode_failed_keys_[TILE_COUNT];
|
||||
std::uint32_t decode_failed_generations_[TILE_COUNT];
|
||||
@@ -110,9 +117,11 @@ private:
|
||||
|
||||
static void workerEntry(void* context);
|
||||
void workerLoop();
|
||||
Pyxis::MapTileLoadResult loadTile(const Pyxis::MapTileRequest& request);
|
||||
Pyxis::MapTileLoadResult loadTile(const Pyxis::MapTileRequest& request,
|
||||
std::uint32_t transport_epoch);
|
||||
Pyxis::MapTileLoadResult readTile(const Pyxis::MapTileRequest& request);
|
||||
Pyxis::MapTileLoadResult downloadTile(const Pyxis::MapTileRequest& request);
|
||||
Pyxis::MapTileLoadResult downloadTile(const Pyxis::MapTileRequest& request,
|
||||
std::uint32_t transport_epoch);
|
||||
bool decodeFailedFor(const Pyxis::MapTileRequest& request) const;
|
||||
void markDecodeFailed(const Pyxis::MapTileRequest& request);
|
||||
bool startWorker();
|
||||
|
||||
@@ -79,12 +79,25 @@ def test_default_endpoint_uses_current_chain_with_known_fallback_available():
|
||||
def test_downloader_is_explicitly_opt_in_and_wired_only_for_visible_misses():
|
||||
screen = MAP_SCREEN.read_text()
|
||||
settings = SETTINGS.read_text()
|
||||
assert "downloadTile(request)" in screen
|
||||
assert "downloadTile(request, transport_epoch)" in screen
|
||||
assert "downloader_.enqueue(request.key, request.frame_epoch)" in screen
|
||||
assert "presenter_.frameEpoch() != request.frame_epoch" in screen
|
||||
assert "download_failed_frame_epoch_ == request.frame_epoch" in screen
|
||||
assert "presenter_.requestCount() == 0U" in screen
|
||||
assert "download_transport_.disconnectIdle()" in screen
|
||||
worker = screen[screen.index("void MapScreen::workerLoop()"):
|
||||
screen.index("Pyxis::MapTileLoadResult MapScreen::loadTile")]
|
||||
assert "frame_drained" not in worker
|
||||
assert "retain_download_transport" in worker
|
||||
assert "screen_visible_.load(std::memory_order_acquire)" in worker
|
||||
assert "transport_close_epoch_.load(std::memory_order_acquire)" in worker
|
||||
assert "requests_released_ && should_retain_download_transport" in worker
|
||||
assert "download_transport_.disconnectIdle()" in worker
|
||||
assert "screen_visible_.store(true, std::memory_order_release)" in screen
|
||||
assert "screen_visible_.exchange(false, std::memory_order_acq_rel)" in screen
|
||||
assert "transport_close_epoch_.fetch_add(1U, std::memory_order_acq_rel)" in screen
|
||||
download = screen[screen.index("Pyxis::MapTileLoadResult MapScreen::downloadTile"):
|
||||
screen.index("Pyxis::MapTileLoadResult MapScreen::readTile")]
|
||||
assert "!screen_visible_.load(std::memory_order_acquire)" in download
|
||||
assert "transport_close_epoch_.load(std::memory_order_acquire) !=" in download
|
||||
assert 'KEY_MAP_DOWNLOAD = "map_dl"' in settings
|
||||
assert "prefs.getBool(KEY_MAP_DOWNLOAD, false)" in settings
|
||||
assert "Download map tiles:" in settings
|
||||
|
||||
Reference in New Issue
Block a user