diff --git a/apps/desktop/linux/runner/CMakeLists.txt b/apps/desktop/linux/runner/CMakeLists.txt index 730c6f4..e97dabc 100644 --- a/apps/desktop/linux/runner/CMakeLists.txt +++ b/apps/desktop/linux/runner/CMakeLists.txt @@ -9,7 +9,6 @@ project(runner LANGUAGES CXX) add_executable(${BINARY_NAME} "main.cc" "my_application.cc" - "hot_restart_guard.cc" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" ) @@ -23,6 +22,5 @@ add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") # Add dependency libraries. Add any application-specific dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter) target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) -target_link_libraries(${BINARY_NAME} PRIVATE ${CMAKE_DL_LIBS}) target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/apps/desktop/linux/runner/hot_restart_guard.cc b/apps/desktop/linux/runner/hot_restart_guard.cc deleted file mode 100644 index c8e4b7a..0000000 --- a/apps/desktop/linux/runner/hot_restart_guard.cc +++ /dev/null @@ -1,69 +0,0 @@ -#include "hot_restart_guard.h" - -#ifdef NDEBUG - -void hot_restart_guard_attach(FlView* view) {} - -#else - -#include -#include -#include - -namespace { - -// Mirrors media_kit's NativeReferenceHolder (debug only): a calloc'd buffer -// of kReferenceBufferSize intptr slots holding live mpv_handle addresses, -// its address written in decimal to /. -constexpr int kReferenceBufferSize = 512; -constexpr char kFilePrefix[] = "com.alexmercerind.media_kit.NativeReferenceHolder."; - -using SetWakeupCallback = void (*)(void* ctx, void (*cb)(void*), void* d); - -SetWakeupCallback find_set_wakeup_callback() { - static const char* const kNames[] = {"libmpv.so.2", "libmpv.so", "libmpv.so.1"}; - for (const char* name : kNames) { - void* lib = dlopen(name, RTLD_NOW | RTLD_NOLOAD); - if (lib == nullptr) continue; - auto fn = reinterpret_cast( - dlsym(lib, "mpv_set_wakeup_callback")); - dlclose(lib); // Drops only the reference NOLOAD added. - if (fn != nullptr) return fn; - } - return nullptr; -} - -// Runs on the engine's UI thread before the old isolate shuts down, so the -// buffer is not being written concurrently. Clearing the callback takes the -// same lock mpv calls it under: once this returns, mpv never calls it again. -// The handles stay in the buffer: media_kit's startup in the new isolate -// still sends them "quit". -void on_pre_engine_restart(FlEngine* engine, gpointer user_data) { - g_autofree gchar* name = g_strdup_printf("%s%d", kFilePrefix, getpid()); - g_autofree gchar* path = g_build_filename(g_get_tmp_dir(), name, nullptr); - g_autofree gchar* contents = nullptr; - if (!g_file_get_contents(path, &contents, nullptr, nullptr)) return; - const guint64 address = g_ascii_strtoull(contents, nullptr, 10); - if (address == 0) return; - const SetWakeupCallback set_wakeup = find_set_wakeup_callback(); - if (set_wakeup == nullptr) return; - const auto* slots = reinterpret_cast(address); - int cleared = 0; - for (int i = 0; i < kReferenceBufferSize; i++) { - if (slots[i] == 0) continue; - set_wakeup(reinterpret_cast(slots[i]), nullptr, nullptr); - cleared++; - } - if (cleared > 0) { - g_message("hot restart: unhooked %d mpv wakeup callback(s)", cleared); - } -} - -} // namespace - -void hot_restart_guard_attach(FlView* view) { - g_signal_connect(fl_view_get_engine(view), "on-pre-engine-restart", - G_CALLBACK(on_pre_engine_restart), nullptr); -} - -#endif diff --git a/apps/desktop/linux/runner/hot_restart_guard.h b/apps/desktop/linux/runner/hot_restart_guard.h deleted file mode 100644 index e876dec..0000000 --- a/apps/desktop/linux/runner/hot_restart_guard.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef RUNNER_HOT_RESTART_GUARD_H_ -#define RUNNER_HOT_RESTART_GUARD_H_ - -#include - -// Debug builds: before a hot restart tears the Dart isolate down, unhooks -// the libmpv wakeup callbacks that media_kit's players point at that -// isolate's NativeCallables. Without this, the next mpv event on a leftover -// player calls into freed code and the process dies (SIGSEGV on mpv's -// "core" thread). No-op in profile/release. -void hot_restart_guard_attach(FlView* view); - -#endif // RUNNER_HOT_RESTART_GUARD_H_ diff --git a/apps/desktop/linux/runner/my_application.cc b/apps/desktop/linux/runner/my_application.cc index 90877d0..ce91967 100644 --- a/apps/desktop/linux/runner/my_application.cc +++ b/apps/desktop/linux/runner/my_application.cc @@ -6,7 +6,6 @@ #endif #include "flutter/generated_plugin_registrant.h" -#include "hot_restart_guard.h" struct _MyApplication { GtkApplication parent_instance; @@ -88,7 +87,6 @@ static void my_application_activate(GApplication* application) { gtk_widget_realize(GTK_WIDGET(view)); fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - hot_restart_guard_attach(view); gtk_widget_grab_focus(GTK_WIDGET(view)); } diff --git a/apps/desktop/pubspec.lock b/apps/desktop/pubspec.lock index eaa6086..3ef066b 100644 --- a/apps/desktop/pubspec.lock +++ b/apps/desktop/pubspec.lock @@ -228,11 +228,11 @@ packages: dependency: "direct main" description: path: "." - ref: "v0.1.7" - resolved-ref: dc16bba05491f54daf528ed83484ea9b6eab8825 + ref: "v0.1.8" + resolved-ref: d2435a06b26d4f94c3c3777e6ef006ac84f4eef4 url: "https://git.senkochan.moe/Foxyz/fox_utils.git" source: git - version: "0.1.7" + version: "0.1.8" hive_ce: dependency: "direct main" description: diff --git a/apps/desktop/pubspec.yaml b/apps/desktop/pubspec.yaml index da49832..51580b9 100644 --- a/apps/desktop/pubspec.yaml +++ b/apps/desktop/pubspec.yaml @@ -29,7 +29,7 @@ dependencies: fox_utils: git: url: https://git.senkochan.moe/Foxyz/fox_utils.git - ref: v0.1.7 + ref: v0.1.8 dev_dependencies: flutter_test: sdk: flutter diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md index b357bbe..067a36c 100644 --- a/docs/DEVELOPMENT.md +++ b/docs/DEVELOPMENT.md @@ -131,11 +131,11 @@ unexpectedly` line just before it is expected. Without the app: - Hot restart with any media_kit `Player` alive (session, thumbnails, sfx) used to SIGSEGV on mpv's `core` thread: each mpv handle's wakeup callback is a `NativeCallable` of the old isolate, freed by the restart, and media_kit - then sends the leftover handles `quit`, which fires it. The Linux runner - (`linux/runner/hot_restart_guard.cc`, debug builds only) clears those - callbacks on the engine's `on-pre-engine-restart` signal, reading the - handles from media_kit's debug-only `NativeReferenceHolder` buffer (address - in `$TMPDIR/com.alexmercerind.media_kit.NativeReferenceHolder.`). Old + then sends the leftover handles `quit`, which fires it. `fox_utils`' Linux + plugin (from 0.1.8, debug builds only) clears those callbacks on the + engine's `on-pre-engine-restart` signal, reading the handles from + media_kit's debug-only `NativeReferenceHolder` buffer (address in + `$TMPDIR/com.alexmercerind.media_kit.NativeReferenceHolder.`). Old players are leaked, not destroyed, until the process exits. Re-check this after a media_kit upgrade. - mpv reconnect flags: comma form works, colon form is rejected. Re-verify