Hot-restart guard comes from fox_utils 0.1.8 (shared with other media_kit apps)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d002ff6941
commit
b2b77a6b3f
7 files changed
+9
-95
No files matched your search
@@ -9,7 +9,6 @@ project(runner LANGUAGES CXX)
|
|||||||
add_executable(${BINARY_NAME}
|
add_executable(${BINARY_NAME}
|
||||||
"main.cc"
|
"main.cc"
|
||||||
"my_application.cc"
|
"my_application.cc"
|
||||||
"hot_restart_guard.cc"
|
|
||||||
"${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.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.
|
# Add dependency libraries. Add any application-specific dependencies here.
|
||||||
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
target_link_libraries(${BINARY_NAME} PRIVATE flutter)
|
||||||
target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK)
|
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}")
|
target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#include "hot_restart_guard.h"
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
|
|
||||||
void hot_restart_guard_attach(FlView* view) {}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
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 <tmp>/<kFilePrefix><pid>.
|
|
||||||
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<SetWakeupCallback>(
|
|
||||||
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<const intptr_t*>(address);
|
|
||||||
int cleared = 0;
|
|
||||||
for (int i = 0; i < kReferenceBufferSize; i++) {
|
|
||||||
if (slots[i] == 0) continue;
|
|
||||||
set_wakeup(reinterpret_cast<void*>(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
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#ifndef RUNNER_HOT_RESTART_GUARD_H_
|
|
||||||
#define RUNNER_HOT_RESTART_GUARD_H_
|
|
||||||
|
|
||||||
#include <flutter_linux/flutter_linux.h>
|
|
||||||
|
|
||||||
// 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_
|
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "flutter/generated_plugin_registrant.h"
|
#include "flutter/generated_plugin_registrant.h"
|
||||||
#include "hot_restart_guard.h"
|
|
||||||
|
|
||||||
struct _MyApplication {
|
struct _MyApplication {
|
||||||
GtkApplication parent_instance;
|
GtkApplication parent_instance;
|
||||||
@@ -88,7 +87,6 @@ static void my_application_activate(GApplication* application) {
|
|||||||
gtk_widget_realize(GTK_WIDGET(view));
|
gtk_widget_realize(GTK_WIDGET(view));
|
||||||
|
|
||||||
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
fl_register_plugins(FL_PLUGIN_REGISTRY(view));
|
||||||
hot_restart_guard_attach(view);
|
|
||||||
|
|
||||||
gtk_widget_grab_focus(GTK_WIDGET(view));
|
gtk_widget_grab_focus(GTK_WIDGET(view));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,11 +228,11 @@ packages:
|
|||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
path: "."
|
path: "."
|
||||||
ref: "v0.1.7"
|
ref: "v0.1.8"
|
||||||
resolved-ref: dc16bba05491f54daf528ed83484ea9b6eab8825
|
resolved-ref: d2435a06b26d4f94c3c3777e6ef006ac84f4eef4
|
||||||
url: "https://git.senkochan.moe/Foxyz/fox_utils.git"
|
url: "https://git.senkochan.moe/Foxyz/fox_utils.git"
|
||||||
source: git
|
source: git
|
||||||
version: "0.1.7"
|
version: "0.1.8"
|
||||||
hive_ce:
|
hive_ce:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ dependencies:
|
|||||||
fox_utils:
|
fox_utils:
|
||||||
git:
|
git:
|
||||||
url: https://git.senkochan.moe/Foxyz/fox_utils.git
|
url: https://git.senkochan.moe/Foxyz/fox_utils.git
|
||||||
ref: v0.1.7
|
ref: v0.1.8
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|||||||
+5
-5
@@ -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)
|
- 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
|
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
|
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
|
then sends the leftover handles `quit`, which fires it. `fox_utils`' Linux
|
||||||
(`linux/runner/hot_restart_guard.cc`, debug builds only) clears those
|
plugin (from 0.1.8, debug builds only) clears those callbacks on the
|
||||||
callbacks on the engine's `on-pre-engine-restart` signal, reading the
|
engine's `on-pre-engine-restart` signal, reading the handles from
|
||||||
handles from media_kit's debug-only `NativeReferenceHolder` buffer (address
|
media_kit's debug-only `NativeReferenceHolder` buffer (address in
|
||||||
in `$TMPDIR/com.alexmercerind.media_kit.NativeReferenceHolder.<pid>`). Old
|
`$TMPDIR/com.alexmercerind.media_kit.NativeReferenceHolder.<pid>`). Old
|
||||||
players are leaked, not destroyed, until the process exits. Re-check this
|
players are leaked, not destroyed, until the process exits. Re-check this
|
||||||
after a media_kit upgrade.
|
after a media_kit upgrade.
|
||||||
- mpv reconnect flags: comma form works, colon form is rejected. Re-verify
|
- mpv reconnect flags: comma form works, colon form is rejected. Re-verify
|
||||||
|
|||||||
Reference in new issue
Block a user