Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🐧] GNU+Linux compatibility progress #1430

Open
37 of 42 tasks
YoshiRulz opened this issue Jan 7, 2019 · 243 comments
Open
37 of 42 tasks

[🐧] GNU+Linux compatibility progress #1430

YoshiRulz opened this issue Jan 7, 2019 · 243 comments
Labels
App: EmuHawk Relating to EmuHawk frontend Meta Relating to code organisation or to things that aren't code re: Multiplatform Relating to the Linux and macOS ports (Mono Framework, and eventually .NET Core)

Comments

@YoshiRulz
Copy link
Member

YoshiRulz commented Jan 7, 2019

jump to known bugs

Overview:

  • Nothing on this page applies to the (discontinued) macOS port.
  • Build instructions are in the readme. tl;dr: run Dist/BuildRelease.sh.
  • "Installation" instructions are also in the readme. tl;dr: run output/EmuHawkMono.sh.
    • No WINE required! If you get it working in WINE, good for you, but I'm going to ignore you and hide any counter-productive comments.
  • 35-ish of 40-ish systems can be emulated, with the notable exception of N64 (Mupen64Plus isn't available, and the experimental Ares64 core is too slow).
  • For casual players, most things work as they would on Windows.
  • For TASers, most things work as they would on Windows.
  • For glitch hunters and romhackers, everything sucks and I'm sorry. But if a core is available on Linux, and the core implements the necessary services for a tool, then it should be at least functional.
  • Before 2.9.2:
    • Command-line flags to EmuHawkMono.sh are passed through as expected. The single exception is if you pass --mono-no-redirect as the first flag, which disables redirecting stdout/stderr to EmuHawkMono_last*.txt (the default behaviour is to write to disk instead of the terminal).
    • When it inevitably crashes, some errors go to the terminal/EmuHawkMono_last*.txt, some appear in dialog boxes, some both. Most of these error dialogs will either have a "Copy" button, or will allow Ctrl+C.

As of 2.9.1, the following systems can be emulated:

  • Apple II with Virtu
  • Arcades with MAME
  • Atari 2600 with Atari2600Hawk
  • Atari 7800 with A7800Hawk
  • Atari Jaguar with VirtualJaguar
  • Atari Lynx with Handy
  • ColecoVision with ColecoHawk
  • Commodore 64 with C64Hawk (loads to BASIC prompt, at least --yoshi)
  • Game Boy and GBC with Gambatte, GBHawk, or SameBoy
  • GBA with mGBA
  • Intellivision with IntelliHawk
  • Magnavox Odyssey² with O2Hawk
  • MSX with MSXHawk
  • N64 with Ares64
  • Neo Geo Pocket / Color with NeoPop
  • NES/Famicom plus FDS with NesHawk or QuickNes
  • Nintendo DS with melonDS
  • Nintendo Virtual Boy with Virtual Boyee
  • PC Engine / TG-16 and SuperGrafx plus CD with HyperNyma, PCEHawk, or TurboNyma
  • PC-FX with T.S.T.
  • PSX with Nymashock
  • Sega 32X with PicoDrive
  • Sega CD with Genplus-gx
  • Sega Game Gear with SMSHawk
  • Sega Genesis / Mega Drive with Genplus-gx
  • Sega Master System with SMSHawk
  • Sega Saturn with Saturnus (see "Issues with Saturnus" below)
  • Sega SG-1000 SMSHawk
  • SNES/SFC with BSNES, Faust, or Snes9x
  • Super Game Boy with Gambatte or BSNES
  • TI-83 with Emu83 or TI83Hawk
  • TIC-80 fantasy console with TIC-80 reference implementation
  • Uzebox fantasy console with Uzem
  • Vectrex with VectrexHawk
  • WonderSwan / Color with Cygne
  • ZX Spectrum with ZXHawk
  • Anything else via Libretro cores (provided they don't crash)

These systems haven't been tested or aren't finished:

  • 3DS with Encore (I don't have roms --yoshi)
  • Amstrad CPC with CPCHawk (unreleased core)
  • Channel F with ChannelFHawk (unreleased core)
  • N64DD with Ares64 (I don't have roms --yoshi)
  • Sega Pico with Genplus-gx (I don't have roms --yoshi)

These features/subsystems work:

  • The core lifecycle i.e. loading roms (for the systems noted above)
  • Savestates
  • Virtual Pad
  • Tool Box
  • Lua Console (scripts can load, YMMV)
  • Config > Controllers... and Config > Hotkeys...
    • Keyboard, mouse, and gamepad inputs, and from 2.9.2, haptic feedback
  • Config > Display...
  • Config > Sound...
  • Config > Paths...
  • Config > Firmwares...
  • Config > Autofire...
  • Config > Customize...
  • Config > Profiles...
  • Core selector (Config > Cores)
  • View > Window Size
  • Misc. OSD layers under View
  • Lua (from 2.9, same as Windows, before 2.9 see [🐧] Lua in Mono megathread #2951)
  • External tools (ApiHawk)
  • Movie playback, "traditional" movie recording
  • TAStudio (basic functionality is good)
  • Tools > RAM Watch
  • Hex Editor (works as of 625c657)
  • RAM Search
  • Tools > Cheats (does not crash)
  • Basic Bot (opens as of 1dbcdcd)
  • RetroAchievements
@YoshiRulz
Copy link
Member Author

YoshiRulz commented Jan 7, 2019

Issues with EmuHawk

Startup issues:

  • An InvalidOperationException with "Error compiling shader", "syntax error, unexpected KW_SAMPLER_STATE" (stacktrace will include the IGL_SlimDX9.CreateVertexShader method, which has since been removed): Seems to be a bug in WINE's GPU drivers. WINE is not supported, so just stop using it and you won't hit this.

Misc. issues:

  • Mono seemingly ignores the GTK theme... on my machine >:( Meaning everything is ugly and there's nothing we can do about it. TBH it's kinda ugly on Win10 too. band-aid applied 62f90f1
    • ...though with Nix you can see Gtk not found (missing LD_LIBRARY_PATH to libgtk-x11-2.0.so.0?), using built-in colorscheme in stderr which implies it's looking for a GTK theme??? And several users have complained about their system-wide dark theme being partially applied, to bad results, so it's at least sometimes finding one. (Bad results because my band-aid fix is light theme. Without that, EmuHawk would be mostly dark theme, but still ugly, and it may have a lot of unreadable text.)
    • with b967e60, either all or none of the menubar colours come from the GTK theme, so if you're lucky enough to have your dark theme detected, it doesn't have ugly gradients! Some of our icons have white crusts on them, but oh well. Eventually, they'll all be replaced. If you're lucky enough to have your dark theme applied, and you notice one of the menubars or one specific UI element is light theme, please report it as I'm now classing that as a bug. --yoshi
    • As a result, some icons in e.g. open file dialogs are missing. Hope you remember which is the parent directory button!
  • I think file extensions are case-sensitive on Mono. The rom loader dialog doesn't recognise my .32X file as a rom. fixed in f8a688d
  • (unthrottled) FPS triples when window unfocused. Is input slowing it down? who knows --yoshi
    • actually I can't repro this --yoshi at 25a5449
    • dwango repro'd this on stream. still no idea why it happens. --yoshi
    • Still can't repro, no change when swapping out OpenTKInputAdapter for a DummyInputAdapter --yoshi at 24f69eb
    • Repro'd on NixOS, both on 2.9.1 and at ebe3cad, though it's a very small difference in Release config. --yoshi
  • Keyboard shortcuts in RAM Watch don't work. ToolStripMenuItem.ShortcutKeys isn't working at all.
    • Just looked into this again with TAStudo and ProcessCmdKey isn't even being called. --yoshi at 681ef72
  • Menubar mnemonics are disabled. Past me did it to prevent a crash, needs retesting. --yoshi at 03d10ce
    • enabled on MainForm as of 28d62e6
    • not working on other Forms --yoshi at 28d62e6
    • probably same cause as ShortcutKeys --yoshi at 681ef72
  • Some file open dialogs cause a ArgumentOutOfRangeException in System.DateTimeOffset.FromUnixTimeSeconds(long). --yoshi at 03d10ce
  • In IToolFormAutoConfigs, Settings > Stay on Top correctly writes Window.KeepAbove = !item.Checked, but does not read the actual value i.e. toggling keep-above via the WM does not change the checkbox's state. I suggest this menu item be disabled on Linux (and macOS?). --yoshi at 03d10ce
    • Fixed in 329a7de (by hiding the menu item).
  • Defaults for Config > Paths... could be changed to standards like $XDG_CONFIG_HOME. Making this change to system-global dirs would break from the "portable app" precedent. --yoshi
    • Sorta done in NixHawk
  • Users with only an Intel iGPU (i.e. no discrete GPU) may get i965: Failed to submit batchbuffer: Invalid argument. Try LIBGL_ALWAYS_SOFTWARE=1 ./EmuHawkMono.sh or otherwise setting that environment variable. (workaround found by @InfamousKnight)
  • Dialogs which pause emulation should cause the current frame to be redrawn to MainForm, but instead drawing stops and you get the solitaire effect. --yoshi at 268ab96
  • Possibly related, under Plasma Wayland on NixOS: "open file" dialogs sometimes result in empty black windows, which then become "infectious" and result in even the main window only showing black, which persists until user logout / compositor shutdown. --bugQ
  • Dropdowns not closing: WinForms - ToolStrip dropdowns do not close properly mono/mono#12644 --yoshi at 42fc895
    • workaround added in 653844e (sorry I didn't do that sooner --yoshi)
  • Controls in RecordMovie (dialog asking for filename and author for new movie) are misplaced, making keyboard navigation a requirement for recording movies (without TAStudio) --yoshi at 9e60927
  • If you get an error like "GDI+ status: InvalidParameter" at System.Drawing.Image.get_FrameDimensionsList, try updating libgdiplus.
  • Hard crash when clicking+dragging scrollbar in OpenFileDialog. Nothing in stdout or stderr. ¯\_(ツ)_/¯
    • Similarly, random hard crashes when clicking+dragging scrollbar in core settings dialogs, then moving cursor over the button of a dropdown menu without releasing the mouse button.
  • In Hex Editor, opening context menu causes scroll wheel and arrow keys to have no effect until the window is unfocused and refocused.
  • Log Window threading is fragile, see LogWindow something causes crash on Mono #2741.
  • Starting Mono while the solution is being rebuild will, rather than hitting the version check in EmuHawk.Program, cause Mono to segfault. (Not before init'ing GTK, though. I swear it's taunting me.)
  • May be NixOS-specific, but it seems idling with Lua scripts running+drawing but emulation paused causes the Lua Console (possible all WinForms UI?) to freeze, and unpausing emulation fixes it immediately...
    • It also seems to unpause for no reason? Does it think I closed a menu and it was only temp. paused?
  • RetroAchievements dialogs aren't great, but they are technically usable
  • From 2.9.2, SDL2 handles sleep prevention, but while it's implemented for Linux (X11), it's not working in practice. See BizHawk does not inhibit display or system sleep while running #3644 (comment).
  • PictureBox applies anti-aliasing/interpolation to pixel graphics: NES PPU Viewer's "zoom box" shouldn't be anti-aliased #3764

Cores

Issues with Mupen

System.InvalidOperationException: got null pointer from dlopen, error: libmupen64plus.so.2: cannot open shared object file: No such file or directory (or, if standalone Mupen64Plus is installed, System.InvalidOperationException: got null pointer from dlopen, error: /usr/lib/mupen64plus: cannot read file data: Is a directory) from mupen64plusApi ctor --yoshi at 25a5449
fixed in 6e46cb5

Issues with TI83Hawk

  • IndexOutOfRangeException at BizHawk.Emulation.Cores.Calculators.TI83.ReadMemory(ushort) --yoshi at 25a5449

Building and packaging

Dependencies are being recorded (so build scripts can be made) in the GitLab mirror's snippets. On multi-arch distros, target x86_64/amd64.

For the record I've mostly focused on Manjaro (which I use), Nix/NixOS, Linux Mint, and Ubuntu. --yoshi

Bus error (core dumped) when building may be because you're out of disk space.

libblip_buf works as intended on both OSes, but the Makefile for Linux builds was hacked together (see libblip_buf issue tracker) and using the library in BizHawk was intended to be a temporary hack. The library has been rewritten as noted in #1312. Sappharad has previously attempted moving it to managed C#. It may be possible to use libspeex instead. they serve different purposes according to #3207 (comment) --yoshi

Don't know where else to leave these:

  • Debug P/Invokes (.dll/.so loading) with MONO_LOG_LEVEL=debug MONO_LOG_MASK=dll ./EmuHawkMono.sh --mono-no-redirect.
  • It seems libgdiplus.so doesn't support whatever the "PNG 256x256" mode of .icos is.

@nattthebear

This comment has been minimized.

@Sappharad

This comment has been minimized.

@alyosha-tas

This comment was marked as outdated.

@YoshiRulz

This comment has been minimized.

@Asnivor

This comment was marked as outdated.

@YoshiRulz

This comment was marked as outdated.

@Asnivor

This comment was marked as outdated.

@nattthebear

This comment has been minimized.

@Sappharad

This comment has been minimized.

@Asnivor

This comment has been minimized.

@nattthebear

This comment has been minimized.

@Asnivor

This comment has been minimized.

@YoshiRulz

This comment has been minimized.

@Asnivor

This comment has been minimized.

@nattthebear

This comment has been minimized.

@nattthebear

This comment has been minimized.

@Asnivor

This comment has been minimized.

@nattthebear

This comment has been minimized.

@lsthiros

This comment was marked as outdated.

@YoshiRulz

This comment has been minimized.

Asnivor added a commit to Asnivor/BizHawk that referenced this issue Jan 14, 2019
EmuHawk: SharpCompress implementation for Mono - TASEmulators#1430
Asnivor added a commit to Asnivor/BizHawk that referenced this issue Jan 15, 2019
…licks 'open firmware folder'. This mitigates the 'Folder open dialog crash' referenced in TASEmulators#1430
Asnivor added a commit to Asnivor/BizHawk that referenced this issue Jan 16, 2019
@YoshiRulz

This comment has been minimized.

@YoshiRulz
Copy link
Member Author

Nope, or at least, not in the same overlay folder. The emuhawk-monort-2.9.2-local wrapper script sets $BIZHAWK_HOME to /nix/store/...-bizhawk-asms-and-wbox, which doesn't contain an Assets folder at all. Instead, it exists in two different places: /nix/store/...-BizHawk-2.9.2-local/Assets and /nix/store/...-BizHawk-2.9.2-local-assets.

I tried following along the nix build scripts to see what's really happening with Assets but got quite lost.

It's probably clearer if you follow the launch scripts starting with result/bin/emuhawk-monort-2.9.2-local. There's a check for whether $XDG_DATA_HOME/emuhawk-monort-2.9.2-local exists, and if not, it's initialised by copying the assets from the Nix store. So if you update to a new dev build, new assets won't be copied.

@YoshiRulz
Copy link
Member Author

Every time i try to draw some text on a display it absolutely looks horrible and unreadable when i compare with windows users.

I suspect this is because we render text to the surface and then scale everything up at the end, rather than scaling up the frame then rendering text at a larger size on a larger surface.

@Luxadevi
Copy link

Luxadevi commented Feb 1, 2024

Every time i try to draw some text on a display it absolutely looks horrible and unreadable when i compare with windows users.

I suspect this is because we render text to the surface and then scale everything up at the end, rather than scaling up the frame then rendering text at a larger size on a larger surface.

Yeah i already suspected something like that was happening. When i made the font/TextSize bigger the quality got better and better.
Would there be a "hacky" way to maybe do a dirty pass of a bigger font and then downscale the text for the time being?
What makes the workflow/pipeline different from the windows one, because this was not accidental i suppose?

@Luxadevi
Copy link

Luxadevi commented Feb 1, 2024

Every time i try to draw some text on a display it absolutely looks horrible and unreadable when i compare with windows users.

I suspect this is because we render text to the surface and then scale everything up at the end, rather than scaling up the frame then rendering text at a larger size on a larger surface.

Funny thing actually;
I've build a ubuntu GUI container with BizHawk and that runs perfectly, has the right text quality and looks like no scaling issues.

@SandTAS
Copy link

SandTAS commented Mar 11, 2024

Summary

A certain combination of memorysavestate and coroutines in a Lua script crashes the Gambatte core with a SIGSEGV. It does not crash the GBHawk core.

Repro

  1. Run ./EmuHawkMono.sh with any ROM.

  2. Load or toggle crash_gambatte.lua while the "Nintendo" animation is playing. See main coroutine start in the Lua console.The script will make the emulator enter a loop of: advance 8 frames, reset 7 frames, advance 8 frames, reset 7 frames, and so on. That part is expected.

    crash_gambatte.lua
    -- Demonstrates a crash of the Gambatte core in BizHawk-2.9.1-linux-x64.
    -- Run ./EmuHawkMono.sh with any ROM. Load or toggle this script any time
    -- before the "Nintendo" boot animation finishes. Around frame 330, just after
    -- the animation is finished, the Gambatte core crashes.
    
    -- Run the emulator until the start of the next frame.
    local function run_one_frame()
    	local co = coroutine.running()
    	local frame_event_id = event.onframestart(function ()
    		assert(coroutine.resume(co))
    	end)
    	coroutine.yield()
    	assert(event.unregisterbyid(frame_event_id))
    end
    
    -- Run the emulator until it is about to execute addr, or until frame_limit
    -- frames have elapsed, whichever occurs first. Return false if frame_limit was
    -- reached, or true if the exec address was reached.
    local function run_until_exec(frame_limit, addr)
    	local co = coroutine.running()
    	local frame_count = 0
    	local frame_event_id = event.onframestart(function ()
    		if frame_limit ~= nil then
    			frame_count = frame_count + 1
    			if frame_count >= frame_limit then
    				assert(coroutine.resume(co, false))
    			end
    		end
    	end)
    	local event_id = event.on_bus_exec(function ()
    		assert(coroutine.resume(co, true))
    	end, addr)
    	local result = coroutine.yield()
    	assert(event.unregisterbyid(frame_event_id))
    	assert(event.unregisterbyid(event_id))
    	return result
    end
    
    -- Find the earliest frame, starting from the current frame, at which executing
    -- action causes a predicate test function to return true.
    --
    -- Execute action, then execute test (which generally will run the emulator for
    -- a few frames and check a condition). If test returns true, reset the
    -- emulator to the state just after executing action, and return. If test
    -- returns false, try the whole thing again, this time executing action one
    -- frame later. Continue doing this until finding a frame where executing
    -- action causes test() to become true.
    local function earliest_effective_frame(action, test)
    	local savestate_id = memorysavestate.savecorestate()
    	while true do
    		action()
    		if test() then
    			-- Reset to just after the action occurred.
    			-- (No crash occurs if this final loadcorestate is commented out.)
    			memorysavestate.loadcorestate(savestate_id)
    			action()
    			return
    		end
    		-- No luck with this frame. Reload the savestate
    		-- and try doing the action one frame later.
    		memorysavestate.loadcorestate(savestate_id)
    		run_one_frame()
    		memorysavestate.removestate(savestate_id)
    		savestate_id = memorysavestate.savecorestate()
    	end
    	memorysavestate.removestate(savestate_id)
    	assert(status, err)
    end
    
    assert(coroutine.resume(coroutine.create(function ()
    	console.log("main coroutine start")
    
    	-- For crash demo purposes, find the earliest frame that is within 8
    	-- frames of the "Nintendo" boot animation finishing.
    	earliest_effective_frame(function ()
    		-- no action required for crash demo
    	end, function ()
    		return run_until_exec(8, 0x00fe) -- last instruction in GB boot ROM
    	end)
    
    	console.log("main coroutine end")
    end)))
  3. Around frame 330, BizHawk crashes.

Output

=================================================================
	Native Crash Reporting
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================
EmuHawkMono_laststdout.txt
Using OpenTK 3 for host input (keyboard + gamepads)
GB
Core reported BoardID: "NULL"
Active Firmwares:
  GB+World : 4ED31EC6B0B175BB109C0EB5FD3D193DA823339F

=================================================================
	Native Crash Reporting
=================================================================
Got a SIGSEGV while executing native code. This usually indicates
a fatal error in the mono runtime or one of the native libraries 
used by your application.
=================================================================

=================================================================
	Native stacktrace:
=================================================================
	0x5588a72a303c - mono : (null)
	0x5588a72a33dc - mono : (null)
	0x5588a725201c - mono : (null)
	0x5588a729cac1 - mono : (null)
	0x7fe6c2d9667a - /usr/lib/x86_64-linux-gnu/libc.so.6 : (null)
	0x7fe6c24c9d70 - Unknown

=================================================================
	Telemetry Dumper:
=================================================================
Pkilling 0x7fe6a4bff6c0 from 0x7fe6c2cf1bc0
Pkilling 0x7fe6a47fd6c0 from 0x7fe6c2cf1bc0
Pkilling 0x7fe6b457f6c0 from 0x7fe6c2cf1bc0
Pkilling 0x7fe6bfdff6c0 from 0x7fe6c2cf1bc0
Pkilling 0x7fe676c036c0 from 0x7fe6c2cf1bc0
Pkilling 0x7fe677fff6c0 from 0x7fe6c2cf1bc0
Pkilling 0x7fe6a49fe6c0 from 0x7fe6c2cf1bc0
Pkilling 0x7fe6b437e6c0 from 0x7fe6c2cf1bc0
Pkilling 0x7fe69697b6c0 from 0x7fe6c2cf1bc0
Pkilling 0x7fe6b7fff6c0 from 0x7fe6c2cf1bc0
Entering thread summarizer pause from 0x7fe6c2cf1bc0
Finished thread summarizer pause from 0x7fe6c2cf1bc0.
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing
NULL handle mono-state mem on freeing

Waiting for dumping threads to resume
NULL handle mono-state mem on freeing

=================================================================
	Basic Fault Address Reporting
=================================================================
Memory around native instruction pointer (0x7fe6c2d9667a):0x7fe6c2d9666a  84 00 00 00 00 00 40 0f b6 c6 48 89 d1 48 89 fa  ......@...H..H..
0x7fe6c2d9667a  f3 aa 48 89 d0 c3 66 48 0f 7e c6 83 fa 08 7d 16  ..H...fH.~....}.
0x7fe6c2d9668a  83 fa 04 7d 1a 83 fa 01 7f 1c 7c 03 40 88 37 c3  ...}......|.@.7.
0x7fe6c2d9669a  66 0f 1f 44 00 00 48 89 37 48 89 74 17 f8 c3 89  f..D..H.7H.t....

=================================================================
	Managed Stacktrace:
=================================================================
	  at <unknown> <0xffffffff>
	  at BizHawk.Emulation.Cores.Nintendo.Gameboy.LibGambatte:gambatte_runfor <0x000f6>
	  at BizHawk.Emulation.Cores.Nintendo.Gameboy.Gameboy:FrameAdvance <0x000bb>
	  at BizHawk.Client.EmuHawk.MainForm:StepRunLoop_Core <0x00957>
	  at BizHawk.Client.EmuHawk.MainForm:ProgramRunLoop <0x004f3>
	  at BizHawk.Client.EmuHawk.MainForm:ProgramRunLoop <0x00073>
	  at BizHawk.Client.EmuHawk.Program:SubMain <0x013b7>
	  at BizHawk.Client.EmuHawk.Program:Main <0x0002b>
	  at <Module>:runtime_invoke_int_object <0x00091>
=================================================================
EmuHawkMono_laststderr.txt

=================================================================
	External Debugger Dump:
=================================================================
[New LWP 14149]
[New LWP 14150]
[New LWP 14153]
[New LWP 14161]
[New LWP 14162]
[New LWP 14163]
[New LWP 14164]
[New LWP 14165]
[New LWP 14166]
[New LWP 14167]
[New LWP 14168]
[New LWP 14175]
[New LWP 14176]
[New LWP 14179]
[New LWP 14180]
[New LWP 14181]
[New LWP 14190]
[New LWP 14191]
[New LWP 14192]
[New LWP 14193]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/x86_64-linux-gnu/libthread_db.so.1".
0x00007fe6c2dc6b57 in __GI___wait4 (pid=14209, stat_loc=0x7fff0b637624, options=0, usage=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:30
30	../sysdeps/unix/sysv/linux/wait4.c: No such file or directory.
  Id   Target Id                                           Frame 
* 1    Thread 0x7fe6c2cf1bc0 (LWP 14148) "mono"            0x00007fe6c2dc6b57 in __GI___wait4 (pid=14209, stat_loc=0x7fff0b637624, options=0, usage=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:30
  2    Thread 0x7fe6c23ff6c0 (LWP 14149) "SGen worker"     __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588a76a27a8) at ./nptl/futex-internal.c:57
  3    Thread 0x7fe6bfdff6c0 (LWP 14150) "Finalizer"       __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588a76935e0) at ./nptl/futex-internal.c:57
  4    Thread 0x7fe6b7fff6c0 (LWP 14153) "mono"            __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x7fe6b7ffe690, op=137, expected=0, futex_word=0x5588a76a2e48) at ./nptl/futex-internal.c:57
  5    Thread 0x7fe6b757b6c0 (LWP 14161) "mono:disk$0"     __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588aa0e7938) at ./nptl/futex-internal.c:57
  6    Thread 0x7fe6b63d26c0 (LWP 14162) "mono:disk$0"     __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588aa58d318) at ./nptl/futex-internal.c:57
  7    Thread 0x7fe6b6d7a6c0 (LWP 14163) "mono:gdrv0"      __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588aa69afa0) at ./nptl/futex-internal.c:57
  8    Thread 0x7fe6b457f6c0 (LWP 14164) "mono"            __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x7fe6b457ec60, op=137, expected=0, futex_word=0x5588a76a2e48) at ./nptl/futex-internal.c:57
  9    Thread 0x7fe6b437e6c0 (LWP 14165) "Thread Pool Wor" __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x7fe6b437dd10, op=393, expected=0, futex_word=0x5588a7693ec8) at ./nptl/futex-internal.c:57
  10   Thread 0x7fe6a4bff6c0 (LWP 14166) "Thread Pool Wor" __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x7fe6a4bfed10, op=393, expected=0, futex_word=0x5588a7693ec8) at ./nptl/futex-internal.c:57
  11   Thread 0x7fe6a49fe6c0 (LWP 14167) "Thread Pool Wor" __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x7fe6a49fdd10, op=393, expected=0, futex_word=0x5588a7693ec8) at ./nptl/futex-internal.c:57
  12   Thread 0x7fe6a47fd6c0 (LWP 14168) "Thread Pool Wor" __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x7fe6a47fcd10, op=393, expected=0, futex_word=0x5588a7693ec8) at ./nptl/futex-internal.c:57
  13   Thread 0x7fe6951916c0 (LWP 14175) "mono:disk$0"     __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588ab19d128) at ./nptl/futex-internal.c:57
  14   Thread 0x7fe69617a6c0 (LWP 14176) "mono:gdrv0"      __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588ab286770) at ./nptl/futex-internal.c:57
  15   Thread 0x7fe677fff6c0 (LWP 14179) "mono"            0x00007fe6c2def15f in __GI___poll (fds=0x7fe677ffe688, nfds=1, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
  16   Thread 0x7fe69697b6c0 (LWP 14180) "mono"            __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x7fe69697a700, op=137, expected=0, futex_word=0x5588a76a2e48) at ./nptl/futex-internal.c:57
  17   Thread 0x7fe676c036c0 (LWP 14181) "mono"            __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x7fe676c02680, op=137, expected=0, futex_word=0x5588a76a2e48) at ./nptl/futex-internal.c:57
  18   Thread 0x7fe67605b6c0 (LWP 14190) "threaded-ml"     0x00007fe6c2def15f in __GI___poll (fds=0x7fe6680071e0, nfds=2, timeout=1172) at ../sysdeps/unix/sysv/linux/poll.c:29
  19   Thread 0x7fe6756cf6c0 (LWP 14191) "mono"            __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x7fe64c000f08) at ./nptl/futex-internal.c:57
  20   Thread 0x7fe674ca76c0 (LWP 14192) "mono"            __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588ab5dc8c0) at ./nptl/futex-internal.c:57
  21   Thread 0x7fe674aa66c0 (LWP 14193) "mono:gdrv0"      __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588ac3093d0) at ./nptl/futex-internal.c:57

Thread 21 (Thread 0x7fe674aa66c0 (LWP 14193) "mono:gdrv0"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588ac3093d0) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588ac3093d0, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588ac3093d0, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b558 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5588ac309380, cond=0x5588ac3093a8) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x5588ac3093a8, mutex=0x5588ac309380) at ./nptl/pthread_cond_wait.c:618
#5  0x00007fe6a650c059 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#6  0x00007fe6a64be17b in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#7  0x00007fe6a650bf97 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#8  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#9  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 20 (Thread 0x7fe674ca76c0 (LWP 14192) "mono"):
#0  __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588ab5dc8c0) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588ab5dc8c0, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=<optimized out>, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588ab5dc8c0, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=<optimized out>) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d83c3f in do_futex_wait (sem=sem@entry=0x5588ab5dc8c0, abstime=0x0, clockid=0) at ./nptl/sem_waitcommon.c:111
#4  0x00007fe6c2d83cd0 in __new_sem_wait_slow64 (sem=0x5588ab5dc8c0, abstime=0x0, clockid=0) at ./nptl/sem_waitcommon.c:183
#5  0x00007fe676972a39 in ?? () from /usr/lib/x86_64-linux-gnu/libopenal.so.1
#6  0x00007fe67693712d in ?? () from /usr/lib/x86_64-linux-gnu/libopenal.so.1
#7  0x00007fe676972587 in ?? () from /usr/lib/x86_64-linux-gnu/libopenal.so.1
#8  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#9  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 19 (Thread 0x7fe6756cf6c0 (LWP 14191) "mono"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x7fe64c000f08) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x7fe64c000f08, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x7fe64c000f08, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b558 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5588a9da4d00, cond=0x7fe64c000ee0) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x7fe64c000ee0, mutex=0x5588a9da4d00) at ./nptl/pthread_cond_wait.c:618
#5  0x00007fe676c3ca48 in pa_threaded_mainloop_wait () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
#6  0x00007fe67696be7e in ?? () from /usr/lib/x86_64-linux-gnu/libopenal.so.1
#7  0x00007fe676972587 in ?? () from /usr/lib/x86_64-linux-gnu/libopenal.so.1
#8  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#9  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 18 (Thread 0x7fe67605b6c0 (LWP 14190) "threaded-ml"):
#0  0x00007fe6c2def15f in __GI___poll (fds=0x7fe6680071e0, nfds=2, timeout=1172) at ../sysdeps/unix/sysv/linux/poll.c:29
#1  0x00007fe676c3c2e1 in ?? () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
#2  0x00007fe676c2dfa4 in pa_mainloop_poll () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
#3  0x00007fe676c2e606 in pa_mainloop_iterate () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
#4  0x00007fe676c2e6b0 in pa_mainloop_run () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
#5  0x00007fe676c3c3b9 in ?? () from /usr/lib/x86_64-linux-gnu/libpulse.so.0
#6  0x00007fe67659033f in ?? () from /usr/lib/x86_64-linux-gnu/pulseaudio/libpulsecommon-16.1.so
#7  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#8  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 17 (Thread 0x7fe676c036c0 (LWP 14181) "mono"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x7fe676c02680, op=137, expected=0, futex_word=0x5588a76a2e48) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a76a2e48, expected=expected@entry=0, clockid=clockid@entry=1, abstime=abstime@entry=0x7fe676c02680, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a76a2e48, expected=expected@entry=0, clockid=clockid@entry=1, abstime=abstime@entry=0x7fe676c02680, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b83c in __pthread_cond_wait_common (abstime=0x7fe676c02680, clockid=1, mutex=0x5588a76a2e60, cond=0x5588a76a2e20) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_timedwait64 (cond=0x5588a76a2e20, mutex=0x5588a76a2e60, abstime=0x7fe676c02680) at ./nptl/pthread_cond_wait.c:643
#5  0x00005588a750d98a in ?? ()
#6  0x00005588a7519194 in ?? ()
#7  0x00005588a744f16d in ?? ()
#8  0x00005588a73d2871 in ?? ()
#9  0x00000000408c7d4e in ?? ()
#10 0x0000000000000000 in ?? ()

Thread 16 (Thread 0x7fe69697b6c0 (LWP 14180) "mono"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x7fe69697a700, op=137, expected=0, futex_word=0x5588a76a2e48) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a76a2e48, expected=expected@entry=0, clockid=clockid@entry=1, abstime=abstime@entry=0x7fe69697a700, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a76a2e48, expected=expected@entry=0, clockid=clockid@entry=1, abstime=abstime@entry=0x7fe69697a700, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b83c in __pthread_cond_wait_common (abstime=0x7fe69697a700, clockid=1, mutex=0x5588a76a2e60, cond=0x5588a76a2e20) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_timedwait64 (cond=0x5588a76a2e20, mutex=0x5588a76a2e60, abstime=0x7fe69697a700) at ./nptl/pthread_cond_wait.c:643
#5  0x00005588a750d98a in ?? ()
#6  0x00005588a7519194 in ?? ()
#7  0x00005588a744f16d in ?? ()
#8  0x00005588a73d2871 in ?? ()
#9  0x00000000408c7d4e in ?? ()
#10 0x00007fe6c26fed80 in ?? ()
#11 0x00007fe6c24deea0 in ?? ()
#12 0x00007fe6c26fed00 in ?? ()
#13 0x00007fe6c26fedd0 in ?? ()
#14 0x00007fe6c26fed00 in ?? ()
#15 0x00007fe678003a10 in ?? ()
#16 0x00007fe69697aa60 in ?? ()
#17 0x00007fe69697a880 in ?? ()
#18 0x00007fe600000000 in ?? ()
#19 0x0000000040836be3 in ?? ()
#20 0x00440043002d0044 in ?? ()
#21 0x00440043002d0044 in ?? ()
#22 0x0000000000000014 in ?? ()
#23 0x00007fe6c24ded00 in ?? ()
#24 0x0000000000000000 in ?? ()

Thread 15 (Thread 0x7fe677fff6c0 (LWP 14179) "mono"):
#0  0x00007fe6c2def15f in __GI___poll (fds=0x7fe677ffe688, nfds=1, timeout=-1) at ../sysdeps/unix/sysv/linux/poll.c:29
#1  0x00007fe6c0ba9d12 in ?? () from /usr/lib/x86_64-linux-gnu/libxcb.so.1
#2  0x00007fe6c0bac07a in xcb_wait_for_event () from /usr/lib/x86_64-linux-gnu/libxcb.so.1
#3  0x00007fe6bfb013b8 in _XReadEvents () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#4  0x00007fe6bfae848d in XIfEvent () from /usr/lib/x86_64-linux-gnu/libX11.so.6
#5  0x0000000040a5f6e4 in ?? ()
#6  0x00007fe6c26002a0 in ?? ()
#7  0x00007fe6c2600398 in ?? ()
#8  0x00007fe6c2600220 in ?? ()
#9  0x0000000000000011 in ?? ()
#10 0x00007fe6c2402330 in ?? ()
#11 0x00007fe66c0ae3e0 in ?? ()
#12 0x00007fe677ffea60 in ?? ()
#13 0x00007fe677ffe810 in ?? ()
#14 0x0000000000000000 in ?? ()

Thread 14 (Thread 0x7fe69617a6c0 (LWP 14176) "mono:gdrv0"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588ab286770) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588ab286770, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588ab286770, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b558 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5588ab286720, cond=0x5588ab286748) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x5588ab286748, mutex=0x5588ab286720) at ./nptl/pthread_cond_wait.c:618
#5  0x00007fe6a650c059 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#6  0x00007fe6a64be17b in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#7  0x00007fe6a650bf97 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#8  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#9  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 13 (Thread 0x7fe6951916c0 (LWP 14175) "mono:disk$0"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588ab19d128) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588ab19d128, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588ab19d128, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b558 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5588ab19d0d8, cond=0x5588ab19d100) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x5588ab19d100, mutex=0x5588ab19d0d8) at ./nptl/pthread_cond_wait.c:618
#5  0x00007fe6a650c059 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#6  0x00007fe6a64be17b in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#7  0x00007fe6a650bf97 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#8  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#9  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 12 (Thread 0x7fe6a47fd6c0 (LWP 14168) "Thread Pool Wor"):
#0  __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x7fe6a47fcd10, op=393, expected=0, futex_word=0x5588a7693ec8) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a7693ec8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x7fe6a47fcd10, private=<optimized out>, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a7693ec8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x7fe6a47fcd10, private=<optimized out>) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d83a30 in do_futex_wait (sem=sem@entry=0x5588a7693ec8, abstime=abstime@entry=0x7fe6a47fcd10, clockid=0) at ./nptl/sem_waitcommon.c:111
#4  0x00007fe6c2d83acb in __new_sem_wait_slow64 (sem=0x5588a7693ec8, abstime=0x7fe6a47fcd10, clockid=0) at ./nptl/sem_waitcommon.c:183
#5  0x00005588a74b4623 in ?? ()
#6  0x00005588a744db27 in ?? ()
#7  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#8  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 11 (Thread 0x7fe6a49fe6c0 (LWP 14167) "Thread Pool Wor"):
#0  __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x7fe6a49fdd10, op=393, expected=0, futex_word=0x5588a7693ec8) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a7693ec8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x7fe6a49fdd10, private=<optimized out>, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a7693ec8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x7fe6a49fdd10, private=<optimized out>) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d83a30 in do_futex_wait (sem=sem@entry=0x5588a7693ec8, abstime=abstime@entry=0x7fe6a49fdd10, clockid=0) at ./nptl/sem_waitcommon.c:111
#4  0x00007fe6c2d83acb in __new_sem_wait_slow64 (sem=0x5588a7693ec8, abstime=0x7fe6a49fdd10, clockid=0) at ./nptl/sem_waitcommon.c:183
#5  0x00005588a74b4623 in ?? ()
#6  0x00005588a744db27 in ?? ()
#7  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#8  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 10 (Thread 0x7fe6a4bff6c0 (LWP 14166) "Thread Pool Wor"):
#0  __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x7fe6a4bfed10, op=393, expected=0, futex_word=0x5588a7693ec8) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a7693ec8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x7fe6a4bfed10, private=<optimized out>, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a7693ec8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x7fe6a4bfed10, private=<optimized out>) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d83a30 in do_futex_wait (sem=sem@entry=0x5588a7693ec8, abstime=abstime@entry=0x7fe6a4bfed10, clockid=0) at ./nptl/sem_waitcommon.c:111
#4  0x00007fe6c2d83acb in __new_sem_wait_slow64 (sem=0x5588a7693ec8, abstime=0x7fe6a4bfed10, clockid=0) at ./nptl/sem_waitcommon.c:183
#5  0x00005588a74b4623 in ?? ()
#6  0x00005588a744db27 in ?? ()
#7  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#8  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 9 (Thread 0x7fe6b437e6c0 (LWP 14165) "Thread Pool Wor"):
#0  __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x7fe6b437dd10, op=393, expected=0, futex_word=0x5588a7693ec8) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a7693ec8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x7fe6b437dd10, private=<optimized out>, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a7693ec8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x7fe6b437dd10, private=<optimized out>) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d83a30 in do_futex_wait (sem=sem@entry=0x5588a7693ec8, abstime=abstime@entry=0x7fe6b437dd10, clockid=0) at ./nptl/sem_waitcommon.c:111
#4  0x00007fe6c2d83acb in __new_sem_wait_slow64 (sem=0x5588a7693ec8, abstime=0x7fe6b437dd10, clockid=0) at ./nptl/sem_waitcommon.c:183
#5  0x00005588a74b4623 in ?? ()
#6  0x00005588a744db27 in ?? ()
#7  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#8  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 8 (Thread 0x7fe6b457f6c0 (LWP 14164) "mono"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x7fe6b457ec60, op=137, expected=0, futex_word=0x5588a76a2e48) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a76a2e48, expected=expected@entry=0, clockid=clockid@entry=1, abstime=abstime@entry=0x7fe6b457ec60, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a76a2e48, expected=expected@entry=0, clockid=clockid@entry=1, abstime=abstime@entry=0x7fe6b457ec60, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b83c in __pthread_cond_wait_common (abstime=0x7fe6b457ec60, clockid=1, mutex=0x5588a76a2e60, cond=0x5588a76a2e20) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_timedwait64 (cond=0x5588a76a2e20, mutex=0x5588a76a2e60, abstime=0x7fe6b457ec60) at ./nptl/pthread_cond_wait.c:643
#5  0x00005588a750d98a in ?? ()
#6  0x00005588a7519194 in ?? ()
#7  0x00005588a74b5243 in ?? ()
#8  0x00005588a744db27 in ?? ()
#9  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#10 0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 7 (Thread 0x7fe6b6d7a6c0 (LWP 14163) "mono:gdrv0"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588aa69afa0) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588aa69afa0, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588aa69afa0, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b558 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5588aa69af50, cond=0x5588aa69af78) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x5588aa69af78, mutex=0x5588aa69af50) at ./nptl/pthread_cond_wait.c:618
#5  0x00007fe6a650c059 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#6  0x00007fe6a64be17b in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#7  0x00007fe6a650bf97 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#8  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#9  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 6 (Thread 0x7fe6b63d26c0 (LWP 14162) "mono:disk$0"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588aa58d318) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588aa58d318, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588aa58d318, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b558 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5588aa58d2c8, cond=0x5588aa58d2f0) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x5588aa58d2f0, mutex=0x5588aa58d2c8) at ./nptl/pthread_cond_wait.c:618
#5  0x00007fe6a650c059 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#6  0x00007fe6a64be17b in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#7  0x00007fe6a650bf97 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#8  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#9  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 5 (Thread 0x7fe6b757b6c0 (LWP 14161) "mono:disk$0"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588aa0e7938) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588aa0e7938, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588aa0e7938, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b558 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5588aa0e78e8, cond=0x5588aa0e7910) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x5588aa0e7910, mutex=0x5588aa0e78e8) at ./nptl/pthread_cond_wait.c:618
#5  0x00007fe6a650c059 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#6  0x00007fe6a64be17b in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#7  0x00007fe6a650bf97 in ?? () from /usr/lib/x86_64-linux-gnu/dri/crocus_dri.so
#8  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#9  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 4 (Thread 0x7fe6b7fff6c0 (LWP 14153) "mono"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x7fe6b7ffe690, op=137, expected=0, futex_word=0x5588a76a2e48) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a76a2e48, expected=expected@entry=0, clockid=clockid@entry=1, abstime=abstime@entry=0x7fe6b7ffe690, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a76a2e48, expected=expected@entry=0, clockid=clockid@entry=1, abstime=abstime@entry=0x7fe6b7ffe690, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b83c in __pthread_cond_wait_common (abstime=0x7fe6b7ffe690, clockid=1, mutex=0x5588a76a2e60, cond=0x5588a76a2e20) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_timedwait64 (cond=0x5588a76a2e20, mutex=0x5588a76a2e60, abstime=0x7fe6b7ffe690) at ./nptl/pthread_cond_wait.c:643
#5  0x00005588a750d98a in ?? ()
#6  0x00005588a7519194 in ?? ()
#7  0x00005588a744f16d in ?? ()
#8  0x00005588a73d2871 in ?? ()
#9  0x00000000408c7d4e in ?? ()
#10 0x00007fe6c27aabb8 in ?? ()
#11 0x00007fe6c27aad40 in ?? ()
#12 0x00007fe6c27aab38 in ?? ()
#13 0x00007fe6c27aac08 in ?? ()
#14 0x00007fe6c27aab38 in ?? ()
#15 0x00007fe6b00026a0 in ?? ()
#16 0x00007fe6b7ffea60 in ?? ()
#17 0x00007fe6b7ffe810 in ?? ()
#18 0x00007fe600000000 in ?? ()
#19 0x0000000000000000 in ?? ()

Thread 3 (Thread 0x7fe6bfdff6c0 (LWP 14150) "Finalizer"):
#0  __futex_abstimed_wait_common64 (private=<optimized out>, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588a76935e0) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a76935e0, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=<optimized out>, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a76935e0, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=<optimized out>) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d83c3f in do_futex_wait (sem=sem@entry=0x5588a76935e0, abstime=0x0, clockid=0) at ./nptl/sem_waitcommon.c:111
#4  0x00007fe6c2d83cd0 in __new_sem_wait_slow64 (sem=0x5588a76935e0, abstime=0x0, clockid=0) at ./nptl/sem_waitcommon.c:183
#5  0x00005588a74a4292 in ?? ()
#6  0x00005588a744db27 in ?? ()
#7  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#8  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 2 (Thread 0x7fe6c23ff6c0 (LWP 14149) "SGen worker"):
#0  __futex_abstimed_wait_common64 (private=0, cancel=true, abstime=0x0, op=393, expected=0, futex_word=0x5588a76a27a8) at ./nptl/futex-internal.c:57
#1  __futex_abstimed_wait_common (futex_word=futex_word@entry=0x5588a76a27a8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0, cancel=cancel@entry=true) at ./nptl/futex-internal.c:87
#2  0x00007fe6c2d78efb in __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x5588a76a27a8, expected=expected@entry=0, clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=0) at ./nptl/futex-internal.c:139
#3  0x00007fe6c2d7b558 in __pthread_cond_wait_common (abstime=0x0, clockid=0, mutex=0x5588a76a27c0, cond=0x5588a76a2780) at ./nptl/pthread_cond_wait.c:503
#4  ___pthread_cond_wait (cond=0x5588a76a2780, mutex=0x5588a76a27c0) at ./nptl/pthread_cond_wait.c:618
#5  0x00005588a74ffa09 in ?? ()
#6  0x00007fe6c2d7c134 in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:442
#7  0x00007fe6c2dfc7dc in clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:81

Thread 1 (Thread 0x7fe6c2cf1bc0 (LWP 14148) "mono"):
#0  0x00007fe6c2dc6b57 in __GI___wait4 (pid=14209, stat_loc=0x7fff0b637624, options=0, usage=0x0) at ../sysdeps/unix/sysv/linux/wait4.c:30
#1  0x00005588a72a3394 in ?? ()
#2  0x00005588a72a33dc in ?? ()
#3  0x00005588a725201c in ?? ()
#4  0x00005588a729cac1 in ?? ()
#5  0x00007fe6c2d9667a in __memset_sse2_unaligned_erms () at ../sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S:335
#6  0x00007fe6c24c9d70 in ?? ()
#7  0x21b812527e3ef800 in ?? ()
#8  0x00005588a96aa560 in ?? ()
#9  0x00005588a7218719 in ?? ()
#10 0x00000000000ab408 in ?? ()
#11 0x00007fe6b7cb9090 in ?? ()
#12 0x00005588ac25fca8 in ?? ()
#13 0x00007fff0b638398 in ?? ()
#14 0x000000000003c8de in ?? ()
#15 0x0000000000000000 in ?? ()
[Inferior 1 (process 14148) detached]
Aborted

Host env.

Background

The crash_gambatte.lua script is simplified from one I am working on for a TAS. The purpose of the earliest_effective_frame function is to find the earliest frame where doing some action (e.g. pressing a button) causes some property to become true in the near future. In the simplified version here, the action is a no-op, and the property is just checking that the "Nintendo" boot animation finishes within the next 8 frames. An example of a more practical application (which also causes a crash, but depends on specific ROM addresses) would be finding the earliest frame you can press the Start button at the title screen to get to the main menu:

console.log("main coroutine start")

run_until_exec(500, TITLE_SCREEN_ADDR)
console.log("title screen")

earliest_effective_frame(
	function () joypad.set({Start = true}) end,
	function () return run_until_exec(32, MAIN_MENU_ADDR) end
)
console.log("main menu")

If you remove the final memorysavestate.loadcorestate in earliest_effective_frame (i.e., have the function return with the state at which test() became true, rather than rewinding to just after action() happened), then the crash doesn't occur.

@CasualPokePlayer
Copy link
Member

CasualPokePlayer commented Mar 11, 2024

This isn't something Linux specific here (I can repro the crash on Windows, although it just crashes in managed code rather). The issue is you end up using savestate APIs in a memory callback. This is not allowed, it will crash various cores (if some don't, that's rather by happenstance and is not something to be relied on), as you are in the middle of the core's emulation loop, which is not expecting savestates to be used, and if any fix is done it would be to just prohibit savestate API usage (i.e. throw some exception so the lua script dies) while in a memory callback.

@SandTAS
Copy link

SandTAS commented Mar 11, 2024

The issue is you end up using savestate APIs in a memory callback. This is not allowed, it will crash various cores (if some don't, that's rather by happenstance and is not something to be relied on), as you are in the middle of the core's emulation loop, which is not expecting savestates to be used

@CasualPokePlayer, thanks for the information. I see now. Is there a list of which callbacks are safe with respect to making savestates? I suppose it's fine to call memorysavestate.savecorestate() immediately after calling emu.frameadvance(), for example. event.onframestart and event.onframeend callbacks as well? If those are safe, what I can do in my script is, after halting the emulator with a event.on_bus_exec or event.on_bus_write callback, always "round up" the execution state to the next frame boundary before making a savestate.

if any fix is done it would be to just prohibit savestate API usage (i.e. throw some exception so the lua script dies) while in a memory callback.

If possible, I would suggest making the prohibition on savestates a function of the emulator state, not the Lua call stack. In the script I posted in #1430 (comment), the memorysavestate.savecorestate() call doesn't happen "in" the memory callback: the memory callback restores a different coroutine, which is what actually makes the savestate. Similarly, there could be two scripts running at the same time, one periodically making savestates, and one occasionally pausing the emulator in a state where making a savestate won't work; the first script won't have anything in its call stack saying its in a memory callback.

Changing memorysavestate.savecorestate to optionally return an error or throw an exception would be fine with me; but now that I know the problem I can just try to confine myself to safe usages.

@CasualPokePlayer
Copy link
Member

CasualPokePlayer commented Mar 11, 2024

The emulator should not be in charge at all in ensuring Lua users are not using savestates within memory callbacks, if just due to that meaning 10000 copy paste checks in places where the Lua script manager could be doing it.

memorysavestate.savecorestate() call doesn't happen "in" the memory callback: the memory callback restores a different coroutine, which is what actually makes the savestate.

This doesn't matter, the memory callback has not returned (and thus the emulator's FrameAdvance() call has not returned). Until that memory callback returns, and then eventually the FrameAdvance() call returns, will it be safe for a savestate to be made/loaded.

Is there a list of which callbacks are safe with respect to making savestates?

Most callbacks are safe, the only ones that aren't are memory callbacks (on_bus_* and the deprecated variants) and input callbacks (oninputpoll), as they occur midway in the emulator FrameAdvance() call.

@CasualPokePlayer
Copy link
Member

5bf9d38 should fix this.

@SandTAS
Copy link

SandTAS commented Mar 11, 2024

memorysavestate.savecorestate() call doesn't happen "in" the memory callback: the memory callback restores a different coroutine, which is what actually makes the savestate.

This doesn't matter, the memory callback has not returned (and thus the emulator's FrameAdvance() call has not returned). Until that memory callback returns, and then eventually the FrameAdvance() call returns, will it be safe for a savestate to be made/loaded.

I think what I proposed was basically right, though perhaps not for the reason I thought. It's not so much in what coroutine the savestate operations happen, but as you say, whether the memory callback has returned. The workaround I suggested, "rounding up" to the next frame boundary, has the side effect of letting the memory callback return.

Here's an example. Now that I understand the problem better, here's a much more minimal demonstration of a crash from improperly loading a savestate inside an on_bus_exec callback:

-- log to a file to make messages visible after the emulator crashes
assert(io.output(assert(io.open("log.txt", "w"))))
function log(s)
	console.log(s)
	assert(io.write(s .. "\n"))
	assert(io.flush())
end

local savestate_id = memorysavestate.savecorestate()

coroutine.resume(coroutine.create(function ()
	log("begin main coroutine")
	local event_id
	event_id = event.on_bus_exec(function ()
		assert(event.unregisterbyid(event_id))
		log(string.format("enter on_bus_exec callback  cycles %d", emu.totalexecutedcycles()))

		log(string.format("              loadcorestate cycles %d (in on_bus_exec callback)", emu.totalexecutedcycles()))
		memorysavestate.loadcorestate(savestate_id) -- crashes
		memorysavestate.removestate(savestate_id)

		log(string.format(" exit on_bus_exec callback  cycles %d", emu.totalexecutedcycles()))
	end, 0x00fe)
	log("  end main coroutine")
end))

The output of the above script (which crashes the Gambatte core) is:

begin main coroutine
  end main coroutine
enter on_bus_exec callback  cycles 11720156
              loadcorestate cycles 11720156 (in on_bus_exec callback)
 exit on_bus_exec callback  cycles 11720156

Here's a modified version that "rounds up" by waiting for an onframestart callback after the on_bus_exec callback fires. This one does not crash the emulator and works as expected.

coroutine.resume(coroutine.create(function ()
	log("begin main coroutine")
	local co = coroutine.running()

	local event_id
	event_id = event.on_bus_exec(function ()
		assert(event.unregisterbyid(event_id))
		log(string.format("enter on_bus_exec  callback cycles %d", emu.totalexecutedcycles()))
		coroutine.resume(co)
		log(string.format(" exit on_bus_exec  callback cycles %d", emu.totalexecutedcycles()))
	end, 0x00fe)
	coroutine.yield() -- wait for on_bus_exec callback to yield back to us

	-- now run the emulator up to a frame boundary, in order to make it safe to run loadcorestate
	local event_id
	event_id = event.onframestart(function ()
		assert(event.unregisterbyid(event_id))
		log(string.format("enter onframestart callback cycles %d", emu.totalexecutedcycles()))
		coroutine.resume(co)
		log(string.format(" exit onframestart callback cycles %d", emu.totalexecutedcycles()))
	end)
	coroutine.yield() -- wait for onframestart callback to yield back to us

	log(string.format("              loadcorestate cycles %d (in main coroutine)", emu.totalexecutedcycles()))
	memorysavestate.loadcorestate(savestate_id)
	memorysavestate.removestate(savestate_id)
	log("  end main coroutine")
end))

The output of the modified script shows that the on_bus_exec callback returns before loadcorestate runs. An onframestart callback is still pending at the time that loadcorestate runs, but that should be fine. (The cycle count has gone backward when the onframestate callback returns, but in practice you wouldn't need to inspect that.)

begin main coroutine
enter on_bus_exec  callback cycles 11720156
 exit on_bus_exec  callback cycles 11720156
enter onframestart callback cycles 11753028
              loadcorestate cycles 11753028 (in main coroutine)
  end main coroutine
 exit onframestart callback cycles 11720156

I'm using coroutines because I'd like to be able to write the program in a blocking async style rather than a callback-oriented style. But the modified version can also be expressed in a callback style:

local memory_event_id
memory_event_id = event.on_bus_exec(function ()
	assert(event.unregisterbyid(memory_event_id))
	log(string.format("enter on_bus_exec  callback cycles %d", emu.totalexecutedcycles()))
	local frame_event_id
	frame_event_id = event.onframestart(function ()
		assert(event.unregisterbyid(frame_event_id))
		log(string.format("enter onframestart callback cycles %d", emu.totalexecutedcycles()))
		log(string.format("              loadcorestate cycles %d (in onframestart callback)", emu.totalexecutedcycles()))
		memorysavestate.loadcorestate(savestate_id)
		memorysavestate.removestate(savestate_id)
		log(string.format(" exit onframestart callback cycles %d", emu.totalexecutedcycles()))
	end)
	log(string.format(" exit on_bus_exec  callback cycles %d", emu.totalexecutedcycles()))
end, 0x00fe)

The output of the program in the callback style is:

enter on_bus_exec  callback cycles 11720156
 exit on_bus_exec  callback cycles 11720156
enter onframestart callback cycles 11753028
              loadcorestate cycles 11753028 (in onframestart callback)
 exit onframestart callback cycles 11720156

By my reading of 5bf9d38, it won't interfere with either of the two revised programs.

@bugQ

This comment was marked as resolved.

@YoshiRulz
Copy link
Member Author

YoshiRulz commented Mar 15, 2024

"open file" dialogs sometimes result in empty black windows, which then become "infectious" and result in even the main window only showing black, which persists until user logout / compositor shutdown

I've never seen this. What DE do you use?

in a flake [...] default.nix fails to evaluate

As you probably guessed, I still avoid Flakes, so this one is new to me too. And I have no idea what the cause could be; my understanding was that Flake evaluation is pure-by-default, and nix-build --pure -A emuhawk-2_6 works fine. Does it also disable IFD (import (fetchTarball ...))? Can you work-around the failure by using lib.filterAttrs?

default.nix also fails to build whenever Dist/deps.nix is out of sync [...] maybe it's worth finding a way to keep those deps always synced instead of relying on a second manual build step ? if it is not possible with pure nix, maybe with some Github CI magic ?

Contributions welcome! What we have currently is a ~monthly CI job which runs nix-build -A emuhawk, but I don't believe it triggers the failed job email alert because it's set as may-fail. (Future Yoshi says: it does email me. I will now regen the lockfile.)
edit: Also, you could always do:

let
	bizhawkAttrs = import ./. { hawkSourceInfoDevBuild = {
		# ...
	}; };
	patchList = [
		# e.g.
		{ rev = "5cb80569d97436c2e838732ead63c8251dcd8a91"; hash = "sha256-NdJ8Fw7YcrPlkjTzsHm8DbCQPixPmDXTdLNiZp6nggs="; }
	];
	bizhawkAssemblies = bizhawkAttrs.bizhawkAssemblies.overrideAttrs (oldAttrs: {
		patches = (oldAttrs.patches or []) ++ (builtins.map
			({ hash, rev }: fetchpatch { inherit hash; url = "https://github.com/TASEmulators/BizHawk/commit/${rev}.patch"; })
			patchList);
	});
in bizhawkAttrs.buildEmuHawkInstallableFor { inherit bizhawkAssemblies; }

@bugQ

This comment was marked as resolved.

@YoshiRulz

This comment was marked as resolved.

@bugQ

This comment was marked as resolved.

@YoshiRulz

This comment was marked as resolved.

@CasualPokePlayer
Copy link
Member

CasualPokePlayer commented Apr 13, 2024

[wrt blip_buf] Sappharad has previously attempted moving it to managed C#

Note I have done so too for another project. Note Vector512 usage is .NET 8 (and the other Vector*s in System.Runtime.Intrinsics are .NET Core/.NET only). The older non-Vector impl could be used (although this will just be somewhat slower as the JIT doesn't really understand it can vectorize this without Vector* giving it that hint).

@YoshiRulz
Copy link
Member Author

Is the C implementation SIMD?

I'm not sure if it's possible, but I was interested in writing a polyfill for Vector* for Vortice, so this would be a good excuse to work on that.

@CasualPokePlayer
Copy link
Member

CasualPokePlayer commented Apr 13, 2024

C implementation gets optimized with SIMD the best the compiler can (it's really more that a C compiler is smart and can recognize SIMD'able code, while the JIT is not that smart and needs hints with Vector*, not really something you can actually polyfill anyways other than even if you do you don't get SIMD benefits if it's not the runtime's actual Vector* impl).

On that note, System.Numerics's Vector*s are largely available in .NET Framework, except Vector<T> (what'd actually be useful in blip's case, granted not by much due to varying size)

@severinkaderli
Copy link

Summary

The Ares64 core doesn't seem the flush the SaveRAM file immediately, only when closing the ROM. I was playing Ocarina of Time in an Archipelago Randomizer and I got a crash. I saved multiple times during gameplay but after restarting the emulator my progress was lost.

I then tested saving the game to see if the SaveRAM file would get written. It only gets written, when you close the ROM and not immediately after saving. This also happens in vanilla Ocarina of Time.

Repro

  1. Play Ocarina of Time
  2. Save the game
  3. Notice the SaveRAM file doesn't get created
  4. Close the ROM
  5. SaveRAM file gets written

Host env.

  • BizHawk 2.9.1; Arch Linux; Kernel 6.8.8-arch1-1

@CasualPokePlayer
Copy link
Member

CasualPokePlayer commented May 2, 2024

That is expected behavior across all the cores, not just Ares64. There is an AutoSaveRAM option in Config -> Customize -> Advanced available for avoiding issue with this behavior.

(There's probably some issue that explains this in length, but the tl;dr is it's really hard to define when the "game is saving," it is something that can only be heuristically determined since the emulator has no understanding of a game's intent of doing things, and for many systems this is just impossible to determine due to "save memory" possibly being used as "extra ram" and not for save data)

@YoshiRulz
Copy link
Member Author

YoshiRulz commented May 3, 2024

That is the received wisdom, though now you mention it I do wonder how bad the disk writes could possibly be if it was flushed every frame (the worst case of an unindicative dirty bit).

@zeromus
Copy link
Contributor

zeromus commented May 3, 2024

The problem is that SSD will get clogged with that much traffic and create random hiccups. It's also abusive. Do the math on the GB/hr it can easily turn into.

@YoshiRulz
Copy link
Member Author

Sure: For a NES game with 64 KiB SaveRAM, it's ~4 MiB/s, or ~14 GiB/hr. For a DS game with 256 KiB SaveRAM, it will obviously be 4x that. I looked up a benchmark for my $40 SSD (CBB running one) and it gets ~300 MiB/s for random writes. I think it's worth experimenting with at least.

@CasualPokePlayer
Copy link
Member

CasualPokePlayer commented May 3, 2024

Most cores don't bother to implement the SaveRAM dirty flag in the first place, just always returning true if SaveRAM exists.

If we want to do anything it should just be enabling AutoSaveRAM by default. And if you want to avoid unneeded writes, you're better off just comparing the returned SaveRAM against the previously returned SaveRAM instead of relying on the core to figure out if SaveRAM is dirty or not.

@zeromus
Copy link
Contributor

zeromus commented May 3, 2024

Bursts of random writes are not the same as a continuous never-ending spew of random writes. Random or not, recording an avi while playing should be a good approximation of what it will be like to continuously spew save data. Regardless, continually writing that much data without a user intentionally enabling it is a defect. Prepare for it to be reported as a bug.

@bugQ

This comment was marked as resolved.

@MJnHerAbsolution

This comment was marked as resolved.

@CasualPokePlayer

This comment was marked as resolved.

@MJnHerAbsolution

This comment was marked as resolved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
App: EmuHawk Relating to EmuHawk frontend Meta Relating to code organisation or to things that aren't code re: Multiplatform Relating to the Linux and macOS ports (Mono Framework, and eventually .NET Core)
Projects
None yet
Development

No branches or pull requests