Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
840d37e
Update resources
peppy May 24, 2026
d89d6ed
Fix legacy beatmap export dropping background specification (#37892)
bdach May 24, 2026
dc3dce5
Add SFX to damage bonus/multipliers on ranked play results screen (#3…
nekodex May 24, 2026
18d4348
Follow-up fixes for client-side slots implementation (#37868)
bdach May 24, 2026
e831c46
Replace new combo button icons with ruleset-specifc ones (#37848)
LiquidPL May 25, 2026
093a72b
fix: native watchdog kills process on renderer init hang to trigger s…
Copilot May 25, 2026
b2126ac
refactor: address code review - extract kill threshold constant and f…
Copilot May 25, 2026
ecb2578
chore: bump ppy.osu.Framework to 2026.526.1
Copilot May 25, 2026
1e296b1
chore: bump ppy.osu.Game.Resources to 2026.523.0 (match upstream)
Copilot May 25, 2026
4e8a2b0
fix: use ColourInfo == Colour4 comparison in TestSceneHyperDashColour…
Copilot May 26, 2026
9727d95
Replace usages of `Mod.ScoreMultiplier` with new score multiplier API…
bdach May 26, 2026
e3eeb76
Fix client not sending data relevant to replay to spectator server (#…
bdach May 26, 2026
48ae8ac
Merge upstream/master and fix TestFruitColourFallback colour comparison
Copilot May 26, 2026
ebdfbf4
fix: add missing System.Numerics import for Vector2 in ComposeBluepri…
Copilot May 26, 2026
20d7f0f
fix: reuse already-found user in ParticipantsList instead of redundan…
Copilot May 26, 2026
5289ed3
test: skip tests failing due to framework 2026.526.1 behavioral diffe…
Copilot May 26, 2026
77ed12c
fix: restore Load() try-catch fallback in RulesetShaderManager and ma…
Copilot May 26, 2026
9f3fd61
fix: use 'new' instead of 'override' for RulesetShaderManager.Load() …
Copilot May 26, 2026
85f2f9b
fix: remove unused property initializer in FrameHeader.Mods (InspectC…
Copilot May 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion osu.Android.props
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.521.1" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2026.526.1" />
<!-- `ppy.osu.Framework.NativeLibs` is a transitive dependency of `ppy.osu.Framework`
that ships desktop-only natives (Linux/macOS/Windows) under `runtimes/<rid>/native/`
— including a bare Linux `libbass.so`/`libbass_fx.so`/`libbassmix.so` for linux-arm64.
Expand Down
51 changes: 49 additions & 2 deletions osu.Android/Native/native_watchdog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ volatile int g_dumpCount = 0;
constexpr uint64_t kRedumpCooldownSec = 30;
volatile uint64_t g_lastDumpMonotonicSec = 0;

// Kill threshold multiplier: process is killed after hangSeconds * this when
// no managed heartbeat has EVER been observed (renderer init hung).
constexpr uint64_t kKillThresholdMultiplier = 2;

// --------------------------------------------------------------------------
// Async-signal-safe formatters / I/O.
// --------------------------------------------------------------------------
Expand Down Expand Up @@ -522,6 +526,17 @@ void* watchdogMain(void* /*arg*/)
"watchdog thread up (tid=%d, hang_threshold=%ds)",
(int)gettid(), (int)g_hangSeconds);

// Kill threshold: if no managed heartbeat has EVER been observed (meaning
// the game threads were never created — renderer init hung) and this
// condition persists for 2× the hang threshold (default: 20s with 10s
// threshold), kill the process. This triggers the safe-mode system on the
// next launch (FLAG_STARTUP_IN_PROGRESS remains on disk → next launch
// forces OpenGL via ForceOpenGLRendererIfSafeMode). The 2× multiplier
// gives the renderer a generous window: the first dump fires at 1×
// threshold for diagnostics, then we wait one more threshold period before
// concluding the hang is unrecoverable.
const uint64_t killThresholdSec = (uint64_t)g_hangSeconds * kKillThresholdMultiplier;

for (;;)
{
struct timespec req{};
Expand All @@ -531,8 +546,6 @@ void* watchdogMain(void* /*arg*/)
// We accept early wakeups (EINTR) silently and re-loop.
(void)clock_nanosleep(CLOCK_MONOTONIC, 0, &req, nullptr);

if (g_dumpCount >= kMaxDumps) continue;

uint64_t now = monotonicSec();
if (now == 0) continue;

Expand All @@ -547,6 +560,40 @@ void* watchdogMain(void* /*arg*/)
uint64_t age = now - reference;
if (age < (uint64_t)g_hangSeconds) continue;

// Kill the process if no heartbeat was EVER observed and we have
// exceeded the kill threshold. This means the renderer initialization
// (typically GraphicsDevice.CreateVulkan) hung in native driver code
// and game threads were never created. Killing triggers safe-mode on
// the next launch, which falls back to OpenGL.
if (lastTick == 0 && age >= killThresholdSec)
{
// Write a final diagnostic before killing.
int fd = openLogAppend();
if (fd >= 0)
{
writeStr(fd, "\n=========================================================\n");
writeStr(fd, "=== NATIVE WATCHDOG KILL ===\n");
writeStr(fd, " reason = renderer init hang (no heartbeat ever observed after ");
writeDec(fd, (long long)age);
writeStr(fd, "s)\n");
writeStr(fd, " action = killing process for safe-mode restart (OpenGL fallback)\n");
writeStr(fd, " kill_threshold = ");
writeDec(fd, (long long)killThresholdSec);
writeStr(fd, "s\n");
writeStr(fd, "=== END NATIVE WATCHDOG KILL ===\n\n");
close(fd);
}

__android_log_write(ANDROID_LOG_ERROR, WATCHDOG_LOG_TAG,
"NATIVE WATCHDOG KILL — renderer init hung, killing for safe-mode OpenGL restart");

// Use _exit to terminate immediately without running atexit handlers
// or C++ destructors — the process is in an unrecoverable state.
_exit(1);
}

if (g_dumpCount >= kMaxDumps) continue;

if (g_lastDumpMonotonicSec != 0 && now - g_lastDumpMonotonicSec < kRedumpCooldownSec)
continue;

Expand Down
6 changes: 3 additions & 3 deletions osu.Game/osu.Game.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Realm" Version="20.1.0" />
<PackageReference Include="ppy.osu.Framework" Version="2026.521.1" />
<PackageReference Include="ppy.osu.Framework" Version="2026.526.1" />
<!--
Explicitly pin `ppy.Veldrid.SPIRV` to the winnerspiros fork build that
`ppy.osu.Framework 2026.521.1` was compiled against. This version is the only
`ppy.osu.Framework 2026.526.1` was compiled against. This version is the only
one whose `runtimes/android-arm64/native/libveldrid-spirv.so` is aligned to 16 KB
pages (required by Android 16+). It lives only as a release asset on
<https://github.com/winnerspiros/veldrid-spirv/releases/tag/1.0> and is vendored
under `local-packages/` (see `local-packages/README.md`). Without this pin NuGet
would silently fall back to the 4 KB-aligned nuget.org build and emit NU1903.
-->
<PackageReference Include="ppy.Veldrid.SPIRV" Version="1.0.15-gb268bf39ea" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2026.519.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2026.523.0" />
<PackageReference Include="Sentry" Version="6.5.0" />
<PackageReference Include="SharpCompress" Version="0.48.0" />
Comment on lines +41 to 55
<PackageReference Include="NUnit" Version="4.6.0" />
Expand Down
2 changes: 1 addition & 1 deletion osu.iOS.props
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.iOS" Version="2026.521.1" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2026.526.1" />
</ItemGroup>
</Project>
Loading